Redis里怎么搞红包回收,保证不漏也不卡顿的那些事儿
- 问答
- 2026-01-19 04:04:08
- 2
主要参考了微信公众号“捉虫大师”的文章《用Redis搞定抢红包业务,含代码》,并结合了常见的分布式系统设计思路)
要聊清楚在Redis里怎么搞红包回收,保证既不漏掉该回收的红包,又不影响系统性能,咱们得先从一个完整的抢红包流程说起,这事儿就像组织一场线上抢红包活动,光是把红包发出去还不行,还得处理那些没人抢的红包,最后要“算总账”。
第一步:发红包时,就把“回收”这事儿惦记上
当有人发一个红包时,比如总金额100元,分成10个包,系统在Redis里会做这么几件关键事:
- 创建一个红包列表(List): 这个列表里预先装好10个随机分配好的金额。
[11.1, 9.9, 8.8, ...],抢红包的本质就是从列表左边(LPOP)弹出一个金额。 - 记录红包关键信息(Hash): 用一个Hash结构存这个红包的元数据,比如总金额(total_amount)、总个数(total_count)、发红包的用户ID(owner_id)等等。
- 最重要的一步:把这个红包的ID塞进一个“待回收检查队列”(ZSET/Sorted Set)。 这是实现红包回收不丢的关键,为这个红包设置一个过期时间(TTL),比如24小时。
这里的关键点是,在红包诞生的一刻,就给它定好了“生命周期”和“监控标签”,那个ZSET队列的分数(score)就设置为这个红包的过期时间戳,这样一来,所有发了但还没处理完的红包,都乖乖地在这个有序队列里排着队,按照过期时间早晚排序。
第二步:抢红包时,保证原子性和准确性
当用户抢红包时,核心操作是从第一步创建的那个红包列表里弹出一个金额,在Redis里,必须用Lua脚本来保证这个操作的原子性,一个简单的Lua脚本会做这几件事:
- 检查红包列表是否还有剩余(LLEN)。
- 如果有,就弹出一个金额(LPOP)。
- 在另一个Hash结构里记录谁抢到了多少钱(HSET),比如一个叫“红包ID:detail”的Hash,字段是用户ID,值是金额。
用Lua脚本能确保“检查”和“弹出”这两个动作是一气呵成的,不会因为网络或并发导致超发(比如列表里只剩一个包,但两个请求同时检查都认为还有,就会出问题),这一步虽然不直接处理回收,但保证了抢红包过程本身不乱,是后续顺利回收的基础。
第三步:核心环节——红包回收,如何做到“不漏”和“不卡”
24小时到了,红包过期了,但可能还有几个没抢完,这时候就需要一个后台任务,我们姑且叫它“红包回收员”,来清理现场,这个回收员的工作逻辑是保证不漏不卡的关键。
怎么保证“不漏”?
“回收员”会定时(比如每秒)去扫描第二步提到的那个“待回收检查队列”(ZSET),它不会漫无目的地找,而是:
- 查询当前时间戳。
- 用
ZRANGEBYSCORE命令,把所有分数(即过期时间)小于当前时间戳的红包ID捞出来,这些就是已经过期的、需要处理的红包。
因为所有红包在发出时都被注册到了这个队列,所以只要这个队列本身不丢(Redis很可靠),就不会有“漏网之鱼”,这个方法不依赖于Redis的Key过期事件通知(这个机制可能不可靠或有延迟),而是主动扫描,可靠性非常高。
怎么保证“不卡顿”?
如果一下子有成百上千个红包同时过期,“回收员”如果一次性处理所有,可能会忙不过来,导致系统卡顿,这里有几个技巧:
- 分批处理: 每次从ZSET里只取出一定数量的红包ID(比如100个)进行处理,处理完一批再取下一批,避免单次操作数据量过大。
- 异步处理: “回收员”从ZSET里拿到过期红包ID列表后,不要自己亲自去干所有脏活累活,它可以把这些ID塞进另一个消息队列(比如Redis的另一个List),然后立刻返回,继续扫描下一批,由多个后台工作进程(Worker)来消费这个消息队列,真正执行退款、更新数据库等操作,这样就把“发现过期任务”和“执行回收任务”解耦了,“回收员”本身非常轻量,不会阻塞。
- 谨慎使用DEL命令: 在真正回收时,处理一个红包的步骤应该是:
- 使用Lua脚本,再次检查红包列表是否真的还有剩余(因为可能在扫描到和处理前的一瞬间被人抢走了最后一个)。
- 如果确实有剩余,再将剩余金额汇总。
- 然后删除Redis中这个红包相关的Key(列表、Hash等)。
- 最后,再把处理结果(比如退还给发红包用户的金额)异步写入数据库。
这个“先检查,再操作”的步骤,也是通过Lua脚本保证原子性,防止重复退款。
总结一下精髓:
- 不漏的秘诀: 是 “主动登记,主动扫描”,发红包时就在一个有序集合里“挂号”,后台任务定时根据过期时间这个“病历”主动来找需要“出院”的红包,而不是被动等待通知。
- 不卡的秘诀: 是 “化整为零,异步处理”,把可能集中的大批量处理拆成小批量,把关键的通知步骤和耗时的业务逻辑步骤分开,用消息队列缓冲,让专业的人(Worker进程)干专业的事。
这样一来,整个红包系统就像一个有条不紊的流水线:发红包时打好标签,抢红包时原子操作,过期后由高效的“回收员”和“工人”协同清理,既不会丢三落四,也不会因为活太多而堵死。

本文由太叔访天于2026-01-19发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/83442.html
