redis 的几种数据类型 & 各自底层实现

对象类型与编码

redis的key和value 都是对象。redis对象有五种:

类型常量对象的名称
REDIS_STRING字符串对象
REDIS_LIST列表对象
REDIS_HASH哈希对象
REDIS_SET集合对象
REDIS_ZSET有序集合对象

key总是字符串对象,value有可能是以上五种。

对象的内部结构

typedef struct redisObject {

    // 类型
    unsigned type:4;

    // 编码
    unsigned encoding:4;

    // 指向底层实现数据结构的指针
    void *ptr;

    // ...

} robj;

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

encoding 记录了这个对象使用了什么数据结构作为对象的底层实现。

编码常量底层数据结构OBJECT ENCODING 命令输出
REDIS_ENCODING_INTlong 类型的整数“int”
REDIS_ENCODING_EMBSTRembstr 编码的简单动态字符串“embstr”
REDIS_ENCODING_RAW简单动态字符串“raw”
REDIS_ENCODING_HT字典“hashtable”
REDIS_ENCODING_LINKEDLIST双端链表“linkedlist”
REDIS_ENCODING_ZIPLIST压缩列表“ziplist”
REDIS_ENCODING_INTSET整数集合“intset”
REDIS_ENCODING_SKIPLIST跳跃表和字典“skiplist”

字符串对象

编码: int | raw | embstr

1、字符串对象,如果保存整数。void则指向long,编码设置为int。

2、如果是字符串会根据字符串长度判断编码方式。(sds len属性)

长度大于39个字节,那么数据结构为SDS,编码为raw。

image

如果是字符串,且小于39个字节,将使用embstr编码保存。

embstr是一种优化编码。虽然也使用SDS数据结构,但它只调用一次内存分配,比raw少调用一次。

它调用一次内存分配,直接分配一块连续的空间, 空间中依次包含 redisObject 和 sdshdr 两个结构。

image

3、最后,redis对于浮点数的保存也是使用sds,当作字符串值来保存的。编码类型为embstr或raw。

列表对象

编码: ziplist | linkedlist

ziplist 数据结构:
image

linkedlist 底层实现数据结构:
image

它是一个双端链表,每个节点node保存了一个字符串对象。

字符串对象是一个非常基本的对象,它不仅被用作key,还会被其它结构(比如linkedlist的底层列表)嵌套。

列表对象使用ziplist编码时,保存的所有字符串元素长度小于64字节,且元素数量小于512个。
否则列表对象使用linkedlist编码。

以上两个值是可以通过配置文件进行修改的。

哈希对象

编码:ziplist | hashtable

ziplist 底层实现:
image
image

key和value是先后被push到表尾的。key与value紧挨着,同时每对key-value也紧挨着。(key与value都是StringObject)

hashtable 底层数据结构:

image

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

哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节;
哈希对象保存的键值对数量小于 512 个。

以上两个值是可以通过配置文件进行修改的。

集合对象(set)

编码:intset | hashtable

intset底层数据结构:
image
底层实现是一个整数集合。

hashtable底层数据结构:
image

key(StringObject)保存元素值,value为NULL。

使用intset条件:

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

元素数量上限是可以修改的。

有序集合对象

编码: ziplist | skiplist(跳表)

ziplist 底层实现结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eYEEoWRT-1587976902750)(http://redisbook.com/_images/graphviz-61b04c9bb72915ec0374125ba9455bc6783db4ff.png)]
image

每个集合元素使用两个紧挨在一起的压缩列表节点来保存, 第一个节点保存元素的成员(member), 而第二个元素则保存元素的分值(score)。

压缩列表内的集合元素按分值从小到大进行排序。

skiplist 底层实现:
使用zset,一个zset结构同时包含一个字典和一个跳表:

typedef struct zset {

    zskiplist *zsl;

    dict *dict;

} zset;

zsl 跳跃表按分值从小到大保存了所有集合元素。

每个跳跃表节点都保存了一个集合元素: 跳跃表节点的 object 属性保存了元素的成员, 而跳跃表节点的 score 属性则保存了元素的分值。

通过这个跳跃表, 程序可以对有序集合进行范围型操作, 比如 ZRANK 、 ZRANGE 等命令就是基于跳跃表 API 来实现的。

dict 字典为有序集合创建了一个从成员到分值的映射。

待。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值