Redis List 实现消息队列的核心是 LPUSH + BRPOP 组合:生产者用 LPUSH 从左侧入队,消费者用 BRPOP 从右侧阻塞出队,实现 FIFO、原子性及零轮询;但无 ACK 机制,消息可靠性需靠 BRPOPLPUSH + Pending 队列 + 幂等设计来增强。

用 Redis 的 List 实现简单消息队列,核心就是利用它双向链表的特性 + 原子性命令,让生产者和消费者各走一端,配合阻塞操作避免轮询。不需要额外组件,几条命令就能跑起来。
基础命令搭配:LPUSH + BRPOP
这是最常用、语义最清晰的一组组合:
-
生产者用
LPUSH queue_name message—— 把消息插到列表头部,保证先进入的排在前面; -
消费者用
BRPOP queue_name 0—— 从尾部阻塞读取,拿到的是最早入队的消息(FIFO); - 如果队列为空,
BRPOP会挂起连接,直到新消息到达,不消耗 CPU; - 命令天然原子,多个消费者同时
BRPOP同一个 key,Redis 会确保每条消息只被一个客户端取走。
为什么不用 RPUSH + LPOP?
理论上也可以,但实际中 LPUSH + BRPOP 更推荐:
- 语义更直观:生产“推头”,消费“取尾”,符合“先进先出”的直觉;
- 性能无差异 —— Redis List 两端插入/弹出都是 O(1);
- 部分客户端库(比如 Jedis、Lettuce)对
BRPOP的封装更成熟,异常处理更统一。
加个长度检查和清空机制
日常运维和调试离不开这两个辅助操作:
- 查当前积压量:
LLEN queue_name,返回整数,方便监控告警; - 清空测试队列:
DEL queue_name(比逐条LPOP快得多); - 临时查看几条待处理消息:
LRANGE queue_name 0 -1或LRANGE queue_name 0 9(只取前 10 条)。
注意几个现实坑点
简单不等于鲁棒,上线前得心里有数:
-
消息丢了怎么办?
BRPOP取出即删,消费者崩溃就丢。若需可靠性,得升级为BRPOPLPUSH+ 处理中队列 + ACK 逻辑; -
Redis 挂了消息还在吗? 取决于持久化配置 —— AOF 开启且
appendfsync always才能几乎不丢,但写性能下降; - 消息重复怎么防? List 本身不提供幂等,得靠业务层加唯一 ID + 已处理记录(比如用 Set 记已消费 msg_id);
-
别用非阻塞命令轮询,比如循环
RPOP+ sleep,既浪费连接又可能漏消息或打满 CPU。


















