Based on Redis 7.0.11.

Redis 对外支持的数据类型(String、List、Hash、Set、ZSet)并不是直接使用其定义的数据结构,而是基于另外的一套对象系统。对象系统除了可以根据不同场景选择不同底层数据结构外,还实现了基于引用计数的对象共享垃圾回收以及缓存淘汰机制。

Redis Object 定义

1
2
3
4
5
6
7
8
9
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
} robj;
  • type:记录对象类型
    类型取值
    OBJ_STRING0
    OBJ_LIST1
    OBJ_SET2
    OBJ_ZSET3
    OBJ_HASH4
  • encoding:记录对象的编码及底层实现
    编码取值对应数据结构
    OBJ_ENCODING_RAW0SDS
    OBJ_ENCODING_INT1long
    OBJ_ENCODING_HT2字典
    OBJ_ENCODING_INTSET6整数集合
    OBJ_ENCODING_SKIPLIST7跳表和字典
    OBJ_ENCODING_EMBSTR8embedded 编码的 SDS
    OBJ_ENCODING_QUICKLIST9
    OBJ_ENCODING_STREAM10
    OBJ_ENCODING_LISTPACK11
  • lru:缓存淘汰策略相关
  • refcount:引用计数
  • ptr:底层数据指针

该结构采用了 Bit Field 来降低内存的占用。Redis 会根据实际情况(数据类型,数据大小)选择相对合适的 encoding 来提高性能与效率。

typeencoding对象
OBJ_STRINGOBJ_ENCODING_RAWptr 指向 SDS
OBJ_STRINGOBJ_ENCODING_INTptr 值就是整数值,而非地址
OBJ_STRINGOBJ_ENCODING_EMBSTR字符串较短时,一次分配一块内存连续存放 redisObjectsdshdr 对象
OBJ_LISTOBJ_ENCODING_QUICKLISTptr 指向 quicklist
OBJ_SETOBJ_ENCODING_HTptr 指向 dict,只使用 key,值设为 NULL
OBJ_SETOBJ_ENCODING_INTSETptr 指向 intset,所有元素都是整数,且数量不超过 512
OBJ_ZSETOBJ_ENCODING_LISTPACKptr 指向 listpack,元素数量 < server.zset_max_listpack_entries 且元素大小 < server.zset_max_listpack_value
OBJ_ZSETOBJ_ENCODING_SKIPLISTptr 指向 zset{dict, skiplist},
OBJ_HASHOBJ_ENCODING_LISTPACKptr 指向 listpack,元素数量 < server.zset_max_listpack_entries 且元素大小 < server.zset_max_listpack_value。暂时不支持 HT 转成 LISTPACK
OBJ_HASHOBJ_ENCODING_HTptr 指向 dict

对象引用计数

Redis 通过追踪 redisObject#refcount,在适当的时候自动释放 refcount == 0 的对象。

引用计数除了用作垃圾回收外,还可用作对象共享。不过对象共享需要查找到一个具有相同值的对象,O(N2) 复杂度,CPU 开销大。

Key takeaways

server.h/redisObject

t_string.h

t_list.h

t_hash.h

t_set.h

t_zset.h

《Redis 设计与实现》