疯狂涨知识!「高并发秒杀」微信抢红包实战案例帮你突破瓶颈

推荐阅读:

  • 阿里二面凉经:设计模式+缓存+Spring+虚拟机+MySQL+中间件+并发等难题,全部迎刃而解
  • 阿里巴巴字节跳动那些大厂必问的HTTP该怎么学?我建议你看看这篇文章!
  • 蚂蚁、字节、PDD社招面经Java岗(分布式+线程安全+MySQL+CAS)

前言

群里有小伙伴咨询微信红包的架构,对于我来说,显然是不知道的,但是写一个相对高并发的抢红包案例还是完全可以的。

架构流程

架构设计

  • 老板发红包,此时缓存初始化红包个数,红包金额(单位分),并异步入库。

  • 抢红包,判断缓存剩余红包金额,剩余金额大于零则抢到红包,否则手慢了,红包派完了

  • 拆红包,根据 redPacketId 获取分布式锁,如果获取到锁,红包个数减一,如果剩余红包个数大于零抢红包成功、否则失败。成功则计算红包金额,缓存总红包金额减去抢到的红包金额,异步入库、异步到账。

  • 若获取分布式锁失败,使用 Redis的 decr命令对红包个数加一。

数据库设计

  • 红包信息表
CREATE TABLE `red_racket` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',`red_packet_id` bigint(20) NOT NULL COMMENT '红包唯一ID',`total_amount` int(11) NOT NULL COMMENT '红包金额单位分',`total_packet` int(11) NOT NULL COMMENT '红包个数',`type` int(11) NOT NULL COMMENT '红包类型',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`version` int(11) NOT NULL COMMENT '版本号',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='红包信息表'
  • 抢红包记录表
CREATE TABLE `red_packet_record` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',`amount` int(11) NOT NULL COMMENT '抢到红包的金额',`red_packet_id` bigint(20) NOT NULL COMMENT '红包ID',`uid` int(11) NOT NULL COMMENT '抢到红包用户的用户标识',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='抢红包记录表'

代码案例

老板发了10个红包一共200人民币,100个人同时抢红包,伪代码分别为拆红包和抢红包相关业务逻辑。模拟抢红包伪代码:

   /*** 抢红包 拆红包 抢到不一定能拆到* @param redPacketId* @return*/@ApiOperation(value="抢红包二",nickname="爪哇笔记")@PostMapping("/startTwo")public Result startTwo(long redPacketId){int skillNum = 100;final CountDownLatch latch = new CountDownLatch(skillNum);//N个抢红包/*** 初始化红包数据,抢红包拦截*/redisUtil.cacheValue(redPacketId+"-num",10);/*** 初始化红包金额,单位为分*/redisUtil.cacheValue(redPacketId+"-money",20000);/*** 模拟100个用户抢10个红包*/for(int i=1;i<=skillNum;i++){int userId = i;Runnable task = () -> {/*** 抢红包 判断剩余金额*/Integer money = (Integer) redisUtil.getValue(redPacketId+"-money");if(money>0){/*** 虽然能抢到 但是不一定能拆到* 类似于微信的 点击红包显示抢的按钮*/Result result = redPacketService.startTwoSeckil(redPacketId,userId);if(result.get("code").toString().equals("500")){LOGGER.info("用户{}手慢了,红包派完了",userId);}else{Double amount = DoubleUtil.divide(Double.parseDouble(result.get("msg").toString()), (double) 100);LOGGER.info("用户{}抢红包成功,金额:{}", userId,amount);}}else{/*** 直接显示手慢了,红包派完了*///LOGGER.info("用户{}手慢了,红包派完了",userId);}latch.countDown();};executor.execute(task);}try {latch.await();Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());LOGGER.info("剩余金额:{}",restMoney);} catch (InterruptedException e) {e.printStackTrace();}return Result.ok();}

业务层拆红包:

    @Override@Transactionalpublic Result startTwoSeckil(long redPacketId, int userId) {Integer money = 0;boolean res=false;try {/*** 获取锁 保证红包数量和计算红白金额的原子性操作*/res = RedissLockUtil.tryLock(redPacketId+"", TimeUnit.SECONDS, 3, 10);if(res){long restPeople = redisUtil.decr(redPacketId+"-num",1);if(restPeople>0){/*** 如果是最后一人*/if(restPeople==1){money = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());}else{Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());Random random = new Random();//随机范围:[1,剩余人均金额的两倍]money = random.nextInt((int) (restMoney / (restPeople+1) * 2 - 1)) + 1;}redisUtil.decr(redPacketId+"-money",money);/*** 异步入库*/RedPacketRecord record = new RedPacketRecord();record.setMoney(money);record.setRedPacketId(redPacketId);record.setUid(userId);record.setCreateTime(new Timestamp(System.currentTimeMillis()));saveRecord(record);/*** 异步入账*/}else{return Result.error("手慢了,红包派完了");}}else{/*** 获取锁失败相当于抢红包失败,红包个数加一*/redisUtil.incr(redPacketId+"-num",1);}} catch (Exception e) {e.printStackTrace();}finally {if(res){//释放锁RedissLockUtil.unlock(redPacketId+"");}}return Result.ok(money);}

演示

在 Application中有接口演示说明,你可以在抢红包 Red Packet Controller接口中输入任何参数进行测试,也可以配合数据库稍加修改即可作为生产环境的抢红包功能模块。

源码

最后

如果觉得本文对你有帮助的话,不妨给我点个赞,关注一下吧!

资料免费领取方式:点击这里

esult.ok(money);

}
## **演示**在 `Application`中有接口演示说明,你可以在抢红包 `Red Packet Controller`接口中输入任何参数进行测试,也可以配合数据库稍加修改即可作为生产环境的抢红包功能模块。## **源码**### 最后**如果觉得本文对你有帮助的话,不妨给我点个赞,关注一下吧!****[资料免费领取方式:点击这里](https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB)**[外链图片转存中...(img-qm6jDdfJ-1623502396052)]![](https://img-blog.csdnimg.cn/img_convert/6e6463247e74e06477dd5eb773261f4b.png)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android开发;Activity-Hook你了解多少?一起来debug

享学课堂特邀作者&#xff1a;周周 转载请声明出处&#xff01; 前言 手把手讲解系列文章&#xff0c;是我写给各位看官&#xff0c;也是写给我自己的。文章可能过分详细&#xff0c;但是这是为了帮助到尽量多的人&#xff0c;毕竟工作5,6年&#xff0c;不能老吸血&#xff0c;…

Android架构师谈:View-Pager-性能优化之-无限循环

作者&#xff1a;享学课堂Alvin老师 转载请声明出处&#xff01; ViewPager实现无限滑动 **方案一&#xff1a;**将viewpager上限设置成一个很大的数&#xff0c;第一个页面设置到中间。然后滑动的时候&#xff0c;用当前的序号与viewpager页面数取余得到目标页面的序号&#…

你知道如何用面向对象思想写好并发编程吗?

在工作中&#xff0c;我发现很多人在设计之初都是直接按照单线程的思路来写程序的&#xff0c;而忽略了本应该重视的并发问题&#xff1b;等上线后的某天&#xff0c;突然发现诡异的 Bug&#xff0c;再历经千辛万苦终于定位到问题所在&#xff0c;却发现对于如何解决已经没有了…

你知道怎么在生产环境下部署tomcat吗?

享学课堂特邀作者&#xff1a;老顾 转载请声明出处&#xff01; 一、前言 小伙伴们在网上看到的很多文章&#xff0c;都是对tomcat的一些介绍&#xff0c;什么配置啊&#xff0c;怎么启动。其实在生产环境中怎么部署&#xff0c;和网上介绍的有很大区别。这篇文章老顾就带着大…

浅谈HashMap

Java集合类的整体架构 比较重要的集合类图如下&#xff1a; 有序否 允许元素重复否 Collection 否 是 List 是 是 Set AbstractSet 否 否 HashSet TreeSet 是&#xff08;用二叉树排序&#xff09; Map AbstractMap 否 使用 key-value 来映射和存储数据&#xff0c; Key 必须惟…

互联网寒冬!“996”为什么还没实行?我还等着早点下班呢!

“喊了十多个月的‘996’&#xff0c;说要实行‘996’&#xff0c;上班上到现在&#xff0c;影子都没看到&#xff0c;我还能早点下班吗&#xff1f;” 我一个在广州上班的朋友小李&#xff0c;在我去广州出差期间&#xff0c;与他聊天的时候发出了这样的牢骚&#xff0c;我刚…

matlab求解常微分方程组/传染病模型并绘制SIR曲线

看了很多关于传染病模型的matlab程序,大都是绘制出两条曲线(I、S)的,本文最大的不同是绘出SIR三条曲线。 先给出SIR微分方程组 函数文件: run的程序:

互联网寒冬!技术站最全MySQL数据库实战规范

享学课堂特邀作者&#xff1a;老顾 转载请声明出处&#xff01; 前言 我们小伙伴们经常使用到mysql数据库&#xff0c;一般就这么一用&#xff0c;很少会考虑mysql里面的细节问题&#xff0c;如sql语句的规范&#xff0c;或索引有没有起到相应的效果&#xff0c;今天老顾就给大…

SQL求一个表中非重复数据及其出现的次数

mysql中&#xff0c;我们可以用distinct求不重复的数据有多少&#xff0c;也可以用group by。 这里有个例子&#xff0c;如下表sheet1&#xff0c;共有5411条数据 查询语句 共有3446条不重复数据&#xff0c;每条不重复数据出现的次数在第二列显示&#xff1a;

什么是微服务扩展性和高可用-可扩展性、高可用性和性能

欢迎关注专栏&#xff1a;Java架构技术进阶。里面有大量batj面试题集锦&#xff0c;还有各种技术分享&#xff0c;如有好文章也欢迎投稿哦。 Overview 可扩展性、高可用性和性能 术语可扩展性、高可用性、性能和关键任务对于不同的组织或组织内的不同部门来说可能意味着不同的…

SQL实现当前行等于前面两行数据之和

sql实现类似斐波那契数列的功能&#xff0c;即当前数据等于前面两个数据之和&#xff0c;详看本文例子 原表&#xff1a; sql语句&#xff08;此处要熟悉JION ON的用法&#xff09; 结果

【大牛系列教学】靠着这份面试题跟答案

开篇闲扯 打工人&#xff0c;打工魂&#xff0c;我们生而人上人。当“资本主义”逐渐禁锢我们人&#xff08;大&#xff09;上&#xff08;韭&#xff09;人&#xff08;菜&#xff09;肉体的时候&#xff0c;那一刻我才明白那个日不落帝国资本主义收割机瑞民族之光幸瑞幸咖啡…

【工作感悟】成功入职阿里月薪45K

前言 苦苦寻觅找工作之间&#xff0c;殊不知今日之时乃我心之痛&#xff0c;难道是我不配拥有工作嘛。自面试后他所谓的等待都过去一段时日&#xff0c;可惜在下京东上的小金库都要见低啦。每每想到不由心中一紧。正处为难之间&#xff0c;手机忽然来了个短信预约后续面试。 我…

【工作经验分享】不会真有人觉得mybatis很难学吧

什么是自旋锁和互斥锁&#xff1f; 由于CLH锁是一种自旋锁&#xff0c;那么我们先来看看自旋锁是什么&#xff1f; 自旋锁说白了也是一种互斥锁&#xff0c;只不过没有抢到锁的线程会一直自旋等待锁的释放&#xff0c;处于busy-waiting的状态&#xff0c;此时等待锁的线程不会…

【工作经验分享】这些新技术你们都知道吗

前言 近年来&#xff0c;微服务架构(Microservices Architecture)已经成为一种主流的软件开发方法论&#xff0c;所谓微服务( Microservices ),就是一些具有足够小的粒度、能够相互协作且自治的服务体系。 微服务架构基于分布式系统&#xff0c;同时借助了面向服务架构和企业服…

【微信小程序】使用Hystrix的插件机制

前言 在本篇文章开始前&#xff0c;我想想来回答一个问题&#xff1a;我为什么要写这一篇关于面试的文章&#xff1f; 原因有三&#xff1a;第一&#xff0c;我想为每一个为梦想时刻准备着的”有心人“尽一份自己的力量&#xff0c;提供一份高度精华的Java面试清单&#xff1…

【微信小程序】目前最全的《Java面试题及解析》

开头 在找工作的过程中&#xff0c;对于 Redis 技术知识的掌握已经成为必须的技能。美团面试常常就会被问到Redis相关知识&#xff0c;而这次我就差点倒在了美团3面&#xff0c;面试官连问我以下几个Redis的问题&#xff0c;然后就卡壳了… redis了解吗&#xff1f;你说说怎么…

大话数据结构——算法

算法&#xff1a;算法是解决特定问题求解步骤的描述&#xff0c;在计算机中表现为指令的有限序列&#xff0c;并且每条指令表示一个或多个操作。 为什么把数据结构和算法一起说&#xff1f; 想想罗密欧与朱丽叶&#xff0c;梁山伯和祝英台&#xff0c;少了一个你总会觉得奇怪…

java线上培训班学费一般多少,成长路线图

前言 众所皆知的&#xff0c;Linux的核心原型是1991年由托瓦兹(Linus Torvalds)写出来的&#xff0c;但是托瓦兹为何可以写出Linux这个操作系统?为什么它要选择386的计算机来开发?为什么Linux的发展可以这么迅速?又为什么Linux是免费的?以及目前为何有这么多的 Linux版本(…

java线程池使用实战,太牛了!

前言 今天这篇文章中简单介绍一下一个 Java 程序员必知的 Linux 的一些概念以及常见命令。 如果文章有任何需要改善和完善的地方&#xff0c;欢迎在评论区指出&#xff0c;共同进步&#xff01;笔芯&#xff01; 正式开始 Linux 之前&#xff0c;简单花一点点篇幅科普一下操作…