Redis压缩列表、跳表、位图的实现原理

本文深入探讨Redis中的数据结构,包括压缩列表(ziplist)、跳表(skiplist)和位图(BitMap)。ziplist作为内存优化的数据结构,适用于小型数据集;跳表用于有序集合,提供高效的查找;位图则在存储少量状态信息时表现出色。文章详细阐述了这些数据结构的实现原理和应用场景。
摘要由CSDN通过智能技术生成

ziplist数据结构

内存会一次性开辟一块大的连续的空间,来存放ziplist。

  • • zlbytes

32bit内存空间,表示ziplist占用的字节总数

  • • zltail

32bit内存空间,表示ziplist表中最后一项(entry)在ziplist中的偏移字节数,通过zltail可以很方便的找到最后一项,从而可以在ziplist尾端快速的执行push或pop操作。

  • • zllen

16bit内存空间,表示ziplist中数据项entry的个数

  • • zlend:255

ziplist最后一个字节,是一个结束标记,值固定等于255

  • • entry

表示真正存放数据的数据项,长度不定

  • • prerawlen

表示上一个节点的数据长度信息。

如果前一个元素的大小prerawlen等于254,用一个字节作为标记项,在用4个字节描述前一个元素大小。

ziplist额外的信息最多需要5个字节存储,相比quicklist双端链表的一个元素需要2个指针16个字节来说节省很多内存开销。

  • • len

entry中数据的长度

  • • data

表示当前元素里面的真实数据,业务数据存储,这是一个非常紧凑的二进制数据结构。

连续的内存空间也会存在弊端?

ziplist放入n多个元素的时候,再往里面添加元素,都需要分配新的内存空间,并且完成数据的完整拷贝。元素比较少还好,但如果元素很多的情况下,会很消耗性能。

那么就需要借助双端链表来控制ziplist的大小,如果超过一定的大小,则分裂成两个,保证每个ziplist不能太大。

quicklist的底层是quicklistNode,quicklistNode指向ziplist。

加一些数据,比如加入到ziplist里面去,不需要对数据整个做偏移,因为数据已经分配到不同的ziplist里面去了,修改数据,只需要修改某一个ziplist就可以了。

这是基于双端链表做的优化,可以从前往后遍历,也可以从后往前遍历。

接下来看下lpush源码

pushGenericCommand

先从redis数据库获取数据

  • • c->db

db就是要操作的redis数据库

  • • c->argv[1]

比如执行lpush命令

lpush alist a b c

argv[0]就是lpush
argv[1]就是alist

根据key去db中查找数据

  • • key->ptr

key真正所执行的字符串

进行rehash操作

-1表示没有进行rehash,不等于-1表示正在进行rehash。

做rehash的方法

筛选非空的hash槽

有时候,hash槽上不一定有数据,因为hashtable散列之后有的是空的,如果循环的时候发现有empty_visits=10个hash槽是空的,就不做rehash了。

这个while循环结束之后,剩下的都是非空的hash槽。

获取非空hash槽上链表的头节点

开始遍历链表,重新计算hash值。

这里是进行与运算,而不是求模运算,性能更高。

  • • size

size大小为2^n

  • • sizemask

sizemask=size-1=2^n-1

公式

任意数 % 2^n <=> 任意数 & (2^n-1)

即累除法求余数,一次位运算就能计算出结果,更加高效。

计算出key在新的hashtable上的位置之后,将老的hash槽索引指向新的hashtable的表头,并将老的hash槽上的链表迁移到新的hashtable上去,完成了数据迁移操作。

迁移过来之后,老的hashtable上的元素个数减1,新的加1。

一个hash槽一个hash槽的迁移数据。

判断老的hashtable中还有没有元素,如果没有的话,就释放掉老的hashtable。

将老的hashtable(ht[0])指向新的hashtable(ht[1]),新的hashtable(ht[1])就释放掉了。

至此,就完成了rehash的过程。

rehash完之后,接下来就是查找key的过程

先从老的hashtable查找(ht[0]),有的话就返回,没有的话再查找新的hashtable(ht[1]),还没有的话就返回null。

接下来就是检查查询到数据的类型

看是否为List数据类型

lpush alist a b c

如果alist不是List而是string 则会报异常提示类型不匹配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值