当前位置:首页 > 缓存 > 正文内容

redis中底层的编码转换

phpmianshi4年前 (2017-05-22)缓存172
编码转化
Redis 使用对象(redisObject)来表示数据库中的键值,当我们在 Redis 中创建一个键值对时,至少创建两个对象,一个对象是用做键值对的键对象,另一个是键值对的值对象。
例如我们执行 SET MSG XXX 时,键值对的键是一个包含了字符串“MSG”的对象,键值对的值对象是包含字符串”XXX”的对象。
redisObject 的结构如下:
typedef struct redisObject{
    //类型
   unsigned type:4;
   //编码
   unsigned encoding:4;
   //指向底层数据结构的指针
   void *ptr;
    //...
 }robj;
其中 type 字段记录了对象的类型,包含字符串对象、列表对象、哈希对象、集合对象、有序集合对象。
当我们执行 type key 命令时返回的结果如下:

图片.png

ptr 指针字段指向对象底层实现的数据结构,而这些数据结构是由 encoding 字段决定的,每种对象至少有两种数据编码:
图片.png
细心的读者可能注意到,list、hash、zset 三个键使用的是 ziplist 压缩列表编码,这就涉及到了 Redis 底层的编码转换。
上面介绍到,ziplist 是一种结构紧凑的数据结构,当某一键值中所包含的元素较少时,会优先存储在 ziplist 中,当元素个数超过某一值后,才将 ziplist 转化为标准存储结构,而这一值是可配置的。
1、String 对象的编码转化
String 对象的编码可以是 int 或 raw,对于 String 类型的键值,如果我们存储的是纯数字,Redis 底层采用的是 int 类型的编码,如果其中包括非数字,则会立即转为 raw 编码:
127.0.0.1:6379> set str 1
OK
127.0.0.1:6379> object encoding str
"int"
127.0.0.1:6379> set str 1a
OK
127.0.0.1:6379> object encoding str
"raw"
2、List 对象的编码转化
List 对象的编码可以是 ziplist 或 linkedlist,对于 List 类型的键值,当列表对象同时满足以下两个条件时,采用 ziplist 编码:
  • 列表对象保存的所有字符串元素的长度都小于 64 字节

  • 列表对象保存的元素个数小于 512 个

如果不满足这两个条件的任意一个,就会转化为 linkedlist 编码。
注意:这两个条件是可以修改的。
在 redis.conf 中:
list-max-ziplist-entries 512
list-max-ziplist-value 64
3、Set 类型的编码转化
Set 对象的编码可以是 intset 或 hashtable,intset 编码的结果对象使用整数集合作为底层实现,把所有元素都保存在一个整数集合里面。
127.0.0.1:6379> sadd set 1 2 3
(integer) 3
127.0.0.1:6379> object encoding set
"intset"
如果 set 集合中保存了非整数类型的数据时,Redis 会将 intset 转化为 hashtable:
127.0.0.1:6379> sadd set 1 2 3
(integer) 3
127.0.0.1:6379> object encoding set
"intset"
127.0.0.1:6379> sadd set a
(integer) 1
127.0.0.1:6379> object encoding set
"hashtable"
当 Set 对象同时满足以下两个条件时,对象采用 intset 编码:
  • 保存的所有元素都是整数值(小数不行)

  • Set 对象保存的所有元素个数小于 512 个

不能满足这两个条件的任意一个,Set 都会采用 hashtable 存储。
注意:第两个条件是可以修改的。
在 redis.conf 中:
set-max-intset-entries 512
4、Hash 对象的编码转化
Hash 对象的编码可以是 ziplist 或 hashtable,当 Hash 以 ziplist 编码存储的时候,保存同一键值对的两个节点总是紧挨在一起,键节点在前,值节点在后:
图片.png
当 Hash 对象同时满足以下两个条件时,Hash 对象采用 ziplist 编码:
  • Hash 对象保存的所有键值对的键和值的字符串长度均小于 64 字节

  • Hash 对象保存的键值对数量小于 512 个

如果不满足以上条件的任意一个,ziplist 就会转化为 hashtable 编码。
注意:这两个条件是可以修改的。
在 redis.conf 中:
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
5、Zset 对象的编码转化
Zset 对象的编码可以是 ziplist 或 zkiplist,当采用 ziplist 编码存储时,每个集合元素使用两个紧挨在一起的压缩列表来存储。
第一个节点存储元素的成员,第二个节点存储元素的分值,并且按分值大小从小到大有序排列。

图片.png

在 redis.conf 中:

zset-max-ziplist-entries 128
zset-max-ziplist-value 64m
思考:Zset 如何做到 O(1) 复杂度内元素并且快速进行范围操作?
Zset 采用 skiplist 编码时使用 zset 结构作为底层实现,该数据结构同时包含了一个跳跃表和一个字典。
其结构如下:
typedef struct zset{
   zskiplist *zsl;
   dict *dict;
}
Zset 中的 dict 字典为集合创建了一个从成员到分值之间的映射,字典中的键保存了成员,字典中的值保存了成员的分值,这样定位元素时时间复杂度是 O(1)。
Zset 中的 zsl 跳跃表适合范围操作,比如 ZRANK、ZRANGE 等,程序使用 zkiplist。
另外,虽然 Zset 中使用了 dict 和 skiplist 存储数据,但这两种数据结构都会通过指针来共享相同的内存,所以没有必要担心内存的浪费。


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

Redis和memache缓存的区别

1.数据类型Redis数据类型丰富,支持set list hash等类型memcache支持简单数据类型,需要客户端自己处理复杂对象2.持久性redis支持数据落地持久化存储,并不是所有的数据都一直存...

Redis中主从复制的原理详解

主从复制的方式命令slaveof。优点:无需重启。缺点:不便于管理 // 命令行使用 slaveof ip port // 使用命令后自身...

redis中zset有序集合的底层实现

redis中zset有序集合的底层实现

跳跃表Zset 是一个有序的链表结构,其底层的数据结构是跳跃表 skiplist,其结构如下:typedef struct zskiplistNode ...

redis中持久化机制对比

RDB filesnapshotting1.按特定的时间间隔来为数据集做快照2.每次持久化都是将全量数据写入,而不是增量3.每次写入时先将数据写入临时文件再替换掉原来的rdb文件优点:1.RDB是一个...

Redis Hyperloglog实现UV数据统计

Redis  自2.8.9起可用时间复杂度: O(1)添加每个元素。HyperLogLog 是一种概率数据结构,用来估算数据的基数。数据集可以是网站访客的 IP 地址,E-mail 邮箱或者...

redis中过期数据的删除以及对性能的影响

过期数据的删除对Redis性能影响当我们对某些 key 设置了 expire 时,数据到了时间会自动删除。如果一个键过期了,它会在什么时候删除呢?下面介绍三种删...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。