深入学习Redis(四),基本类型【List】剖析

759 阅读3分钟
更多精彩文章,关注【ToBeTopJavaer】,更有数万元精品vip资源免费等你来拿!!!

接下来我们要剖析的基本类型是List,相信大家对List都不会陌生吧,下面我们将深入源码剖析Redis中List的实现。

存储类型


存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色。
操作命令


元素增减
lpush queue a
lpush queue b c
rpush queue d e
lpop queue
rpop queue
​blpop queue
brpop queue
取值
lindex queue 0
lrange queue 0 -1
存储( 实现) 原理


在早期的版本中,数据量较小时用 ziplist 存储,达到临界值时转换为 linkedlist 进
行存储,分别对应 OBJ_ENCODING_ZIPLIST 和 OBJ_ENCODING_LINKEDLIST 。
3.2 版本之后,统一用 quicklist 来存储。quicklist 存储了一个双向链表,每个节点
都是一个 ziplist
127.0.0.1:6379> object encoding queue
"quicklist"
什么是quicklist?

quicklist(快速列表)是 ziplist 和 linkedlist 的结合体。

quicklist.h源码如下,head 和 tail 指向双向列表的表头和表尾
typedef struct quicklist {
  quicklistNode *head; /* 指向双向列表的表头 */
  quicklistNode *tail; /* 指向双向列表的表尾 */
  unsigned long count; /* 所有的 ziplist 中一共存了多少个元素 */
  unsigned long len; /* 双向链表的长度, node 的数量 */
  int fill : 16; /* fill factor for individual nodes */
  unsigned int compress : 16; /* 压缩深度, 0: 不压缩; */
} quicklist;
redis.conf 相关参数:
list-max-ziplist-size(fill)
正数表示单个 ziplist 最多所包含的 entry 个数。
负数代表单个 ziplist 的大小, 默认 8k。
-1: 4KB; -2: 8KB; -3: 16KB; -4: 32KB; -5: 64KB


list-compress-depth(compress)
压缩深度, 默认是 0。
其它值含义: 1: 首尾的 ziplist 不压缩; 2: 首尾第一第二个 ziplist 不压缩, 以此类推
quicklistNode 中的*zl 指向一个 ziplist,一个 ziplist 可以存放多个元素。

源码如下:

typedef struct quicklistNode {
  struct quicklistNode *prev; /* 前一个节点 */
  struct quicklistNode *next; /* 后一个节点 */
  unsigned char *zl; /* 指向实际的 ziplist */
  unsigned int sz; /* 当前 ziplist 占用多少字节 */
  unsigned int count : 16; /* 当前 ziplist 中存储了多少个元素, 占 16bit(下同) , 最大 65536 个 */
  unsigned int encoding : 2; /* 是否采用了 LZF 压缩算法压缩节点, 1: RAW 2: LZF */
  unsigned int container : 2; /* 2: ziplist, 未来可能支持其他结构存储 */
  unsigned int recompress : 1; /* 当前 ziplist 是不是已经被解压出来作临时使用 */
  unsigned int attempted_compress : 1; /* 测试用 */
  unsigned int extra : 10; /* 预留给未来使用 */
} quicklistNode;

源码结构图



ziplist 的结构在探讨Hash时已经说过了,不再重复。


应用场景


用户消息时间线 timeline
因为 List 是有序的,可以用来做用户时间线
消息队列


List 提供了两个阻塞的弹出操作:BLPOP/BRPOP,可以设置超时时间。


BLPOP:BLPOP key1 timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

BRPOP:BRPOP key1 timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。


队列:先进先出:rpush blpop,左头右尾,右边进入队列,左边出队列。


栈:先进后出:rpush brpop


今天我们从底层源码剖析了基本数据类型List,接下来我们将会对剩下的几个常用的基本类型的深入探讨,敬请期待。
更多精彩文章,关注【ToBeTopJavaer】,更有数万元精品vip资源免费等你来拿!!!