Redis列表List #

一、列表概述 #

1.1 什么是列表 #

Redis列表是简单的字符串列表,按照插入顺序排序:

  • 有序:元素按插入顺序排列
  • 可重复:允许重复元素
  • 双端操作:可以从两端插入和弹出
text
列表结构:

┌─────────────────────────────────────────────┐
│  LPUSH ← [元素1, 元素2, 元素3, 元素4] → RPUSH │
│                                             │
│  LPOP  ← [元素1, 元素2, 元素3, 元素4] → RPOP  │
└─────────────────────────────────────────────┘

特点:
- 最大长度:2^32 - 1(约40亿)
- 底层实现:quicklist(双向链表 + listpack)

1.2 列表编码 #

text
Redis列表的编码方式:

1. listpack(压缩列表)
   ┌─────────────────────────────────────────────┐
   │ 元素数量少时使用                            │
   │ 内存连续,效率高                            │
   │ 条件:元素数<512,单元素<64字节             │
   └─────────────────────────────────────────────┘

2. quicklist(快速列表)
   ┌─────────────────────────────────────────────┐
   │ 双向链表 + listpack节点                     │
   │ 兼顾内存和性能                              │
   │ 大列表使用                                  │
   └─────────────────────────────────────────────┘

二、基本操作 #

2.1 插入元素 #

bash
# LPUSH: 从左侧插入
LPUSH mylist "world"
# (integer) 1

LPUSH mylist "hello"
# (integer) 2

# 列表内容:["hello", "world"]

# RPUSH: 从右侧插入
RPUSH mylist "redis"
# (integer) 3

# 列表内容:["hello", "world", "redis"]

# 批量插入
LPUSH mylist "a" "b" "c"
# (integer) 6

RPUSH mylist "x" "y" "z"
# (integer) 9

# LPUSHX: 键存在时从左侧插入
LPUSHX mylist "first"
# (integer) 10

LPUSHX notexist "value"
# (integer) 0  键不存在,不插入

# RPUSHX: 键存在时从右侧插入
RPUSHX mylist "last"
# (integer) 11

2.2 弹出元素 #

bash
# LPOP: 从左侧弹出
LPOP mylist
# "c"

# RPOP: 从右侧弹出
RPOP mylist
# "z"

# 弹出多个元素(Redis 6.2+)
LPOP mylist 2
# 1) "b"
# 2) "a"

RPOP mylist 2
# 1) "y"
# 2) "x"

# 列表为空时
LPOP emptylist
# (nil)

2.3 查看列表 #

bash
# LRANGE: 获取范围内的元素
LPUSH mylist "a" "b" "c" "d" "e"

# 获取所有元素
LRANGE mylist 0 -1
# 1) "e"
# 2) "d"
# 3) "c"
# 4) "b"
# 5) "a"

# 获取前3个元素
LRANGE mylist 0 2
# 1) "e"
# 2) "d"
# 3) "c"

# 获取最后2个元素
LRANGE mylist -2 -1
# 1) "b"
# 2) "a"

# LLEN: 获取列表长度
LLEN mylist
# (integer) 5

# LINDEX: 获取指定位置元素
LINDEX mylist 0
# "e"

LINDEX mylist -1
# "a"

LINDEX mylist 10
# (nil)  索引超出范围

三、修改操作 #

3.1 设置元素 #

bash
# LSET: 设置指定位置的元素
LPUSH mylist "a" "b" "c"

LSET mylist 0 "x"
# OK

LRANGE mylist 0 -1
# 1) "x"
# 2) "b"
# 3) "a"

# 索引超出范围
LSET mylist 10 "y"
# (error) ERR index out of range

3.2 插入元素 #

bash
# LINSERT: 在指定元素前后插入
LPUSH mylist "a" "b" "c"

# 在"b"前插入
LINSERT mylist BEFORE "b" "x"
# (integer) 4

LRANGE mylist 0 -1
# 1) "c"
# 2) "x"
# 3) "b"
# 4) "a"

# 在"b"后插入
LINSERT mylist AFTER "b" "y"
# (integer) 5

LRANGE mylist 0 -1
# 1) "c"
# 2) "x"
# 3) "b"
# 4) "y"
# 5) "a"

# 元素不存在
LINSERT mylist BEFORE "notexist" "z"
# (integer) -1

3.3 删除元素 #

bash
# LREM: 删除指定元素
LPUSH mylist "a" "b" "a" "c" "a"

# 删除2个"a"(从头开始)
LREM mylist 2 "a"
# (integer) 2

LRANGE mylist 0 -1
# 1) "c"
# 2) "a"
# 3) "b"

# 删除所有"a"
LPUSH mylist "a" "a"
LREM mylist 0 "a"
# (integer) 3

# 删除1个"b"(从尾开始,负数)
LPUSH mylist "b" "b" "b"
LREM mylist -2 "b"
# (integer) 2

3.4 裁剪列表 #

bash
# LTRIM: 保留指定范围的元素
LPUSH mylist "a" "b" "c" "d" "e"

LTRIM mylist 0 2
# OK

LRANGE mylist 0 -1
# 1) "e"
# 2) "d"
# 3) "c"

# 保留最后3个元素
LPUSH mylist "f" "g"
LTRIM mylist -3 -1
# OK

LRANGE mylist 0 -1
# 1) "d"
# 2) "c"
# 3) "g"

四、阻塞操作 #

4.1 阻塞弹出 #

bash
# BLPOP: 阻塞式左侧弹出
# 语法:BLPOP key [key ...] timeout

# 列表有元素时立即返回
LPUSH mylist "a" "b"
BLPOP mylist 0
# 1) "mylist"
# 2) "b"

# 列表为空时阻塞等待
BLPOP emptylist 10
# 等待10秒,如果期间有元素插入则返回
# 1) "emptylist"
# 2) "value"

# 超时返回
BLPOP emptylist 5
# (nil)
# (5.10s)

# BRPOP: 阻塞式右侧弹出
RPUSH mylist "a" "b"
BRPOP mylist 0
# 1) "mylist"
# 2) "b"

# 同时监听多个列表
BLPOP list1 list2 list3 10
# 返回第一个有元素的列表

4.2 阻塞操作应用 #

bash
# 消息队列消费者
# 消费者1
BLPOP queue:task 0
# 阻塞等待任务

# 消费者2
BLPOP queue:task 0
# 阻塞等待任务

# 生产者
LPUSH queue:task "task_data"
# 消费者1收到任务

五、列表间操作 #

5.1 元素移动 #

bash
# RPOPLPUSH: 从一个列表右侧弹出,推入另一个列表左侧
LPUSH list1 "a" "b" "c"
RPOPLPUSH list1 list2
# "a"

LRANGE list1 0 -1
# 1) "c"
# 2) "b"

LRANGE list2 0 -1
# 1) "a"

# BRPOPLPUSH: 阻塞式移动
BRPOPLPUSH list1 list2 10
# 从list1右侧弹出,推入list2左侧
# 如果list1为空,阻塞等待

5.2 循环队列 #

bash
# 使用RPOPLPUSH实现循环队列
# 处理元素后放回队列尾部

# 获取任务
RPOPLPUSH queue:task queue:processing

# 处理任务...

# 成功:从processing删除
LREM queue:processing 1 "task_data"

# 失败:放回队列
RPOPLPUSH queue:processing queue:task

六、应用场景 #

6.1 消息队列 #

bash
# 简单队列
# 生产者
LPUSH queue:email "email_data_1"
LPUSH queue:email "email_data_2"

# 消费者
RPOP queue:email
# "email_data_1"

# 可靠队列(使用备份队列)
RPOPLPUSH queue:email queue:email:processing
# 处理完成后删除
LREM queue:email:processing 1 "email_data_1"

6.2 最新列表 #

bash
# 最新文章列表
LPUSH articles:latest "article:1001"
LPUSH articles:latest "article:1002"
LPUSH articles:latest "article:1003"

# 只保留最新10篇
LTRIM articles:latest 0 9

# 获取最新5篇
LRANGE articles:latest 0 4
# 1) "article:1003"
# 2) "article:1002"
# 3) "article:1001"

6.3 时间线 #

bash
# 用户时间线
LPUSH timeline:user:1001 "post:2001"
LPUSH timeline:user:1001 "post:2002"
LPUSH timeline:user:1001 "post:2003"

# 获取时间线
LRANGE timeline:user:1001 0 9

6.4 分页 #

bash
# 分页获取列表
# 每页10条,第1页
LRANGE mylist 0 9

# 第2页
LRANGE mylist 10 19

# 第N页
# start = (page - 1) * pageSize
# end = page * pageSize - 1

七、性能优化 #

7.1 避免大列表 #

bash
# 不推荐:无限增长的列表
LPUSH huge:list "item"

# 推荐:限制列表长度
LPUSH limited:list "item"
LTRIM limited:list 0 999  # 只保留1000个

7.2 批量操作 #

bash
# 不推荐:多次单操作
LPUSH mylist "a"
LPUSH mylist "b"
LPUSH mylist "c"

# 推荐:批量操作
LPUSH mylist "a" "b" "c"

7.3 使用阻塞操作 #

bash
# 不推荐:轮询
while true; do
    result=$(RPOP queue)
    if [ -n "$result" ]; then
        process "$result"
    fi
    sleep 1
done

# 推荐:阻塞弹出
while true; do
    result=$(BRPOP queue 0)
    process "$result"
done

八、总结 #

列表操作命令:

命令 说明
LPUSH 左侧插入
RPUSH 右侧插入
LPOP 左侧弹出
RPOP 右侧弹出
LRANGE 获取范围
LLEN 获取长度
LINDEX 获取指定位置
LSET 设置指定位置
LREM 删除元素
LTRIM 裁剪列表

阻塞命令:

命令 说明
BLPOP 阻塞左侧弹出
BRPOP 阻塞右侧弹出
BRPOPLPUSH 阻塞移动

应用场景:

场景 实现方式
消息队列 LPUSH + BRPOP
最新列表 LPUSH + LTRIM
时间线 LPUSH + LRANGE
分页 LRANGE

下一步,让我们学习Redis集合Set!

最后更新:2026-03-27