面试:原来Redis的五种数据类型数底层结构是这样的

关注我,可以获取最新知识、经典面试题以及微服务技术分享

  在Redis中会涉及很多数据结构,比如SDS,双向链表、字典、压缩列表、整数集合等等。Redis会基于这些数据结构自定义一个对象系统,而且自定义的对象系统有很多好处。

通过对以下的Redis对象系统的学习,可以了解Redis设计原理以及初衷,为了我们在使用Redis的时候,更加能够理解到其原理和定位问题。

Redis 对象

Redis基于上述的数据结构自定义一个Object 系统,Object结构:

redisObject结构:
     typedef struct redisObject{
    //类型
    unsigned type:4;
    //编码
    unsigned encoding:4;
    //指向底层实现数据结构的指针
    void *ptr;
    ….. 
} 

Object 系统包含五种Object:

  • String:字符串对象
  • List:列表对象
  • Hash:哈希对象
  • Set:集合对象
  • ZSet:有序集合

Redis使用对象来表示数据库中的键和值,即每新建一个键值对,至少创建有两个对象,而且使用对象的具有以下好处:
1. redis可以在执行命令前会根据对象的类型判断一个对象是否可以执行给定的命令
2. 针对不同的使用场景,为对象设置不同的数据结构实现,从而优化对象的不同场景夏的使用效率
3. 对象系统还可以基于引用计数计数的内存回收机制,自动释放对象所占用的内存,或者还可以让多个数据库键共享同一个对象来节约内存。
4. redis对象带有访问时间记录信息,使用该信息可以进行优化空转时长较大的key,进行删除!



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

编码常量 编码对应的底层数据结构
REDIS_ENCODING_INT long类型的整数
REDIS_ENCODING_EMBSTR embstr编码的简单动态字符串
REDIS_ENCODING_RAW 简单动态字符串
REDIS_ENCODING_HT 字典
REDIS_ENCODING_LINKEDLIST 双向链表
REDIS_ENCODING_ZIPLIST 压缩列表
REDIS_ENCODING_INTSET 整数集合
REDIS_ENCODING_SKIPLIST 跳跃表和字典



每种Object对象至少有两种不同的编码,对应关系:

类型 编码 对象
String int 整数值实现
String embstr sds实现 <=39 字节
String raw sds实现 > 39字节
List ziplist 压缩列表实现
List linkedlist 双端链表实现
Set intset 整数集合使用
Set hashtable 字典实现
Hash ziplist 压缩列表实现
Hash hashtable 字典使用
Sorted set ziplist 压缩列表实现
Sorted set skiplist 跳跃表和字典


String 对象

字符串对象编码可以int 、raw或者embstr,如果保存的值为整数值且这个值可以用long类型表示,使用int编码,其他编码类似。

比如:int编码的String Object

redis> set number 520 
 ok
 redis> OBJECT ENCODING number 
"int"

String Object结构:

file

String 对象之间的编码转换

int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下,会被转换为raw编码的字符串对象。

比如:对int编码的字符串对象进行append命令时,就会使得原来是int变为raw编码字符串


List对象

list对象可以为ziplist或者为linkedlist,对应底层实现ziplist为压缩列表,linkedlist为双向列表。

Redis>RPUSH numbers “Ccww” 520 1

用ziplist编码的List对象结构:

file

用linkedlist编码的List对象结构:

file

List对象的编码转换:

当list对象可以同时满足以下两个条件时,list对象使用的是ziplist编码:
1. list对象保存的所有字符串元素的长度都小于64字节
2. list对象保存的元素数量小于512个,
不能满足这两个条件的list对象需要使用linkedlist编码。

Hash对象

Hash对象的编码可以是ziplist或者hashtable
其中,ziplist底层使用压缩列表实现:

  • 保存同一键值对的两个节点紧靠相邻,键key在前,值vaule在后
  • 先保存的键值对在压缩列表的表头方向,后来在表尾方向

hashtable底层使用字典实现,Hash对象种的每个键值对都使用一个字典键值对保存:

  • 字典的键为字符串对象,保存键key
  • 字典的值也为字符串对象,保存键值对的值

比如:HSET命令

redis>HSET author name  "Ccww"
(integer)

redis>HSET author age  18
(integer)

redis>HSET author sex  "male"
(integer)

ziplist的底层结构:

file

hashtable底层结构:

file

Hash对象的编码转换:

当list对象可以同时满足以下两个条件时,list对象使用的是ziplist编码:
1. list对象保存的所有字符串元素的长度都小于64字节
2. list对象保存的元素数量小于512个,
不能满足这两个条件的hash对象需要使用hashtable编码

Note:这两个条件的上限值是可以修改的,可查看配置文件hash-max-zaiplist-value和hash-max-ziplist-entries


Set对象:

Set对象的编码可以为intset或者hashtable

  • intset编码:使用整数集合作为底层实现,set对象包含的所有元素都被保存在intset整数集合里面
  • hashtable编码:使用字典作为底层实现,字典键key包含一个set元素,而字典的值则都为null

inset编码Set对象结构:

    redis> SAD number  1 3 5 
file

hashtable编码Set对象结构:

redis> SAD Dfruits  “apple”  "banana" " cherry"
file

Set对象的编码转换:

使用intset编码:
1. set对象保存的所有元素都是整数值
2. set对象保存的元素数量不超过512个
不能满足这两个条件的Set对象使用hashtable编码

ZSet对象

ZSet对象的编码 可以为ziplist或者skiplist
ziplist编码,每个集合元素使用相邻的两个压缩列表节点保存,一个保存元素成员,一个保存元素的分值,然后根据分数进行从小到大排序。

ziplist编码的ZSet对象结构:

Redis>ZADD price 8.5 apple 5.0 banana 6.0 cherry
file

skiplist编码的ZSet对象使用了zset结构,包含一个字典和一个跳跃表

Type struct zset{

    Zskiplist *zsl;
    dict *dict;
    ...
}

skiplist编码的ZSet对象结构
file

ZSet对象的编码转换

当ZSet对象同时满足以下两个条件时,对象使用ziplist编码
1. 有序集合保存的元素数量小于128个
2. 有序集合保存的所有元素的长度都小于64字节
不能满足以上两个条件的有序集合对象将使用skiplist编码。

Note:可以通过配置文件中zset-max-ziplist-entries和zset-max-ziplist-vaule

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Redis的内存优化 声明:本文内容来自《Redis开发与运维》一书第八章,如转载请声明。 Redis所有的数据都...
    meng_philip123阅读 18,881评论 2 29
  • 参考来源 Redis的内存优化 Redis所有的数据都在内存中,而内存又是非常宝贵的资源。对于如何优化内存使用一直...
    秦汉邮侠阅读 1,285评论 0 2
  • 声明:本文内容来自《Redis开发与运维》一书第八章,如转载请声明。Redis所有的数据都在内存中,而内存又是非常...
    yoqu阅读 1,494评论 0 2
  • Redis 作为一种 KV 缓存服务器,有着极高的性能,相对于 Memcache,Redis 支持更多种数据类型,...
    为爱放弃一切阅读 517评论 0 8
  • 2017年6月,我参加了属于我们这一届的高考,匆匆那高中三年悄然结束,再见,我的六月,再见,我的高中。 2017年...
    尹沐夏阅读 249评论 0 2