Redis命令-List命令

一、前言:List 不只是"列表",更是高性能工具

Redis 的 List(列表) 是一个双向链表 结构,支持从两端高效插入和弹出 (O(1) 时间复杂度)。

它不仅是简单的数据容器,更是构建以下系统的基石:

  • 轻量级消息队列
  • 用户最新动态/评论流
  • 任务调度缓冲池
  • 限流滑动窗口

本文将系统讲解 Redis List 的核心命令 ,并深入实战应用场景与性能陷阱


二、List 核心命令速查表

命令 作用 时间复杂度
LPUSH key value [value ...] 左端插入一个或多个元素 O(1) 每个元素
RPUSH key value [value ...] 右端插入一个或多个元素 O(1) 每个元素
LPOP key [count] 左端弹出一个或多个元素 O(N),N=弹出数量
RPOP key [count] 右端弹出一个或多个元素 O(N)
BLPOP key [key ...] timeout 阻塞式左弹出(超时返回 nil) O(1)
BRPOP key [key ...] timeout 阻塞式右弹出 O(1)
LRANGE key start stop 获取指定范围元素(支持负数索引) O(S+N),S=起始偏移,N=返回元素数
LLEN key 获取列表长度 O(1)
LINDEX key index 获取指定索引的元素 O(N),N=索引位置
LSET key index value 设置指定索引的值 O(N)
`LINSERT key BEFORE AFTER pivot value` 在指定元素前后插入新元素
LTRIM key start stop 修剪列表,只保留指定范围 O(N),N=被删除元素数

💡 关键特性

  • 左 = 头(head),右 = 尾(tail)
  • 支持阻塞操作(Bxxx),天然适配生产者-消费者模型

三、常用命令详解与示例

3.1 插入元素:LPUSH / RPUSH

bash 复制代码
# 从左侧插入(新元素在前)
127.0.0.1:6379> LPUSH news "头条新闻" "科技快讯" "体育速递"
(integer) 3

# 查看列表(从左到右)
127.0.0.1:6379> LRANGE news 0 -1
1) "体育速递"
2) "科技快讯"
3) "头条新闻"

# 从右侧插入(新元素在后)
127.0.0.1:6379> RPUSH news "财经要闻"
127.0.0.1:6379> LRANGE news 0 -1
1) "体育速递"
2) "科技快讯"
3) "头条新闻"
4) "财经要闻"

典型模式

  • LPUSH + LTRIM → 实现最新 N 条记录
  • LPUSH + RPOP → 实现栈(LIFO)
  • LPUSH + LPOP → 实现队列(FIFO)

3.2 弹出元素:LPOP / RPOP / BLPOP

bash 复制代码
# 非阻塞弹出(无数据返回 nil)
127.0.0.1:6379> LPOP news
"体育速递"

# 阻塞弹出(等待最多 5 秒)
127.0.0.1:6379> BLPOP task_queue 5
(nil)  # 5 秒内无数据,返回 nil

# 多队列监听(优先级队列)
127.0.0.1:6379> BLPOP high_priority_queue low_priority_queue 0
# 只要任一队列有数据,立即返回

⚠️ 注意BLPOP/BRPOP 在 Redis 中是原子操作,适合做可靠队列。


3.3 范围查询:LRANGE

bash 复制代码
# 获取前 10 条(最新动态)
127.0.0.1:6379> LRANGE user:1001:timeline 0 9

# 获取最后 5 条(倒序)
127.0.0.1:6379> LRANGE user:1001:timeline -5 -1

# 获取全部(慎用!大数据量会阻塞)
127.0.0.1:6379> LRANGE big_list 0 -1

🔍 性能提示

  • LRANGE 的时间复杂度与返回元素数量成正比
  • 避免对大列表执行 LRANGE 0 -1

3.4 修剪列表:LTRIM(实现"最新 N 条")

bash 复制代码
# 推送新动态,并只保留最近 100 条
127.0.0.1:6379> LPUSH user:1001:timeline "发布了新文章"
127.0.0.1:6379> LTRIM user:1001:timeline 0 99

这是实现"朋友圈最新 100 条"的标准做法!


四、List 的内部编码

Redis 对小 List 使用 ziplist(压缩列表) 编码,节省内存:

复制代码
# redis.conf 默认配置
list-max-ziplist-size -2   # -2 表示每个节点不超过 8KB
list-compress-depth 0      # 不压缩(可设为 1~3 启用 LZF 压缩)

当元素数量或大小超过阈值,自动转为 linkedlist(快速链表)

💡 建议

  • 短列表(如消息队列、时间线)性能极佳
  • 避免存储超大 List(如 > 10 万元素)

五、实战应用场景

场景 1:轻量级消息队列(生产者-消费者)

python 复制代码
# 生产者(Python)
import redis
r = redis.Redis()
r.lpush("task_queue", '{"action": "send_email", "to": "user@example.com"}')

# 消费者(阻塞等待)
while True:
    task = r.brpop("task_queue", timeout=5)
    if task:
        process(json.loads(task[1]))

优势 :简单、可靠、支持多消费者

局限:不支持 ACK、重试、延迟消息(需用 Stream 或专业 MQ)


场景 2:用户最新动态(Timeline)

java 复制代码
// Java (Lettuce)
String userId = "1001";
String timelineKey = "user:" + userId + ":timeline";

// 发布新动态
redis.lpush(timelineKey, "用户发布了新照片");
redis.ltrim(timelineKey, 0, 99); // 只保留 100 条

// 获取最新 10 条
List<String> latest = redis.lrange(timelineKey, 0, 9);

📌 注意 :此方案适合单用户时间线,不适合全局热门 feed(需用排序集合 ZSet)


场景 3:滑动窗口限流

bash 复制代码
# 每秒最多 5 次请求
EVAL "
  local now = tonumber(ARGV[1])
  local window = now - 1000  -- 1秒窗口
  redis.call('LPUSH', KEYS[1], now)
  redis.call('LTRIM', KEYS[1], 0, 4)  -- 只保留5个时间戳
  local count = redis.call('LLEN', KEYS[1])
  local oldest = redis.call('LINDEX', KEYS[1], -1)
  if oldest and tonumber(oldest) < window then
    return {count, 'expired'}
  else
    return {count, 'allowed'}
  end
" 1 user:1001:rate_limit 1700000000000

六、常见误区与最佳实践

❌ 误区 1:用 List 存储超大集合

  • 问题LRANGE 0 -1 阻塞主线程
  • 建议 :大集合改用 SetSorted Set

❌ 误区 2:频繁使用 LINDEX / LSET

  • 问题:O(N) 复杂度,性能差
  • 建议 :如需随机访问,考虑用 HashString 分片

✅ 最佳实践

  1. 队列命名规范 :如 queue:order:pending
  2. 设置 TTL :防止死队列堆积(EXPIRE queue 86400
  3. 监控长度 :通过 LLEN + 告警防止内存爆炸
  4. 避免大 Value:单个元素建议 < 1KB

七、List vs 其他类型选型建议

需求 推荐类型
FIFO 队列 List(LPUSH + RPOP)
最新 N 条记录 List(LPUSH + LTRIM)
唯一性集合 Set
排序/排行榜 Sorted Set
对象存储 Hash
高可靠消息队列 Stream(Redis 5.0+)

📌 List 适合简单、高性能、顺序敏感的场景


八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
咖啡の猫2 小时前
SpringDataRedis快速入门
redis
我是大猴子2 小时前
解决并发的两种方法(没用到redis)(对上一期的补充)以及开启多个定时任务
数据库·redis·缓存
難釋懷2 小时前
Redis分片集群散列插槽
数据库·redis·缓存
无限进步_2 小时前
深入解析vector:一个完整的C++动态数组实现
c语言·开发语言·c++·windows·git·github·visual studio
zhangx1234_2 小时前
java list介绍
java·开发语言·list
小涛不学习3 小时前
Java List 集合深度解析(ArrayList / LinkedList 原理详解)
java·开发语言·windows
每天被梦想叫醒的程序员3 小时前
Windows 11 系统部署 OpenClaw 完整指南:从零到一的 AI 助手搭建
人工智能·windows
重庆兔巴哥3 小时前
如何使用Dev-C++的Windows API进行GUI开发?
开发语言·c++·windows
咖啡の猫3 小时前
Redis命令-Set命令
数据库·chrome·redis