用Redis做阻塞队列其实挺有意思,聊聊它的实现细节和那些坑
- 问答
- 2026-01-09 07:33:06
- 3
用Redis做阻塞队列,这个想法确实挺有意思的,它不像Kafka、RabbitMQ那样是专门的消息队列,但凭借其简单、高性能和丰富的数据结构,在很多场景下成为轻量级消息队列的首选,它的核心实现主要依赖两个命令:BLPOP 和 BRPOP。
它是怎么工作的?简单说就是“等”和“抢”
想象一下,你有一个列表(List),比如叫 my_task_queue,生产者用 LPUSH 命令把任务从左边推进去,就像往管子的一端塞入弹珠。
关键在消费者这边,普通的做法是消费者不停地用 RPOP 去管子的另一端掏,看看有没有弹珠(任务),但如果管子里是空的,消费者就会不停地“空掏”,这叫忙等待,非常浪费CPU资源。
而阻塞队列的精髓就在于 BLPOP 这个命令,消费者不再傻傻地空掏,而是执行 BLPOP my_task_queue 30,这个命令的意思是:“我去 my_task_queue 这个管子的右边等着,如果有弹珠出来,我立马拿走,如果等了30秒还没弹珠,我就超时返回,不跟你这儿干耗着了。”
这个过程就像是多个消费者在排队“等活儿”,当生产者 LPUSH 一个任务进去的瞬间,所有正在用 BLPOP 命令等待这个队列的消费者中,只有一个会“抢”到这个任务,其他人继续等待,这就天然实现了简单的负载均衡,保证一个任务只被一个消费者处理。
实现细节里藏着哪些“魔鬼”?
虽然原理简单,但真想在生产环境用起来,有几个细节必须处理好,不然都是坑。
-
连接超时问题:
BLPOP可以设置超时时间,比如30秒,但这里有个隐患,Redis服务器默认有timeout配置(比如300秒),如果消费者客户端在等待期间,与Redis的网络连接超过了服务器设置的timeout时间,且中间没有其他通信,Redis服务器可能会主动断开这个“空闲”的连接,结果就是,消费者客户端还傻傻地等着,其实连接早就断了,根本等不到任务,通常需要将客户端的超时时间设置得比Redis服务器的timeout时间更短,或者确保在等待期间有心跳保活机制。 -
空队列与Null值:
BLPOP可以同时监听多个队列,BLPOP queue1 queue2 0,它会按顺序检查这些队列,哪个有元素就弹出哪个,但如果某个客户端往队列里推了一个空值(比如NULL),BLPOP也会把它当做一个有效元素弹出,消费者程序必须能处理这种空消息或无效消息,做好健壮性判断。 -
消息确认与丢失风险:这是最大的一个坑,用基本的
BLPOP/LPUSH实现的队列,是典型的“最多一次”投递,消费者一旦用BLPOP从队列中取走任务,这个任务就在Redis里消失了,如果消费者在处理这个任务的过程中程序崩溃了,这个任务就永远丢失了,没有重试的机会。
如何填坑?更高级的玩法
针对消息丢失这个核心痛点,社区有更成熟的方案,比如使用 Redis 的 可靠队列(Reliable Queue) 模式,这个模式参考了 Disque 项目(一个由Redis作者开发的消息队列)的思路。
它需要两个队列:
- 主任务队列:存放待处理的任务。
- 处理中队列:存放已被取出但尚未完成的任务。
工作流程变成了:
- 消费者不再用
BLPOP直接从主队列取任务,而是用一个 Lua 脚本原子性地执行两个操作:用RPOPLPUSH命令,将任务从主队列移动到处理中队列。 - 消费者开始处理任务。
- 处理成功后,消费者再显式地用
LREM命令从处理中队列里移除这个任务。
这样做的好处是:如果消费者在处理过程中崩溃,这个任务会一直留在“处理中队列”里,你可以启动一个监控进程,定期扫描“处理中队列”,将滞留时间过长的任务重新放回“主任务队列”,让其他消费者重试,从而实现了“至少一次”投递,大大提高了可靠性。
总结一下
用Redis做阻塞队列,上手极其简单,对于丢几条消息也无所谓的场景(比如统计在线人数、发送非关键的通知)是非常高效的选择,它的趣味性就在于用简单的数据结构(List)和命令(BLPOP)组合出了实用的并发控制能力。
但它的“坑”也源于它的“简单”,当你需要消息持久化、可靠投递、严格的消息顺序、队列监控等高级功能时,原生的List就显得力不从心了,这时,你可能需要引入更复杂的模式(如可靠队列),或者直接考虑使用专业的消息中间件。
技术选型没有银弹,理解Redis阻塞队列的实现细节和局限性,才能在你需要一把“瑞士军刀”的时候,把它用在最合适的场景里。
(引用来源:本文内容基于Redis官方文档关于List和BLPOP/BRPOP命令的说明,以及Redis之父Salvatore Sanfilippo设计的Disque项目理念和社区中常见的可靠队列模式实践。)

本文由钊智敏于2026-01-09发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/77308.html
