news 2026/6/1 13:54:40

高并发场景下的“抢红包”算法设计:如何保证红包金额随机且不超发?(二倍均值法)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高并发场景下的“抢红包”算法设计:如何保证红包金额随机且不超发?(二倍均值法)

🧧 前言:为什么“抢红包”这么难?

你以为抢红包只是Random()一下吗?
如果是 100 块钱发给 10 个人:

  • 第一个人Random(0, 100),随到了 99 元。
  • 剩下 9 个人分 1 块钱?这游戏还能玩?

核心难点在于:

  1. 随机性:每个人抢到的金额要随机,但要符合正态分布(大部分人手气差不多,少数人运气爆棚)。
  2. 公平性:越早抢和越晚抢,获取金额的“数学期望”必须相等。
  3. 高并发:春节除夕夜,几亿人同时点,数据库直接炸裂。
  4. 不超发:绝对不能出现 100 块钱分出了 101 块的情况(资损)。

今天,我们重点讲业界最通用的算法——二倍均值法,以及如何用Redis Lua脚本落地。


🧮 核心算法:二倍均值法 (Double Mean Method)

如果让你设计,你可能想过“预先生成好 10 个随机数放到数组里”。这没问题,但如果红包金额很大、人数很多,存储成本较高。

二倍均值法是一种实时计算算法。

1. 算法公式

假设剩余金额为M,剩余人数为N
每次抢到的金额X=Random(0.01, (M / N) * 2)

2. 原理推导

假设 100 元发给 10 人。

  • 第 1 人

  • 均值 = 100 / 10 = 10 元。

  • 范围 = [0.01, 20]。

  • 假设抢到5 元

  • 第 2 人

  • 剩余金额 95 元,剩余 9 人。

  • 均值 = 95 / 9 ≈ 10.55 元。

  • 范围 = [0.01, 21.1]。

  • 假设抢到15 元

  • 最后 1 人:直接拿走剩余所有金额。

数学证明:
每次抢夺的期望值始终等于剩余人均金额。这保证了无论你第几个来,理论上抢到的钱平均值是一样的。


💻 代码实现 (Java 版)

算法逻辑本身很简单,注意处理最小单位(1分钱)

publicclassRedPacketUtil{/** * 二倍均值法计算红包 * @param restMoney 剩余金额 (单位:分) * @param restPeople 剩余人数 * @return 本次抢到的金额 */publicstaticintsplitRedPacket(intrestMoney,intrestPeople){// 1. 如果是最后一人,拿走所有if(restPeople==1){returnrestMoney;}// 2. 二倍均值法的核心公式// 范围:[1, (剩余金额/剩余人数) * 2)// 注意:Random 是左闭右开,所以要 -1 留给剩下的人至少 1 分钱intmax=(restMoney/restPeople)*2;// 随机生成金额,至少 1 分钱intamount=(int)(Math.random()*max);if(amount<=0)amount=1;// 3. 兜底逻辑:不能让剩下的人没钱分// 如果本次抢太多,导致剩下的人分不到 1 分钱,要强行截断if(restMoney-amount<restPeople-1){amount=restMoney-(restPeople-1);}returnamount;}}

🏗️ 高并发架构:Redis + Lua 脚本

算法有了,怎么抗住 10万 QPS?
绝对不能用 MySQL 的行锁(悲观锁),必死无疑。
必须使用Redis进行内存计算,并配合Lua 脚本保证原子性(Atomic)。

1. 架构流程图
1. 执行 Lua 脚本
2. 库存/金额不足
3. 扣减成功, 返回金额
4. 异步写入 (削峰)
5. 消费入库
用户请求: 抢红包
Nginx 负载均衡
业务服务 Cluster
Redis (单线程原子性)
返回: 抢光了
抢到红包
消息队列 (RocketMQ/Kafka)
MySQL (最终一致性)
2. 核心 Lua 脚本

Redis 的 Lua 脚本是原子执行的,中间不会被插入其他命令。我们把“查询剩余金额”、“计算二倍均值”、“扣减库存”这三步合为一步。

-- keys[1]: 红包信息的 Key (Hash结构)-- argv[1]: 用户 IDlocalkey=KEYS[1]localuserId=ARGV[1]-- 1. 校验是否抢过 (幂等性)ifredis.call('hexists',key..':records',userId)==1thenreturn-1-- 已经抢过了end-- 2. 获取剩余金额和人数localrestMoney=tonumber(redis.call('hget',key,'money'))localrestPeople=tonumber(redis.call('hget',key,'count'))-- 3. 校验库存ifrestPeople<=0thenreturn0-- 抢光了end-- 4. 执行二倍均值法算法 (简化版)localamount=0ifrestPeople==1thenamount=restMoneyelse-- Lua 的随机数localmax=math.floor((restMoney/restPeople)*2)amount=math.random(1,max)end-- 5. 扣减 Redis 库存redis.call('hincrby',key,'money',-amount)redis.call('hincrby',key,'count',-1)-- 记录领取记录redis.call('hset',key..':records',userId,amount)returnamount

📉 方案优缺点分析

方案优点缺点适用场景
预分配法(发红包时生成所有金额存 List)抢红包速度极快 (LPOP),逻辑简单占用内存大,发红包时耗时标准红包,人数确定
二倍均值法(实时计算)内存占用极小,不需要预存列表每次需要计算,Redis Lua 逻辑稍复杂超大额/超多人红包

📝 总结

设计一个抢红包系统,不仅仅是写个Random

  1. 算法层:用二倍均值法保证数学期望的公平。
  2. 存储层:用Redis Atomicity解决超卖。
  3. 持久层:用MQ 异步解耦保护 MySQL。

这一套组合拳打下来,面试官基本就被你折服了。


博主留言:
想获取“Redis Lua 脚本完整版”“SpringBoot 抢红包项目源码”吗?
在评论区回复“红包”,我打包发给你!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/31 20:32:17

Meta的 Mango「芒果」模型:看来AI视频生成要变天了

&#x1f4cc; 目录扎克伯格的「芒果」要炸场&#xff01;Meta神秘AI视频模型Mango曝光&#xff1a;4K/60帧秒出片&#xff0c;好莱坞都要慌了一、Meta的野心&#xff1a;不止超越Sora&#xff0c;要把AI视频搬进专业片场&#xff08;一&#xff09;Mango vs 现有AI视频工具&am…

作者头像 李华
网站建设 2026/5/28 22:05:29

moodycamel::ConcurrentQueue 清空队列的方法论

方法1&#xff1a;循环弹出元素 #include <concurrentqueue.h>// 如果存储的是指针类型 moodycamel::ConcurrentQueue<int*> queue; int* item nullptr; while (queue.try_dequeue(item)) {if (item) {delete item; // 如果需要释放内存item nullptr;} }// 如果…

作者头像 李华
网站建设 2026/5/30 17:36:43

halcon窗口显示文字

前言 我们在开发C#上位机的时候&#xff0c;有时候会使用Halcon控件&#xff0c;在Halcon控件上会有绘制文字&#xff0c;本文就来介绍如何实现。 Halcon代码实现 dev_close_window () dev_open_window (0, 0, 512, 512, black, WindowHandle) set_font (WindowHandle, 宋体…

作者头像 李华
网站建设 2026/6/1 0:55:10

Langchain-Chatchat错误排查手册:常见问题与解决方案

Langchain-Chatchat 错误排查手册&#xff1a;常见问题与解决方案 在企业级 AI 应用日益强调数据隐私和本地化部署的今天&#xff0c;基于大型语言模型&#xff08;LLM&#xff09;的知识库系统正从“云端调用”转向“私有可控”。Langchain-Chatchat 作为一款开源、可离线运行…

作者头像 李华
网站建设 2026/5/30 17:36:25

AtCoder Beginner Contest竞赛题解 | 洛谷 AT_abc436_b Magic Square

​欢迎大家订阅我的专栏&#xff1a;算法题解&#xff1a;C与Python实现&#xff01; 本专栏旨在帮助大家从基础到进阶 &#xff0c;逐步提升编程能力&#xff0c;助力信息学竞赛备战&#xff01; 专栏特色 1.经典算法练习&#xff1a;根据信息学竞赛大纲&#xff0c;精心挑选…

作者头像 李华