📋 Redis 列表(List)

Redis 中的有序集合,支持双端操作

列表类型概述

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可存储 2^32 - 1 个元素。

列表结构示意图

元素1
元素2
元素3
元素4

左端(头部) ← 列表 → 右端(尾部)

📝 基本操作命令

列表类型的基础插入和删除操作:

命令 描述 示例
LPUSH key element [element ...] 从左端(头部)插入元素 LPUSH mylist "world" "hello"
RPUSH key element [element ...] 从右端(尾部)插入元素 RPUSH mylist "redis"
LPOP key 从左端(头部)弹出元素 LPOP mylist
RPOP key 从右端(尾部)弹出元素 RPOP mylist
LLEN key 获取列表长度 LLEN mylist
LINDEX key index 获取指定索引的元素 LINDEX mylist 0
LSET key index element 设置指定索引的元素值 LSET mylist 0 "new_value"

基本操作示例:

# 创建列表并添加元素
LPUSH tasks "task3" "task2" "task1"  # 从左端插入
RPUSH tasks "task4" "task5"          # 从右端插入
# 列表内容:["task1", "task2", "task3", "task4", "task5"]

# 获取列表信息
LLEN tasks                           # 返回: 5
LINDEX tasks 0                       # 返回: "task1" (第一个元素)
LINDEX tasks -1                      # 返回: "task5" (最后一个元素)

# 弹出元素
LPOP tasks                           # 返回: "task1"
RPOP tasks                           # 返回: "task5"
# 列表内容:["task2", "task3", "task4"]

# 修改元素
LSET tasks 0 "updated_task2"         # 修改第一个元素
LINDEX tasks 0                       # 返回: "updated_task2"

🔍 范围操作命令

获取和操作列表中的元素范围:

命令 描述 示例
LRANGE key start stop 获取指定范围的元素 LRANGE mylist 0 2
LTRIM key start stop 保留指定范围的元素 LTRIM mylist 0 99
LINSERT key BEFORE|AFTER pivot element 在指定元素前/后插入 LINSERT mylist BEFORE "world" "beautiful"
LREM key count element 删除指定数量的元素 LREM mylist 2 "hello"

范围操作示例:

# 创建测试列表
RPUSH numbers 1 2 3 4 5 6 7 8 9 10

# 获取范围元素
LRANGE numbers 0 4                   # 返回: ["1", "2", "3", "4", "5"]
LRANGE numbers -3 -1                 # 返回: ["8", "9", "10"] (最后3个)
LRANGE numbers 0 -1                  # 返回: 所有元素

# 保留指定范围
LTRIM numbers 0 4                    # 只保留前5个元素
LRANGE numbers 0 -1                  # 返回: ["1", "2", "3", "4", "5"]

# 插入元素
LINSERT numbers AFTER "3" "3.5"      # 在"3"后插入"3.5"
LRANGE numbers 0 -1                  # 返回: ["1", "2", "3", "3.5", "4", "5"]

# 删除元素
RPUSH duplicates "a" "b" "a" "c" "a"
LREM duplicates 2 "a"                # 删除2个"a"
LRANGE duplicates 0 -1               # 返回: ["b", "c", "a"]

⏰ 阻塞操作命令

当列表为空时,阻塞等待新元素的命令:

命令 描述 示例
BLPOP key [key ...] timeout 阻塞式左端弹出 BLPOP queue1 queue2 30
BRPOP key [key ...] timeout 阻塞式右端弹出 BRPOP queue1 30
BRPOPLPUSH source destination timeout 阻塞式弹出并推入另一个列表 BRPOPLPUSH queue1 queue2 30

阻塞操作示例:

# 消费者等待任务(阻塞30秒)
BLPOP task_queue 30
# 如果task_queue为空,将阻塞等待30秒
# 如果有新任务被推入,立即返回

# 生产者添加任务(在另一个连接中)
LPUSH task_queue "new_task"
# 此时阻塞的BLPOP会立即返回 ["task_queue", "new_task"]

# 多队列监听
BLPOP high_priority_queue normal_queue low_priority_queue 0
# 按优先级顺序检查队列,0表示永久阻塞

# 原子性转移
BRPOPLPUSH processing_queue completed_queue 30
# 从processing_queue右端弹出,推入completed_queue左端

🔄 列表间操作

在不同列表之间移动元素:

命令 描述 示例
RPOPLPUSH source destination 从源列表右端弹出,推入目标列表左端 RPOPLPUSH list1 list2

列表间操作示例:

# 任务处理流程
RPUSH todo "task1" "task2" "task3"
RPUSH doing
RPUSH done

# 开始处理任务
RPOPLPUSH todo doing                 # 将任务从todo移到doing
LRANGE doing 0 -1                    # 返回: ["task3"]

# 完成任务
RPOPLPUSH doing done                 # 将任务从doing移到done
LRANGE done 0 -1                     # 返回: ["task3"]

# 查看各阶段任务
LRANGE todo 0 -1                     # 返回: ["task1", "task2"]
LRANGE doing 0 -1                    # 返回: []
LRANGE done 0 -1                     # 返回: ["task3"]

实际应用场景

📨 消息队列

使用列表实现简单的消息队列系统:

# 生产者发送消息
LPUSH message_queue "{\"id\": 1, \"type\": \"email\", \"to\": \"user@example.com\"}"
LPUSH message_queue "{\"id\": 2, \"type\": \"sms\", \"to\": \"13800138000\"}"

# 消费者处理消息
BRPOP message_queue 30               # 阻塞等待消息

# 可靠队列(处理中队列)
BRPOPLPUSH message_queue processing_queue 30
# 处理完成后
LREM processing_queue 1 "processed_message"

# 失败重试
RPOPLPUSH processing_queue retry_queue

📰 最新动态

存储用户的最新动态或文章列表:

# 发布新动态
LPUSH user:1001:timeline "{\"id\": 101, \"content\": \"今天天气不错\", \"time\": 1609459200}"
LPUSH user:1001:timeline "{\"id\": 102, \"content\": \"学习Redis\", \"time\": 1609462800}"

# 获取最新10条动态
LRANGE user:1001:timeline 0 9

# 限制动态数量(只保留最新100条)
LTRIM user:1001:timeline 0 99

# 获取特定动态
LINDEX user:1001:timeline 0         # 最新动态
LINDEX user:1001:timeline -1        # 最早动态

📊 排行榜

实现简单的排行榜功能:

# 添加分数记录
LPUSH game:leaderboard "player1:1000"
LPUSH game:leaderboard "player2:1200"
LPUSH game:leaderboard "player3:800"

# 获取排行榜
LRANGE game:leaderboard 0 9          # 前10名

# 更新分数(需要先删除旧记录)
LREM game:leaderboard 1 "player1:1000"
LPUSH game:leaderboard "player1:1500"

# 注意:对于复杂排行榜,建议使用Sorted Set

🔄 任务调度

实现任务调度和处理流程:

# 任务提交
LPUSH task:pending "{\"id\": 1, \"type\": \"image_process\", \"file\": \"image1.jpg\"}"
LPUSH task:pending "{\"id\": 2, \"type\": \"video_encode\", \"file\": \"video1.mp4\"}"

# 工作进程获取任务
BRPOPLPUSH task:pending task:processing 30

# 任务完成
RPOPLPUSH task:processing task:completed

# 任务失败
RPOPLPUSH task:processing task:failed

# 重试失败任务
RPOPLPUSH task:failed task:pending

# 监控队列状态
LLEN task:pending                    # 待处理任务数
LLEN task:processing                 # 处理中任务数
LLEN task:completed                  # 已完成任务数
LLEN task:failed                     # 失败任务数

性能优化建议

列表 vs 其他数据类型

数据类型选择建议:

  • List vs Set:List允许重复元素且有序,Set不允许重复且无序
  • List vs Sorted Set:List按插入顺序排序,Sorted Set按分数排序
  • List vs Stream:Stream更适合复杂的消息队列场景
  • 使用List的场景:消息队列、最新动态、简单排行榜、任务调度