数据库
首页 > 数据库> > 【死磕 Redis】----- Redis 数据结构:对象(RedisObject)

【死磕 Redis】----- Redis 数据结构:对象(RedisObject)

作者:互联网

原文:https://www.topjava.cn/category/1391389927996002304chenssy


在前面几篇文章中,小编陆陆续续介绍了 Redis 用到的所有主要数据结构,如比如简单动态字符串(SDS)字典(dict)压缩列表(ziplist)整数集合( intset)跳跃表(skiplist)。然而 Redis 并没有直接使用这些数据结构来实现键值对的数据库,而是在这些数据结构之上又包装了一层 RedisObject(对象),RedisObject 有五种对象:字符串对象、列表对象、哈希对象、集合对象和有序集合对象。

redisObject 定义在 redis.h 文件中:

    typedef struct redisObject {
        unsigned type:4;
        unsigned encoding:4;
        unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
        int refcount;
        void *ptr;
    } robj;

其中各字段的含义如下:

/* Object types */
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
    #define REDIS_ENCODING_RAW 0     /* Raw representation */
    #define REDIS_ENCODING_INT 1     /* Encoded as integer */
    #define REDIS_ENCODING_HT 2      /* Encoded as hash table */
    #define REDIS_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
    #define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
    #define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
    #define REDIS_ENCODING_INTSET 6  /* Encoded as intset */
    #define REDIS_ENCODING_SKIPLIST 7  /* Encoded as skiplist */

下图展示了 redisObject 、Redis 所有数据类型、以及 Redis 所有编码方式(底层实现)三者之间的关系:

下面就这幅图来一一阐述每个数据类型的实现,由于底层实现都已经在前面文章分析了,所以不介绍了,如有不懂的参考以下链接:

字符串对象 STRING

字符串对象的 encoding 有三种,分别是:int、raw、embstr。

127.0.0.1:6379> set number 1234
OK
127.0.0.1:6379> object encoding number
"int"
127.0.0.1:6379>  set str "Spring Boot lets you externalize your configu"
OK
127.0.0.1:6379> strlen str
(integer) 45
127.0.0.1:6379> object encoding str
"raw"

如果这个字符串的长度小于 45 字节,那么字符串对象将使用 embstr 编码的方式来保存这个字符串值了。

127.0.0.1:6379>  set str "Spring Boot lets you externalize your config"
OK
127.0.0.1:6379> strlen str
(integer) 44
127.0.0.1:6379> object encoding str
"embstr"

可能有小伙伴说,既然有了 raw 的编码方式,为什么还会有 embstr 的编码方式呢?因为 embstr 编码是专门用于保存短字符串的一种优化编码方式,它具有如下优点:

哈希对象 HASH

哈希对象的编码有两种,分别是:ziplist、hashtable。

当哈希对象保存的键值对数量小于 512,并且所有键值对的长度都小于 64 字节时,使用压缩列表存储;否则使用 hashtable 存储。这两个条件是可以修改的。见 hash-max-ziplist-value 和 hash-max-ziplist-entries。

下面将演示一番:

# 插入一个 value 不超过 64 字节的键值对
127.0.0.1:6379> hset book name "sikeRedis"
(integer) 1
127.0.0.1:6379> object encoding book
"ziplist"
# 插入一个 value 为 64 字节的键值对
127.0.0.1:6379> hset person des "chenssy1chenssy1chenssy1chenssy1chenssy1chenssy1chenssy1chenssy1"
(integer) 1
127.0.0.1:6379> object encoding person
"ziplist"
# value 增大到 65 字节
127.0.0.1:6379> hset person des "chenssy1chenssy1chenssy1chenssy1chenssy1chenssy1chenssy1chenssy11"
(integer) 0
127.0.0.1:6379> object encoding person
"hashtable"

我们看到当我们插入一个 value 为 64 字节的键值对时,类型依然是 ziplist,当把 value 调整到 65 个字节的时候,对象的编码也由 ziplist 变为 hashtable 了。

下面演示因为键值对数量过多引起的编码转换的情况:

# 插入 512 个键值对
127.0.0.1:6379> eval "for i = 1,512 do  redis.call('HSET',KEYS[1],i,i) end " 1 "numbers"
(nil)
127.0.0.1:6379> hlen numbers
(integer) 512
# 编码为 ziplist
127.0.0.1:6379> object encoding numbers
"ziplist"
# 继续插入一个键值对
127.0.0.1:6379> hset numbers 513 "513"
(integer) 1
127.0.0.1:6379> hlen numbers
(integer) 513
# 编码变为 hashtable
127.0.0.1:6379> object encoding numbers
"hashtable"

以下的数据类型就不再演示了,具体流程和 hash 一致。

列表对象 LIST

列表对象的编码有两种: ziplist 和 linkedlist。

当列表对象可以同时满足以下两个条件时,列表对象使用 ziplist 编码:

  1. 列表对象保存的所有字符串元素的长度都小于 64 字节
  2. 列表对象保存的元素数量小于 512 个
  3. 如果不能同时满足这两个条件,列表对象则使用 linkedlist

以上两个条件的是可以修改的,见 list-max-ziplist-value 和 list-max-ziplist-entries。

集合对象 SET

集合对象的编码有两种:intset 和 hashtable。

当集合对象可以同时满足一下两个条件时,对象使用 intset 编码:

  1. 集合对象保存的所有元素都是整数值
  2. 集合对象保存的元素数量不超过 512 个

如果不能满足这两个条件的集合对象需要使用 hashtable 编码。其中第二条件可以修改配置文件修改:set-max-intset-entries。

有序集合对象 ZSET

有序集合的编码也有两种:ziplist 和 skiplist。

当有序集合对象可以同时满足以下两个条件,对象使用 ziplist 编码:

  1. 有序集合保存的元素数量小于 128 个
  2. 有序集合保存的所有元素成员的长度都小于 64 字节

不能同时满足以上两个条件的有序集合将使用 skiplist 编码。且上述两个条件可以通过配置文件修改,参数见:zset-max-ziplist-entries 和 zset-max-ziplist-value

参考

标签:0.1,127.0,对象,ziplist,RedisObject,Redis,6379,-----
来源: https://blog.csdn.net/chenssy/article/details/118280266