Redis从入门到放弃系列(三) List

Redis从入门到放弃系列(三) List

本文例子基于:5.0.4 List是Redis中一种比较常见的数据结构,其实现为quicklist,quicklist是一个ziplist的双向链表

Redis从入门到放弃系列(一) String

Redis从入门到放弃系列(二) Hash

首先让我们来看一下该如何在redis里面使用List类型

1//设置key的列表为value 2lpush key value [value...] 3

代码示例:

1//栈的用法,rpush rpop一样~ 通过rpush,lpop相当于堆的用法 2> lpush books java python c 3(integer) 3 4> lpop books 5"c" 6> lpop books 7"python" 8> lpop books 9"java" 10---------------------------------- 11//返回列表key指定区间的元素,区间偏移量start跟stop指定 12//start跟stop的下表都是以0为底 13> lrange books 0 2 141) "c" 152) "python" 163) "java" 17---------------------------------- 18//ltrim可以作为一个定长的list,每次都可以获取到最新的2条数据 19> lpush books java python c c++ 20(integer) 4 21> ltrim books 0 1 22OK 23> lrange books 0 -1 241) "c++" 252) "c" 26---------------------------------- 27//当给定列表内没有任何元素可供弹出的时候,连接将被blpop ,brpop命令阻塞,直到等待超时或发现可弹出元素为止。 28//设置超时 1秒 29> BLPOP books 1 301) "books" 312) "c++" 32> BLPOP books 1 331) "books" 342) "c" 35> BLPOP books 1 36(nil) 37(1.05s) 38---------------------------------- 39

至此,redis list的用法先告一段落.


源码解析

本文开头的时候讲list实现为quicklist,quicklist是一个ziplist的双向链表,那么其内部结构是怎样的呢?

1/* quicklist is a 40 byte struct (on 64-bit systems) describing a quicklist. 2 * 'count' is the number of total entries. 3 * 'len' is the number of quicklist nodes. 4 * 'compress' is: -1 if compression disabled, otherwise it's the number 5 * of quicklistNodes to leave uncompressed at ends of quicklist. 6 * 'fill' is the user-requested (or default) fill factor. */ 7typedef struct quicklist { 8 quicklistNode *head; 9 quicklistNode *tail; 10 unsigned long count; /* total count of all entries in all ziplists */ 11 unsigned long len; /* number of quicklistNodes */ 12 int fill : 16; /* fill factor for individual nodes */ 13 unsigned int compress : 16; /* depth of end nodes not to compress;0=off */ 14} quicklist; 15 16/* quicklistNode is a 32 byte struct describing a ziplist for a quicklist. 17 * We use bit fields keep the quicklistNode at 32 bytes. 18 * count: 16 bits, max 65536 (max zl bytes is 65k, so max count actually < 32k). 19 * encoding: 2 bits, RAW=1, LZF=2. 20 * container: 2 bits, NONE=1, ZIPLIST=2. 21 * recompress: 1 bit, bool, true if node is temporarry decompressed for usage. 22 * attempted_compress: 1 bit, boolean, used for verifying during testing. 23 * extra: 10 bits, free for future use; pads out the remainder of 32 bits */ 24typedef struct quicklistNode { 25 struct quicklistNode *prev; 26 struct quicklistNode *next; 27 unsigned char *zl; 28 unsigned int sz; /* ziplist size in bytes */ 29 unsigned int count : 16; /* count of items in ziplist */ 30 unsigned int encoding : 2; /* RAW==1 or LZF==2 */ 31 unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */ 32 unsigned int recompress : 1; /* was this node previous compressed? */ 33 unsigned int attempted_compress : 1; /* node can't compress; too small */ 34 unsigned int extra : 10; /* more bits to steal for future usage */ 35} quicklistNode; 36/* quicklistLZF is a 4+N byte struct holding 'sz' followed by 'compressed'. 37 * 'sz' is byte length of 'compressed' field. 38 * 'compressed' is LZF data with total (compressed) length 'sz' 39 * NOTE: uncompressed length is stored in quicklistNode->sz. 40 * When quicklistNode->zl is compressed, node->zl points to a quicklistLZF */ 41typedef struct quicklistLZF { 42 unsigned int sz; /* LZF size in bytes*/ 43 char compressed[]; 44} quicklistLZF; 45

从上面我们可以知道,quicklist是一个的双向链表,所以当我们使用lpush,rpop等操作是O(1)了。

ziplist本身也是一个能够维持数据先后顺序的列表(按照插入位置),而且是一个内存紧凑的列表。 当我们要表示list拥有12个数据项,这时候就会有可能有多种选择了,例如3个节点的quicklist,每个节点ziplist又包含4个数据项.或者2个节点的quicklist,每个节点ziplist又包含6个数据项 那么redis是如何选择的呢?我们可以再redis.conf找到蛛丝马迹~

1# Lists are also encoded in a special way to save a lot of space. 2# The number of entries allowed per internal list node can be specified 3# as a fixed maximum size or a maximum number of elements. 4# For a fixed maximum size, use -5 through -1, meaning: 5# -5: max size: 64 Kb <-- not recommended for normal workloads 6# -4: max size: 32 Kb <-- not recommended 7# -3: max size: 16 Kb <-- probably not recommended 8# -2: max size: 8 Kb <-- good 9# -1: max size: 4 Kb <-- good 10# Positive numbers mean store up to _exactly_ that number of elements 11# per list node. 12# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), 13# but if your use case is unique, adjust the settings as necessary. 14list-max-ziplist-size -2 15 16# Lists may also be compressed. 17# Compress depth is the number of quicklist ziplist nodes from *each* side of 18# the list to *exclude* from compression. The head and tail of the list 19# are always uncompressed for fast push/pop operations. Settings are: 20# 0: disable all list compression 21# 1: depth 1 means "don't start compressing until after 1 node into the list, 22# going from either the head or tail" 23# So: [head]->node->node->...->node->[tail] 24# [head], [tail] will always be uncompressed; inner nodes will compress. 25# 2: [head]->[next]->node->node->...->node->[prev]->[tail] 26# 2 here means: don't compress head or head->next or tail->prev or tail, 27# but compress all nodes between them. 28# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] 29# etc. 30list-compress-depth 0 31 32 33 34list-max-ziplist-size 35

当设置为正数意味着最多只能储存该数量的元素,redis的作者建议设置为-1 or -2,设置每个quicklist节点上的ziplist能储存元素的大小~ 当列表很长的时候,中间的数据被访问的频率就有可能很低,那么在这种情况下,list提供了一个参数能够将中间的数据压缩~

1list-compress-depth 0 2

这个参数表示quicklist两端不被压缩的节点数.head节点跟tail节点总是不压缩的,方便在list的两端进行快速存取

  • 0: 是个特殊值,表示都不压缩。这是Redis的默认值。
  • 1: 表示quicklist两端各有1个节点不压缩,中间的节点压缩。
  • 2: 表示quicklist两端各有2个节点不压缩,中间的节点压缩。
  • 3: 表示quicklist两端各有3个节点不压缩,中间的节点压缩。
  • 依此类推…

quickList结构图如下图所示:

图中对应的ziplist的配置大小和节点压缩深度配置如下:

1list-max-ziplist-size 3 2list-compress-depth 1 3

在这里例子中我们可以看到,quickList两端各有一个节点没有被压缩,它们的数据指针指向真正的ziplist(即zl的指向).中间的其他节点是被压缩过的,它们的数据指针指向quicklistLZF

应用场景

1.消息队列(无ack机制)

1//生产者使用lpush将消息放入list中,消费者就可以通过rpop取出该消息,并且可以保证消息的有序性。 2>lpush message "ces" 3(integer) 1 4>rpop message 5"ces" 6

2.时间轴

1//一种场景就是当用户发送一条微博,通过lpush将它存放到list中,然后通过lrange就可以取出最近的最新的微博信息了 2> lpush weibo "xiaoxi1" 3(integer) 1 4> lpush weibo "xiaoxi2" 5(integer) 2 6> lpush weibo "xiaoxi3" 7(integer) 3 8> lrange weibo 0 9 91) "xiaoxi3" 102) "xiaoxi2" 113) "xiaoxi1" 12

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Redis从入门到放弃系列(二) Hash

Redis从入门到放弃系列(二)Hash本文例子基于:5.0.4Hash是Redis中一种比较常见的数据结构,其实现为hashtable/ziplist,默认创建时为ziplist,当到达一定量级时,redis会将ziplist转化为hashtableRedis从入门到放弃系列(一)String

Redis从入门到放弃系列(四) Set

Redis从入门到放弃系列(四)Set本文例子基于:5.0.4Set是Redis中一种比较常见的数据结构,当存储的member为十进制64位有符号整数范围内的整数的字符串的时候其实现为intset,其他为hashtableRedis从入门到放弃系列(三)List(https://www.osch

Redis从入门到放弃系列(十) Cluster

Redis从入门到放弃系列(十)Cluster本文例子基于:5.0.4RedisCluster集群高可用方案,去中心化,最基本三主多从,主从切换类似Sentinel,关于Sentinel内容可以查看编者另外一篇【Redis从入门到放弃系列(九)Sentinel(https://www.o