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

推荐阅读:

  • 阿里二面凉经:设计模式+缓存+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,一经查实,立即删除!

相关文章

2016面试——腾讯、蚂蚁金服、蘑菇街

腾讯TST技术面&#xff1a; 先罗列一下问题吧: 编程语言编译的过程 同样的逻辑,golang的二进制代码比C语言的二进制代码长很多.试分析原因 项目 ,三个项目都有聊.因为现场面,可以用纸写,所以描述的更清楚些 N * N的方格纸,里面有多少个正方形 两个数组求交集 什么样的…

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

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

牛客网笔记之JAVA运算符

计算机的最基本用途之一就是执行数学运算&#xff0c;作为一门计算机语言&#xff0c;Java也提供了一套丰富的运算符来操纵变量。我们可以把运算符分成以下几组&#xff1a; 算术运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 其他运算符 逻辑运算符结果 ~a是按位非&#…

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 必须惟…

matlab实现一元线性回归和多元线性回归

在回归分析中,如果有两个或两个以上的自变量,就称为多元回归。事实上,一种现象常常是与多个因素相联系的,由多个自变量的最优组合共同来预测或估计因变量,比只用一个自变量进行预测或估计更有效,更符合实际。 在实际经济问题中,一个变量往往受到多个变量的影响。例如,家…

互联网寒冬!“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;那一刻我才明白那个日不落帝国资本主义收割机瑞民族之光幸瑞幸咖啡…

matlab实现二项分布

二项分布 1. 求n次独立重复试验中事件A恰好发生k次的概率P。 命令:pdf 或 binopdf 格式:pdf (‘bino’, k, n, p) 或 binopdf (k, n, p) 说明:该命令的功能是计算二项分布中事件A恰好发生k次的概率。pdf为通用函数,bino表示二项分布,binopdf为专用函数,n为试验总次数,…

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

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

Mysql优化技巧

索引优化&#xff0c;查询优化&#xff0c;查询缓存&#xff0c;服务器设置优化&#xff0c;操作系统和硬件优化&#xff0c;应用层面优化&#xff08;web服务器&#xff0c;缓存&#xff09;等等。这里的记录的优化技巧更适用于开发人员&#xff0c;都是从网络上收集和自己整理…

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

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

华为面试题

技术面试&#xff1a; java&#xff1a; java学了几年&#xff0c;看过什么书&#xff0c;有没有看过thinking in java这本书 java的公共父类是什么&#xff0c;object类中有什么方法 object中有个hashcode方法&#xff0c;这个方法是用来做什么的&#xff0c; equal 与 的区…