Redis 支持的五大基本数据类型:String,Hash,List,Set,Zset
本文以 Redis 6.2 版本为例
通用结构
Redis 中的每个键值对的键和值都是一个对象,是以 Object 的形式进行存储的
typedef struct redisObject {
unsigned [type] 4; //type:基本的数据结构,例如:String等
unsigned [encoding] 4; //encoding:编码,底层具体实现方式
unsigned [lru] REDIS_LRU_BITS; //lru:记录了对象最后一次被命令程序访问的时间
int refcount; //对象引用计数,用于GC
void *ptr; //指向实际值(底层具体实现)的指针
} robj;
type 对应的是 String,Hash,List,Set,Zset
encoding 对应的是 int,raw,ziplist,LinkedList,intset 等等
String
底层实现
String 字符串的编码有三种:int,raw,embstr,具体实现主要是 int 和 SDS
- 如果保存的是整数值,并且这个整数值可以用 long 类型来表示,那么就将这个整数值存放在字符串结构的 ptr 属性里,将 ptr 的类型从 void 转换成 long,并且将编码设置为 int
- 如果保存的是字符串值(以下两种情况采用的底层数据结构都为 SDS)
- 字符串的长度
>
44 字节,那么就用SDS(Simple Dynamic String)
来存放该字符串,编码设为 raw - 字符串的长度
<=
44 字节,将编码设置为 embstr,使用 embstr 编码的方式来存储
- 字符串的长度
在 Redis 3.2 之前,对于字符串采用的编码的分界值是 39 字节,而非 44 字节,为什么发生了变化呢
从 Redis 2.4 起,开始使用 jemalloc 内存分配器来进行内存分配,jemalloc 进行内存分配时会分配 8、16、32、64 字节的内存块
embstr 编码会一次性分配一块连续的内存区域给字符串,来保存 RedisObject 和 sdshdr,如下:
由于 RedisObject 占 16 个字节,free 和 len 各占 4 字节,最后的'\0'
占 1 个字节,如果 buf 数组占 39 个字节,那么加起来刚好 16 + 4 + 4 + 39 + 1 = 64 个字节
后来变成 44 字节是因为 在 Redis 3.2 之后,Redis 进行了优化,采用 5 种类型的 sdshdr 来节省内存,对于存储短字符串的 embstr,自然采用的是 sdshdr8,sdshdr8 的 len、alloc、flags 各占 1 个字节,如果 buf 数组占 44 个字节,那么 16 + 1 + 1 + 1 + 44 + 1 = 64 个字节
补充:embstr 由于是一次性分配一块连续的内存区域,所以当字符串变长时,需要重新进行分配,所以 embstr 编码的字符串实际上是只读的。在进行字符串拼接等操作时,会先将字符串的编码从 embstr 变成 raw,在执行修改命令
常用命令
应用场景
Hash
底层实现
Hash 的编码有两种:ziplist
、hashtable
,具体实现是压缩列表和哈希表dictht
ziplist
编码 —> 压缩列表hashtable
编码 —> 哈希表dictht
底层结构采用压缩列表ziplist
或者哈希表来实现
- 如果列表的字符串个数 < 512(默认值,可通过设置
list-max-ziplist-entries
来修改),并且每个字符串的长度 < 64 字节(默认值,可通过设置list-max-ziplist-value
来修改),那么底层就采用压缩列表ziplist
来实现 -
常用命令
应用场景
List
List 是简单的字符串列表,根据插入顺序进行排序,可以从头部或者尾部插入
底层实现
**Redis 3.2 之前**
:采用双向链表linkedlist
或者压缩列表ziplist
来实现- 如果列表的字符串个数 < 512(默认值,可通过设置
list-max-ziplist-entries
来修改),并且每个字符串的长度 < 64 字节(默认值,可通过设置list-max-ziplist-value
来修改),那么底层就采用压缩列表ziplist
来实现 - 否则底层就采用双向链表
linkedlist
来实现
- 如果列表的字符串个数 < 512(默认值,可通过设置
**Redis 3.2 及之后**
:采用快速列表quicklist
来实现常用命令
应用场景
Set
底层实现
常用命令
应用场景
Zset
底层实现
常用命令
应用场景
参考资料
- 《Redis 设计与实现》
- rollingRobin:https://www.cnblogs.com/rollingRobin/p/16002143.html