「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
概述
抢红包功能作为几大高并发场景中典型,应该如何实现?
分析
参考微信抢红包功能,将抢红包分成一下几个步骤:
- 发红包;主要填写红包信息,生成红包记录
- 红包支付回调;用户发红包支付成功后,收到微信支付付款成功的回调,生成指定数量的红包。
- 抢红包;用户并发抢红包。
- 拆红包;记录用户抢红包记录,转账抢到的红包金额。
效果展示
项目使用sessionId模拟用户,示例打开俩个浏览器窗口模拟两个用户。
设计开发
表结构设计
红包记录在 redpacket
表中,用户领取红包详情记录在 redpacket_detail
表中。
1 | sql复制代码CREATE DATABASE `redpacket`; |
发红包设计
用户需要填写红包金额、红包数量、备注信息等,生成红包记录,微信收银台下单,返回用户支付。
1 | ini复制代码public RedPacket generateRedPacket(ReqSendRedPacketsVO data,String userId) { |
红包支付成功回调设计
用户支付成功后,系统接收到微信回调接口。
- 更新红包支付状态
- 二倍均值法生成指定数量红包,并批量入库。 红包算法参考:Java实现4种微信抢红包算法,拿走不谢!
- 红包总数入redis,设置红包过期时间24小时
- websocket通知在线用户收到新的红包
1 | scss复制代码@Transactional(rollbackFor = Exception.class) |
页面加载成功后初始化websocket,监听后端新红包生成成功,动态添加红包到聊天窗口。
1 | javascript复制代码$(function (){ |
抢红包设计
抢红包设计高并发,本地单机项目,通过原子Integer控制抢红包接口并发限制为20,
1 | less复制代码private AtomicInteger receiveCount = new AtomicInteger(0); |
对于没有领取过该红包的用户,在红包没有过期且红包还有剩余的情况下,抢红包成功,记录成功标识入redis,设置标识过期时间为5秒。
1 | kotlin复制代码public String receiveOne(ReqReceiveRedPacketVO data) { |
拆红包设计
在用户抢红包成功标识未过期的状态下,且红包未过期红包未领完时,从数据库中领取一个红包,领取成功将领取记录写入redis以供查询过期时间为48小时。
1 | ini复制代码@Transactional(rollbackFor = Exception.class) |
其中 detailMapper.receiveOne(packetId, packetNo, userId);
sql如下,将指定红包记录下未领取的红包更新一条未当前用户已经领取,若成功更新一条则表示领取成功,否则领取失败。
1 | csharp复制代码update redpacket_detail d |
获取红包领取记录设计
直接充redis中获取用户领取记录,没有则直接获取数据库并同步至redis。
1 | scss复制代码public RespReceiveListVO receiveList(ReqReceiveListVO data) { |
jmeter并发测试抢红包、查红包接口
设置jmeter参数1秒中并发请求50个抢11个红包,可以看到,前面的请求都是成功的,中间并发量上来后有部分达到并发上限被拦截,后面红包抢完请求全部失败。
本文转载自: 掘金