Redis学习日志(二)

10. 对象

Redis对象系统结构 string(字符串),hash(哈希),list(列表),set(集合)及zset(有序集合)。
五种类型对象的构建用到了以上的主要数据结构:简单动态字符串、双端链表、字典、压缩列表、整数集合。
Redis中的键值对,键总是一个字符串对象,值可以是五种对象中的一种。
“字符串键”指key-value 中的value是字符串对象类型
“列表键”指key-value 中的value是列表对象类型

    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;
对象 对象type属性值 TYPE命令输出
字符串对象 REDIS_STRING “string”
列表对象 REDIS_LIST “list”
哈希对象 REDIS_HASH “hash”
集合对象 REDIS_SET “set”
有序集合对象 REDIS_ZSET “zset”

对象的ptr指针指向对象的底层实现数据结构,由对象的encoding属性决定。

编码常量 底层数据结构
REDIS_ENCODING_INT long类型整数
REDIS_ENCODING_EMBSTR embstr编码的简单动态字符串 (长度<=32字节)
REDIS_ENCODING_RAM 简单动态字符串
REDIS_ENCODING_HT 字典
REDIS_ENCODING_LINKEDLIST 双端链表
REDIS_ENCODING_ZIPLIST 压缩列表
REDIS_ENCODING_INTSET 整数集合
REDIS_ENCODING_SKIPLIST 跳跃表和字典
        /*默认以RAW字符编码,若需要调整则在调用处显式更改 */
        robj *createObject(int type, void *ptr) {
            robj *o = zmalloc(sizeof(*o));
            o->type = type;
            o->encoding = REDIS_ENCODING_RAW;
            o->ptr = ptr;
            o->refcount = 1;
            /* Set the LRU to the current lruclock (minutes resolution). */
            o->lru = LRU_CLOCK();
            return o;
        }   
        /* 创建一个 ZIPLIST 编码的列表对象  */
        robj *createZiplistObject(void) {
            unsigned char *zl = ziplistNew();
            robj *o = createObject(REDIS_LIST,zl);
            o->encoding = REDIS_ENCODING_ZIPLIST; //显式更改编码
            return o;
        }

11. 字符串对象

字符串对象的编码可以是int embstr raw
根据不同的操作,会将值的编码进行转换。
字符串命令和对应编码操作:(具体命令及方式见图8-7字符串命令及操作)
Redis学习日志(二)_第1张图片

命令 意义
SET 以对应编码保存值
GET 以字符串形式返回值
APPEND 以字符串形式追加值
INCRBYFLOAT 将值转换成浮点数进行计算保存
INCRBY 对整数进行加法计算保存
DECRBY 对整数进行减法计算保存
STRLEN 返回对应值的字符串长度
GETRANGE 获取对应值的字符串形式,及其索引字符

12.列表对象

      列表对象的编码可以是ziplist linkedlist
        redis>RPUSH members 1 "three" 5
        (integer)3
    1)若为ziplist编码:

        |redisObject
        |type=REDIS_LIST
        |encoding=REDIS_ENCODING_ZIPLIST
        |ptr        ---->|zlbytes|zltail|zllen|1|"three"|5|zlend|
        |...

    2)若为linkedlist编码: 
    双端链表中每个节点是一个StringObject,每个StringObject的编码根据对应的值决定
        |redisObject
        |type=REDIS_LIST
        |encoding=REDIS_ENCODING_LINKEDLIST
        |ptr        ---->|StringObject:1|StringObject:"three"|StringObject:5|
        |...
    列表对象采用ziplist编码的条件:(两个都需要满足)
    ①列表对象保存的所有字符串元素长度都小于64字节
    ②列表对象保存的元素数量小于512个
    若不能满足以上两个条件,则采用linkedlist编码。
    列表命令及相应编码操作:(具体见图8-8列表命令及操作)
        LPUSH
        RPUSH
        LPOP
        RPOP
        LINDEX
        LLEN
        LINSERT
        LREM
        LTRIM
        LSET

Redis学习日志(二)_第2张图片

13.哈希对象

    哈希对象编码可以是ziplist hashtable
        redis> HSET profile name "tom"
        (integer)1
        redis> HSET profile age 25
        (integer)1
        redis> HSET profile career "programmer"
        (integer)1
    1)ziplist编码:当有新键值对要加入时,
                   先将保存键的压缩列表节点放置压缩列表表尾,
                   再将保存值的压缩列表节点放置压缩列表表尾。
      因此同一键值对的节点会紧挨在一起,且先添加入的键值对靠前,后添加的键值对靠后。
        |redisObject
        |type=REDIS_HASH
        |encoding=REDIS_ENCODING_ZIPLIST
        |ptr        ---->|zlbytes|zltail|zllen|"name"|"tom"|"age"|25|"career"|"programmer"|zlend|
        |...
    2)hashtable编码: 每个键值对使用一个字典键值对来保存
                      每个键和值都是一个字符串对象。
        |redisObject
        |type=REDIS_HASH
        |encoding=REDIS_ENCODING_HT
        |ptr        ----> |dict|
        |...              |StringObject:"age"   |-->|StringObject:25|
                          |StringObject:"career"|-->|StringObject:"programmer"|
                          |StringObject:"name"  |-->|StringObject:"tom"|

    哈希对象采用ziplist编码的条件:(两个都需要满足)
    ①哈希对象保存的所有键值对的键和值 字符串长度都小于64字节
    ②哈希对象保存的键值对数量小于512个
    若不能满足以上两个条件,则采用hashtable编码。
    哈希命令及相应编码操作:(具体见图8-9哈希命令及操作)
    命令:
        HSET
        HGET
        HEXISTS
        HDEL
        HLEN
        HGETALL

Redis学习日志(二)_第3张图片

14.集合对象:

    集合对象的编码可以是intset hashtable
    1)intset编码:保存在整数集合中。
        redis> SADD members 1 3 5
        (integer)3

        |redisObject                    |-> intset
        |type=REDIS_SET                 |   encoding=INT16
        |encoding=REDIS_ENCODING_INTSET |   length=3
        |ptr        ---------------------   contents-->|1|3|5|

    1)hashtable编码:字典的每个键都是字符串对象,
                     每个字符串对象包含一个集合元素
                     字典的值全部设置为null
        redis> SADD members "apple" "banana" "cherry"
        (integer)3

        |redisObject
        |type=REDIS_SET
        |encoding=REDIS_ENCODING_HT
        |ptr        ----> |dict|
        |...              |StringObject:"apple" |-->NULL
                          |StringObject:"banana"|-->NULL
                          |StringObject:"cherry"|-->NULL
    集合对象采用intset编码的条件:(两个都需要满足)
    ①集合对象保存的所有元素都是整数值
    ②集合对象保存的元素数量小于512个
    若不能满足以上两个条件,则采用hashtable编码。
    集合命令及相应编码操作:(具体见图8-10集合命令及操作)
    命令:
        SADD
        SCARD
        SISMEMBER
        SMEMBERS
        SRANDMEMBER
        SPOP
        SREM

Redis学习日志(二)_第4张图片

15.有序集合:

有序集合对象的编码可以是ziplist skiplist
redis> SADD members  "apple" 8.0 "banana" 5.0 "cherry" 9.0
(integer)3
1)ziplist编码: 当有新键值对要加入时,会对分值低的键值对先插入
                先将保存键的压缩列表节点放置压缩列表表尾,
                再将保存值的压缩列表节点放置压缩列表表尾。
      因此同一键值对的节点会紧挨在一起,分值低的元素靠前,分值高的靠后。
        |redisObject
        |type=REDIS_ZSET
        |encoding=REDIS_ENCODING_ZIPLIST
        |ptr        ---->|zlbytes|zltail|zllen|"banana"|5.0|"apple"|8.0|"cherry"|9.0|zlend|
        |...

2)skiplist编码: 使用zset结构作为底层实现,zset结构包含一个字典和跳跃表
        typedef struct zset{
            zskiplist *zsl;
            dict *dict;
        }zset;
    zset结构中的zsl跳跃表按分值从小到大保存所有集合元素,每个跳跃表节点都保存了一个集合元素
    跳跃表节点的object属性保存元素的成员,score属性保存元素分值。
    zset结构中dict字典为有序集合创建了一个从成员到分值的映射,字典每个键值对都保存一个集合元素(成员对象和它的分值)
    有序集合每个元素的成员都是字符串对象,元素的分值都是double类型浮点数。
    (跳跃表和字典都通过指针共享相同元素的成员和分值,不会有重复元素副本)
为什么有序集合zset结构同时使用跳跃表和字典来实现?
    答:有序集合需要满足 有序、查找 等功能
        单独使用跳跃表实现,能够保证有序及范围型操作功能,但在根据成员查找分值操作时复杂度为O(logN)
        单独使用字典实现,能够保证成员和分值映射查找复杂度为O(1) 但不能以有序方式保存集合元素。
skiplist编码的有序集合实现方式,见图8-16skiplist编码有序集合对象
有序集合对象采用ziplist编码的条件:(两个都需要满足)
①有序集合对象保存的所有元素成员长度小于64字节
②有序集合对象保存的元素数量小于128个
若不能满足以上两个条件,则采用skiplist编码。
有序集合命令及相应编码操作:(具体见图8-11有序集合命令及操作)
    命令:
        ZADD
        ZCARD
        ZCOUNT
        ZRANGE
        ZREVRANGE
        ZRANK
        ZREVRANK
        ZREM
        ZSCORE

Redis学习日志(二)_第5张图片

你可能感兴趣的:(Redis,redis)