Redis中的List数据类型
1435597771 · Jul 9, 2026
Redis List 是什么 在redis中, List类型是字符串列表,按照插入顺序排序,可以从头部或尾部向list中添加元素,一个list类型的列表最多可以存储2^32-1个元素。 在Redis中,可以对列表的两端插入和弹出,还可以获取指定范围的元素列表,获取指定索引下标的元素,可以充当栈和队列的角色。 列表有以下特点: 列表中的元素是按照插入顺序排序的 列表中的元素是可以重复的 list的底层结构 list的底层结构由quicklist(快速链表)组成,他的本质上是一个双向链表,但是他的每一个节点中存储了一个listpack(紧凑列表),我们分别来介绍: listpack listpack是一块连续的空间,作为一个数组用来紧凑的存储序列化的字符串或者数字,他的结构由三个字段组成: encoding: 表示content的编码,有字符串编码和整数编码两种 content: 表示实际存储的内容 length:表示当前节点的总长度,被放在了当前节点的最后。 我们从一个例子中来理解ListPack结构, LPUSH animals 1, dog, cat 我们往animals这个list中 push了 1,dog,cat。 那么在链表中就构建了 cat,dog,1 顺序的链表,想一想,他用了几个listpack存储了这三个元素?三个还是一个listpack? 答案是指用了1个listpack来存储这三个元素。那么这三个元素在listpack中是如何存储的呢? 我们先来看1这个元素,encoding对整数编码有3类,分别是: 7位小整数:encoding占用1字节,以0开头,剩下7位用来存储数据,因此可以存储0~127范围内的数据,同时这意味着content为空,因为数据直接存储在encoding中了 13位整数:encoding占用2字节,content依然被设置为0字节。 16/24/32/64位整数:那么就是encoding占1字节,content分别占用不同字节的空间。 那么1这个元素是7位小整数,所以他的encoding占8位,1字节,然后他的length也占用8位,也是1字节,那么这就是1元素在listpack的存储形式。 接下来我们看dog和cat这两个元素,encoding对给字符串分成了3类,分别是 短字符串:encoding占1字节,前两位是10,后六位用来表示字符串的长度(最大可表示63字节) 中字符串:encoding占2个字节,前四位是1110,后面12位记录字符串的长度(最大4095字节) 长字符串:encoding占5个字节,编码占用1字节的固定前缀,后面四个字节表示字符串的长度(最大4GB的字符串) 那么dog和cat两个元素都是短字符串,都占用3个字节。那么就是encoding占用1字节,content占用3字节,length占用1字节。 他们三个元素按照顺序,紧紧存放在一个listpack中。 那么一个listpack可以存放多少个字符串呢?他的大小由 list-max-listpack-size 来控制,默认为-2代表每个listpack占用的总内存不超过8kb quicklist 我们上面讲过,quicklist是由listpack组成的双向链表。quicklist中有四个字段需要注意: head和tail:分别指向链表的头节点和尾节点 count:所有节点的Entry总数(即所有listpack中存储的所有字符串的个数) len:节点的数量 quicklist的节点的结构是一个叫做quicklistnode的结构体,他也有几个字符需要注意: prev和next:双向链表指针,分别指向前一个和后一个节点 zl:指向listpack的指针 sz:记录这个listpack占用率多少字节的内存 count:记录这个listpack一共塞了多少个entry(元素) 那么我们已经知道里quicklist实际上就是由listpack组成的双向链表,那么数据是如何push进去的呢?我们前面讲过listpack也是可以存入多个元素的,还记得吗? 那么还按照我们上面的例子讲解:在LPUSH的时候,找到list的head节点,观察head节点中的listpack是否超过8kb(默认配置),如果没有超过,那么redis不会创建新的quicklistnode,而是给元素存入同一个listpack中,也就是我们上面讲的,cat,dog,1都在一个listpack中。 如果超了那么就要创建一个新的quicklistnode了,Redis 会把全局的 head 指向这个新节点,并把新节点的 next 指针与旧 head 节点连起来(旧节点的 prev 指向新节点)。 所以对于list的LPUSH和RPUSH也就是意味着从head还是从tail中操作数据 常用命令 LPUSH key [value...] 将一个值或者多个值按照顺序插入key的最左边 RPUSH key [value...] 将一个值或者多个值按照顺序插入key的最右边 LPOP key 移除并返回最左边的数据 RPOP key 移除并返回最右边的数据 LRANGE key start stop: 返回列表中key中指定区域内的元素 BLPOP key [key...] timeout: 从key列表中 左边弹出一个元素,如果没有就阻塞timeout秒 BRPOP key [key...] timeout: 从key列表中 右边弹出一个元素,如果没有就阻塞timeout秒 应用场景 消息队列:因为 List 是严格按照顺序存储的,可以利用 LPUSH 生产者写入, RPOP (或阻塞版本的 BRPOP )消费者读取,天然实现先进先出(FIFO)的队列模式。虽然大型分布式系统更倾向于使用 Kafka 或 RabbitMQ,但对于中小型、轻量级的异步任务,Redis List 是一种极低成本且高效的消息队列实现方案。