在之前我们介绍了,Redis有五种基础数据类型,分别是String,Set,List,Hash与SortSet。
今天我们又学习了一个命令,我们可以使用DEBUG OBJECT key查询Redis中,存储数据的一些关键信息,如下所示:
我们发现了ziplist跟intset这两种不在上述基础类型的数据结构,这又是什么呢?
Redis为了节省内存空间,当Hash与Zset元素个数较少的时候,会使用ziplist进行存储,也就是压缩表。在压缩表中,元素紧密排列,更加节省内存。今天,我们一起来探讨ziplist的内部,看一看ziplist的实现。
- 数据结构Zlist是有上述元素构成:zlbytes 记录着整一个压缩表的长度
- zltail 记录着最后一个元素的偏移量,这是为了倒序遍历整个zlist
- zlen 用来记录压缩表中节点的数量
- entryX 列表中的节点,节点用来存储具体的数据,厂部补丁。
- zlend 一个特殊值0XFF,用来标记压缩列表已经结束了。
我们注意到,在Redis中,数据结构压缩表是紧凑排列的,所以,我们每次查询都需要遍历整一个列表,才能查询到相关数据,因为ziplist存放的个数非常有限,所以性能的开销并不大。
接下来,我们来看一看Redis的压缩表中,节点的构成。
- prevlen 用来记录上一个节点的长度,因为压缩表可能需要倒序遍历,所以需要记录prevlen才能够定位出上一个entry的位置。
- encoding 在Redis的压缩表中,设计精髓都在这里,为了节省压缩表占用的内存,Redis对Encoding进行了极致的设计。一般都是读取前8个字节,用来判断存储的数据是什么。举个简单的例子,如果前8个字节是00xxxxxx,这里的00开头,表示的是这是个非常短的字符串,后面的6个x表示字符串的长度,2^6-1等于63,所以,这个数据就encoding就表示,content是一个非常短的字符串,长度最多为63位。另一个例子,如果前8个字节是11111110,那么这个表示是int8,后面跟一个字节用来表示整数。
- content 用来存放具体的数据,前面已经提到了,是用来存放具体的数据。
根据上述规则,假如我们存放的数据是"hello world",那么Redis用来保存这个数据Entry如下所示,prevlen用来保存上一个Entry的长度,跟本数据无关,因为是小字符串,所以encoding为00001011,1011表示长度为11,content则为长度为11的字符串helloworld。
最后,我们再来了解下连锁更新,如同数据结构中数组插入元素时间复杂度为O(N)一样,在Redis的数据结构压缩表中,插入数据也会一样,并且插入数据还可能会引起连锁更新,因为每个Entry都会记录上一个Entry的长度,所以,在插入一定数量的Entry之后,Redis就会使用其他数据结构进行数据的存储。
好了,有关Redis压缩表我们就介绍到这里。欢迎大家关注我,近期还准备了一些AI相关的知识,整理后会和大家继续分享。大家的支持是我继续唠嗑的动力。同名公众号(沙茶敏碎碎念)