前言
Redis 中的 List 是一个有序的字符串列表,按照插入顺序排序,可以在列表的头部(左侧)或尾部(右侧)插入元素。一个 List 最多可以存储 2^32 - 1 个元素(约 42 亿),非常适合用来实现队列、栈、最新消息列表等结构。
底层实现
在 Redis 3.2 之前,List 的底层编码是 ziplist(压缩列表)和 linkedlist(双向链表)二选一:
- 元素数量少且单个元素较短时使用
ziplist,节省内存 - 否则转换为
linkedlist
Redis 3.2 之后统一使用 quicklist(快速列表),它是一个由 ziplist 组成的双向链表,兼顾了内存效率和读写性能。可以通过 list-max-listpack-size 配置每个节点的长度。
常用命令
插入与弹出
# 从左侧插入
LPUSH key value1 value2
# 从右侧插入
RPUSH key value1 value2
# 从左侧弹出
LPOP key
# 从右侧弹出
RPOP key
# 阻塞式弹出,列表为空时等待指定秒数
BLPOP key 10
BRPOP key 10
查看与获取
# 查看指定范围的元素,0 -1 表示全部
LRANGE key 0 -1
# 获取列表长度
LLEN key
# 获取指定下标的元素
LINDEX key 0
其他操作
# 保留指定范围的元素,其余删除
LTRIM key 0 99
# 从列表 source 的右侧弹出一个元素,插入到列表 destination 的左侧
RPOPLPUSH source destination
# 阻塞版本的 RPOPLPUSH
BRPOPLPUSH source destination 10
# 在指定元素前后插入新元素
LINSERT key BEFORE pivot value
LINSERT key AFTER pivot value
# 删除指定数量的等于 value 的元素
LREM key count value
# 修改指定下标的元素
LSET key 0 newValue
使用场景
1. 消息队列
利用 LPUSH + BRPOP 的组合,可以实现一个简单的消息队列:生产者从左侧写入消息,消费者从右侧阻塞式读取。
# 生产者
LPUSH queue "task1"
# 消费者,列表为空时最多阻塞 30 秒
BRPOP queue 30
如果需要保证消息不丢,可以用 BRPOPLPUSH,消费者取出消息的同时备份到另一个列表,处理完成后再删除备份。
2. 最新消息列表
比如朋友圈动态、最新公告等,只需要展示最新的 N 条数据:
# 插入新动态
LPUSH user:1:timeline "post1001"
# 只保留最新 100 条
LTRIM user:1:timeline 0 99
# 读取最新 20 条
LRANGE user:1:timeline 0 19
3. 栈与队列
LPUSH+LPOP:先进后出,实现栈LPUSH+RPOP:先进先出,实现队列LPUSH+BRPOP:带阻塞能力的队列
4. 抽奖与轮询
用 LRANGE 随机范围配合业务逻辑可以做简单抽奖;用 RPOPLPUSH 可以实现任务轮询,把处理完的任务转回另一个列表形成循环。
注意事项
- List 的
LRANGE在数据量大时是 O(N) 操作,避免在长列表上频繁大范围读取 LSET只能修改已存在的下标,越界会报错- 消息队列场景下,Redis 没有原生 ACK 机制,可靠性要求高的业务建议使用专业的消息中间件
- 使用
BLPOP、BRPOP这类阻塞命令时要注意连接超时和连接池配置
小结
List 是 Redis 中最常用的数据类型之一,底层 quicklist 兼顾性能与内存。掌握它之后,消息队列、最新列表、任务轮询等场景都能用非常简单的命令搞定。下一篇可以继续聊聊 Set 与 ZSet。