redis之数据结构
2021/5/19 2:25:21
本文主要是介绍redis之数据结构,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
redis数据结构:
string
String通过 int、SDS(simple dynamic string)作为结构存储,int用来存放整型数据,sds存放字节/字符串和浮点型数据。
typedef char *sds;
sdshdr有五种类型,所以至少需要3位来表示
000:sdshdr5 001:sdshdr8 010:sdshdr16 011:sdshdr32 100:sdshdr64
struct __attribute__ ((__packed__)) sdshdr8 { //8表示字符串最大长度是2^8-1 (长度为255) uint8_t len;//表示当前sds的长度(单位是字节) uint8_t alloc;//表示已为sds分配的内存大小(单 位是字节) unsigned char flags;//用一个字节表示当前sdshdr的类型,001表示他的类型 char buf[];//sds实际存放的位置 }
char buf[]的存储方式是什么样的,首先它是一个二进制,再加上是在内存的一个连续空间,所以中间需要使用标识符来表示结束
List类型
redis3.2之前,List类型的value对象内部以linkedlist或者ziplist来实现, 当list的元素个数和单个元素的长度比较小 的时候,
Redis会采用ziplist(压缩列表)来实现来减少内存占用。否则就会采用linkedlist(双向链表)结构
redis3.2之后,采用的一种叫quicklist的数据结构来存储list,列表的底层都由linkedlist+ziplis实现
结构如图:
typedef struct quicklist { //指向头部(最左边)quicklist节点的指针 quicklistNode *head; //指向尾部(最右边)quicklist节点的指针 quicklistNode *tail; //ziplist中的entry节点计数器 unsigned long count; //quicklist的quicklistNode节点计数器 unsigned int len; //保存ziplist的大小,配置文件设定,占16bits int fill : 16; //保存压缩程度值,配置文件设定,占16bits,0表示不压缩 unsigned int compress : 16; }
压缩的list数据结构:ziplist
typedef struct quicklistLZF { //表示被LZF算法压缩后的ziplist的大小 unsigned int sz; //保存压缩后的ziplist的数组,柔性数组 char compressed[]; }
hash类型
map提供两种结构来存储,一种是hashtable、另一种是前面讲的ziplist,数据量小的时候用ziplist
什么时候使用ziplist:
- hash对象保存的键和值字符串长度都小于64字节
- hash对象保存的键值对数量小于512
在redis中,哈希表分为三层,分别是,源码地址【dict.h】
dictEntry:也就是map中的一个元素,也可以说的基本单位
管理一个key-value,同时保留同一个桶中相邻元素的指针,用来维护哈希桶的内部链;
typedef struct dictEntry { void *key; union { //因为value有多种类型,所以value用了union来存储 void *val; uint64_t u64; int64_t s64; double d; } v; struct dictEntry *next;//下一个节点的地址,用来处理碰撞,所有分配到同一索引的元素通过next指针 链接起来形成链表key和v都可以保存多种类型的数据 }
dictht:dictht表示的,这个每个元素所属的下标
实现一个hash表会使用一个buckets存放dictEntry的地址,一般情况下通过hash(key)%len得到的值就是buckets的 索引,这个值决定了我们要将此dictEntry节点放入buckets的哪个索引里,这个buckets实际上就是我们说的hash 表。dict.h的dictht结构中table存放的就是buckets的地址
typedef struct dictht { dictEntry **table;//buckets的地址 unsigned long size;//buckets的大小,总保持为 2^n unsigned long sizemask;//掩码,用来计算hash值对应的buckets索引 unsigned long used;//当前dictht有多少个dictEntry节点 } dictht;
比如我们要讲一个数据存储到hash表中,那么会先通过murmur计算key对应的hashcode,然后根据hashcode取 模得到bucket的位置,再插入到链表中
dict:在扩容的时候会用到
dictht:实际上就是hash表的核心,但是只有一个dictht还不够,比如rehash、遍历hash等操作,所以redis定义了 一个叫dict的结构以支持字典的各种操作,当dictht需要扩容/缩容时,用来管理dictht的迁移,以下是它的数据结 构,源码在
typedef struct dict { dictType *type;//dictType里存放的是一堆工具函数的函数指针, void *privdata;//保存type中的某些函数需要作为参数的数据 dictht ht[2];//两个dictht,ht[0]平时用,ht[1] rehash时用 long rehashidx; //当前rehash到buckets的哪个索引,-1时表示非rehash状态 int iterators; //安全迭代器的计数。 } dict;
set类型
Set在的底层数据结构以intset或者hashtable来存储。
当set中只包含整数型的元素时,采用intset来存储,
否则,采用hashtable存储
zset类型
zset类型的数据结构就比较复杂一点,内部是以ziplist或者skiplist+hashtable来实现,
这里面最核心的一个结构就 是skiplist,也就是跳跃表
这篇关于redis之数据结构的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-18Redis安装入门:新手必读指南
- 2024-11-08阿里云Redis项目实战入门教程
- 2024-11-08阿里云Redis资料:新手入门与初级使用指南
- 2024-11-08阿里云Redis教程:新手入门及实用指南
- 2024-11-07阿里云Redis学习入门:新手必读指南
- 2024-11-07阿里云Redis学习入门:从零开始的操作指南
- 2024-11-07阿里云Redis学习:初学者指南
- 2024-11-06阿里云Redis入门教程:轻松搭建与使用指南
- 2024-11-02Redis项目实战:新手入门教程
- 2024-10-22Redis入门教程:轻松掌握数据存储与操作