持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
前言
数据结构中数组和链表通常都是最常见的数据结构,那么Redis的list的底层数据结构是采用何种数据结构实现的呢?
数据结构存储
不同的的Redis版本list的数据结构有所不同,Redis3.2之前的版本,List的数据结构分为双向链表、ziplist,而在Redis3.2之后的版本出现了quickList数据结构存储。
linkedlist
与java的中的linkedlist类似,Redis中的linkList是一个双向链表,具体结构如下:
说明:
- pre:指向前一个节点
- next:指针指向后一个节点
- value保存着当前节点对应的数据对象
- head:指向链表的头节点
- tail:指向链表的尾节点
- len:表示这个链表共有多少个节点,这样就可以在O(1)的时间复杂度内获得链表的长度.
ziplist
zipList称之为压缩列表,是一种非常节省内存的结构,其数据结构如下:
说明:
- zlbytes:列表长度
- zltail : 列表尾的偏移量
- zllen:表示entry的个数
- zlend: 列表结束
其中Entry的结构如下:
- prelen:保存的是前一个entry节点的长度,这样在倒序遍历时就可以通过这个参数定位到上一个entry的位置
- encoding:保存了content的编码类型
- content:则是保存的元素内容,它是optional类型的,表示这个字段是可选的。当content是很小的整数时,它会内联到content字段的尾部.
quickList
qucikList是由zipList和双向链表linkedList组成的混合体。它将linkedList按段切分,每⼀段使⽤zipList来紧凑存储,多个zipList之间使⽤双向指针串接起来,其结构示意图如下:
小结
关于这三种数据结构存储的优缺点分别如下:
常用命令
lpush 从头部添加元素
lpush 从尾部添加元素
lrange 获取某个区间的值
lpop 从左边删除元素
lpop 从右边删除元素
llen list的长度
lindex 通过下标获取值
lrem 删除指定元素
ltirm 截断列表
应用场景
- 由于list存在lpush/rpop命令,我们可以采用list作为简单的消息队列.
特别说明:采用rpop命令时,即使没有新的消息写入list,消费者也要不停地调用rpop命令,这就会导致消费者程序的 CPU 一直消耗在执行 RPOP 命令上,带来不必要的性能损失,可以采用BRPOP命令也称为阻塞式读取,客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据。和消费者程序自己不停地调用 RPOP 命令相比,这种方式能节省 CPU 开销。
总结
本文讲解了Redis的list的数据结构存储和相关的基础命令,如有疑问可以随时反馈。