Redis中的对象类型与底层编码

Redis 使用对象来表示数据库中的键和值, 每次当我们在 Redis 的数据库中新创建一个键值对时, 我们至少会创建两个对象, 一个对象用作键值对的键(键对象), 另一个对象用作键值对的值(值对象)。

举个例子, 以下 SET 命令在数据库中创建了一个新的键值对, 其中键值对的键是一个包含了字符串值 "msg" 的对象, 而键值对的值则是一个包含了字符串值 "hello world" 的对象:

redis> SET msg "hello world"

Redis 中的每个对象都由一个 redisObject 结构表示, 该结构中和保存数据有关的三个属性分别是 type 属性、 encoding 属性和 ptr 属性:

typedef struct redisObject {
 unsigned type:4; //类型
 unsigned encoding:4; //编码
 unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
 int refcount; //引用计数
 void *ptr; //指向底层实现数据结构的指针
} robj;
  • type: 对象的数据类型。占4个bit。可能的取值有5种:OBJ_STRING, OBJ_LIST, OBJ_SET, OBJ_ZSET, OBJ_HASH,分别对应Redis对外暴露的5种数据结构。
  • encoding: 对象的内部表示方式(也可以称为编码)。占4个bit。可能的取值有10种,即前面代码中的10个OBJ_ENCODING_XXX常量。
  • lru: 做LRU替换算法用,占24个bit。这个不是我们这里讨论的重点,暂时忽略。
  • refcount: 引用计数。它允许robj对象在某些情况下被共享。
  • ptr: 数据指针。指向真正的数据。比如,一个代表string的robj,它的ptr可能指向一个sds结构;一个代表list的robj,它的ptr可能指向一个quicklist。
使用redisObject的优点:
1) 为多种数据类型提供一种统一的表示方式。
2) 允许同一类型的数据采用不同的内部表示,从而在某些情况下尽量节省内存。
3) 支持对象共享和引用计数。当对象被共享的时候,只占用一份内存拷贝,进一步节省内存。

这里特别需要仔细察看的是encoding字段。对于同一个type,还可能对应不同的encoding,这说明同样的一个数据类型,可能存在不同的内部表示方式。而不同的内部表示,在内存占用和查找性能上会有所不同,下文将给出对应关系。

  • 对象的 type 属性记录了对象的类型
/* Object types */
#define OBJ_STRING 0  // 字符串对象  Type “string”
#define OBJ_LIST 1    // 列表对象    Type "list"
#define OBJ_SET 2     // 集合对象    Type "set"
#define OBJ_ZSET 3    // 有序集合对象 Type "zset"
#define OBJ_HASH 4    // 哈希对象    Type "hash"

对于 Redis 数据库保存的键值对来说, 键总是一个字符串对象, 而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种, 因此:

  • 当我们称呼一个数据库键为“字符串键”时, 我们指的是“这个数据库键所对应的值为字符串对象”;
  • 当我们称呼一个键为“列表键”时, 我们指的是“这个数据库键所对应的值为列表对象”,

诸如此类。

  • 对象的 Encoding 属性记录了对象的编码,它决定对象的 ptr 指针指向对象的底层实现数据结构
// string采用原生的表示方式,即用sds来表示
#define OBJ_ENCODING_RAW 0 /* Raw representation */

// string采用数字的表示方式,实际上是一个long型
#define OBJ_ENCODING_INT 1 /* Encoded as integer */

// hash采用一个dict来表示
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */

// 是个旧的表示方式,已不再用。在小于Redis 2.6的版本中才有
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */

//双端链表
#define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */

//压缩列表
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */

//整数集合
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */

//跳跃表
#define OBJ_ENCODING_SKIPLIST 7 // Encoded as skiplist */

// string采用一种特殊的嵌入式的sds来表示
#define OBJ_ENCODING_EMBSTR 8 //Embedded sds string encoding embstr */

// 表示成quicklist。用于list数据结构
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
  • 类型与编码对应关系
类型 编码 对象
OBJ_STRING OBJ_ENCODING_INT 使用整数值实现的字符串对象。
OBJ_STRING OBJ_ENCODING_EMBSTR 使用 embstr 编码的简单动态字符串实现的字符串对象。
OBJ_STRING OBJ_ENCODING_RAW 使用简单动态字符串实现的字符串对象。
OBJ_LIST OBJ_ENCODING_QUICKLIST 用于list数据结构。(3.0版本后使用,之前的版本对应ziplist或linkedlist)
OBJ_HASH OBJ_ENCODING_ZIPLIST 使用压缩列表实现的哈希对象。
OBJ_HASH OBJ_ENCODING_HT 使用字典实现的哈希对象。
OBJ_SET OBJ_ENCODING_INTSET 使用整数集合实现的集合对象。
OBJ_SET OBJ_ENCODING_HT 使用字典实现的集合对象。
OBJ_ZSET OBJ_ENCODING_ZIPLIST 使用压缩列表实现的有序集合对象。
OBJ_ZSET OBJ_ENCODING_SKIPLIST 使用跳跃表和字典实现的有序集合对象。

Redis中的对象类型与底层编码》上有4条评论

  1. Pingback引用通告: Redis中的有序集合对象(Zset) | 精彩每一天

  2. Pingback引用通告: Redis中的集合对象(Set) | 精彩每一天

  3. Pingback引用通告: Redis中的哈希对象(Hash) | 精彩每一天

  4. Pingback引用通告: Redis中的列表对象(List) | 精彩每一天

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>