源码分析
基于 redis-6.2.4 源码,src/server.sh
Redis 主要包括 string\list\set\zet\hash 五种基本数据类型,这几种基本数据类型底层由不同的 object encoding 实现,包括 raw、int、hashtable、zipmap、linkedlist、intset、skiplist、embstr、quicklist 等。
/* The actual Redis Object */
#define OBJ_STRING 0
#define OBJ_LIST 1
#define OBJ_SET 2
#define OBJ_ZSET 3
#define OBJ_HASH 4
/* Objects encoding. Some kind of objects like Strings and Hashes can be
* internally represented in multiple ways. The 'encoding' field of the object
* is set to one of this fields for this object. */
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
#define LRU_BITS 24
#define LRU_CLOCK_MAX ((1<<LRU_BITS)-1) /* Max value of obj->lru */
#define LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */
#define OBJ_SHARED_REFCOUNT INT_MAX /* Global object never destroyed. */
#define OBJ_STATIC_REFCOUNT (INT_MAX-1) /* Object allocated in the stack. */
#define OBJ_FIRST_SPECIAL_REFCOUNT OBJ_STATIC_REFCOUNT
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* 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;
复制代码
如下为 redis 的基本数据类型及 object encoding 的对应关系:
数据结构
string
底层编码
OBJ_ENCODING_INT:如果一个字符串对象保存的是整数值,并且这个整数值可以用long
类型来表示
OBJ_ENCODING_RAW:如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于 32 字节
OBJ_ENCODING_EMBSTR:如果字符串对象保存的是一个字符串值,并且这个字符申值的长度小于等于 32 字节
应用场景
缓存热点数据
计数器、限速器、自增 ID
session 共享
二进制数据的存储:图片、文件等
hash
底层编码
满足如下两个条件使用 OBJ_ENCODING_ZIPLIST,否则使用 OBJ_ENCODING_HT。
字典中保存的键和值的大小都要小于 64 字节
字典中键值对的个数要小于 512 个
应用场景
购物车
计数器
对象缓存
list
底层编码
3.2 以前,满足如下两个条件使用 OBJ_ENCODING_ZIPLIST,否则使用 OBJ_ENCODING_LINKEDLIST。
3.2 以后使用 quicklist 取代了 ziplist 和 linkedlist,quicklist 是 ziplist 和 linkedlist 的结合体。附 quicklist.h 部分源码如下:
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz; /* ziplist size in bytes */
unsigned int count : 16; /* count of items in ziplist */
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
unsigned int recompress : 1; /* was this node previous compressed? */
unsigned int attempted_compress : 1; /* node can't compress; too small */
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
复制代码
应用场景
栈:lpush+lpop
队列:lpush+rpop
阻塞队列:lpush+brpop
set
底层编码
满足如下两个条件,使用 OBJ_ENCODING_INTSET 实现,否则 OBJ_ENCODING_HT。
集合中的元素都是整数
集合中的元素个数小于 set-maxintset-entries(默认 512 个)
应用场景
标签
社交场景,共同关注、共同好友等
zset
底层编码
满足如下两个条件使用 OBJ_ENCODING_ZIPLIST,否则使用 OBJ_ENCODING_SKIPLIST。
集合中保存的元素个数要小于 128 个
集合中保存的所有元素成员的长度都必须小于 64 字节
应用场景
排行榜
销量 topN
评论