写个简易版秒杀系统练练手
不写文章还有点不自在,完了
今天来分享下这段时间学习的一个秒杀项目,黑马点评。
好久没跟着学这些,感觉非常非常好玩,又想捣鼓点项目玩玩了哈哈。
我也简单搭建了一个,用到了这些技术。
Springboot2Redis7LuaRedissonMySQL8RabbitMQ3。9MybatisPlusHutool
其中Redis和MySQL都是之前搭建在云端的K8S上的主从结构,用Traefik做总网关。
RabbitMQ则是之前在本地虚拟机上用docker搭建的,还有PrometheusGrafana监控。思路
隐藏秒杀地址
这个就是实现一个用户一个地址,给脚本工具加点难度。
根据需要生成这个path,比如用md5混淆下。
然后放到Redis中key:秒杀活动ID’path‘秒杀商品ID用户ID,value:path
真实的秒杀地址如下
lua脚本预扣库存
用lua脚本来保证这个操作的原子性,判断库存key存不存在,数量够不够,够的话执行扣减操作
bug
我这样写的脚本是有问题的,没有进行重复订单校验,以及set这个订单信息到redis中。
这3步操作应该是原子性的,校验,扣减,设置
所以即便lua脚本能保证操作的原子性,但是并发情况下会出现少卖的情况。
模拟同个用户50个并发
改正版
改正后也就正常了,之前我是老想着订单ID的生成要从分布式ID中获取,想尽量较少这个网络请求的,一不小心就疏忽了。(以后得先把核心思路写下,再思考优化,不能边写边想优化了)
分布式ID,我之前研究这个美团Leaf也是想简单搭建一个,奈何总喜欢偷懒,这里我是用Hutool的雪花算法简单生成的。
保存订单信息到Redis
出大bug之前,我以为这里只是做重复订单校验的,没想到,还有这种情况
MQ挂了,消息还没发送出去,甚至一开始就没连接上的情况。
比如我这个本机和虚拟机休眠后得重启下虚拟网络vm8,不然连不上去。
意料之外
所以,这里得写个小脚本,将订单信息发送到MQ中,在紧急情况下能快速补救。分布式锁
目前用jvm级别的锁其实就足够了,但后面上集群还得改代码,干脆一鼓作气。
锁的粒度,不能太大,主要防止用户重复下单。
比如第一版错误的lua脚本中,就会出现重复下单的情况集群模式下,多个消费者的情况,此时谁先拿到分布式锁,谁就可以消费这个订单,避免重复下单
通过分布式锁,保证这个订单只有一个消费者消费,即便在多个消费者模式下,也不会出现重复下单的情况。
同时,也可以防止使用Redis出现意外,就像上面错误使用lua脚本的案例,以及可能存在的key过期等问题导致的重复下单问题。
当然,这还不是兜底方案,万一这个分布式锁也出现意外了呢,所以保险起见,还需要给订单表建立唯一索引(用户id商品id),靠数据库本身保证了。
这里如果不用分布式锁,那就得从数据库层面去保证了,得用selectforupdate开启悲观锁,那效率会进一步降低的。
注意,这里也是缓存击穿的常见解决思路,分布式锁,双重检查锁模式。事务
我这里是简易版的,没有涉及到分库分表,所以也谈不上这个分布式事务。
这里我用的编程式事务,毕竟扣减库存和保存订单要在一个事务里,用注解的话还得考虑这个失效的场景,获取这个代理对象去执行,没有这个编程式事务来得方便。
假设订单在订单库中,商品在商品库中,那这种情况下,是不是还得考虑这个分布式事务呢?
我可能还是不会选择这个分布式事务,我会直接往商品库中建立一个秒杀订单表或者在订单库中建立这个秒杀商品库存表,甚至专门弄一个秒杀库,冗余一下,事后如果需要同步到相应的库表中,再进行相关的操作。
那假如还有个积分系统呢?
比如支付回调后,更新订单状态的同时,还要更新这个用户积分。
这我还是会选择MQ,通过MQ的可靠性来达到这个最终一致性
先发送消息到积分系统,更新订单信息单独在事务中。
这是分布式事务中常见的一种解决方案基于MQ可靠性消息的最终一致性方案。
有时间可以学习下Seata
重试机制
上图将MySQL和MQ的操作放一起,还得小心这个MQ的异常,导致这个事务回滚,但是ACK还是正常发出去的情况。
这里我最后还将异常抛出去,是为了触发这个重试机制,配置文件中开启RabbitMQ消费者重试机制即可。
ACK前发生异常,事务回滚,触发重试机制。
ACK中发生异常,捕获,丢弃异常,提交事务。再次消费时,发现是重复订单。
ACK后还有异常,未捕获,事务回滚,但消息已经被ACK,触发了重试机制,在重试期间没有异常,则正常处理。如果重试后还有异常,则会出现消息丢失的情况,这又得紧急处理了。防止超卖
有两个扣减动作
Redis预扣库存,这里得在lua脚本中操作。
MySQL扣减库存,这里核心就是乐观锁的方式aa1wherea0;
缓存
这里再简短啰嗦下缓存穿透
针对不存在的key,可以用布隆过滤器缓存击穿
key刚好过期,或者商品成了爆款
用分布式锁,双重检查锁模式能解决上面这两种情况,锁的粒度也是这个商品。
针对key刚好过期的情况,我了解到一种新的处理思路:逻辑过期
不在Redis中判断是否过期,在代码中进行判断,过期的话获取锁,开线程去更新,但实现起来比较复杂。缓存雪崩
大量key同时过期,可以给不同的Key的TTL添加随机值,给业务添加多级缓存,降级限流策略安排上总结
到这里,这个简易秒杀系统就介绍完了,至于限流,用户鉴权,标记,订单支付,超时处理,消息的顺序性再到大一点的集群,缓存一致性等等东西,得抽空再完善下了。
搭建过程中,最有意思的是,一直防着超卖,结果还出现了少卖的场景
所以这Redis预扣库存也得谨慎呀,lua脚本三合一疗程:查,扣,存
MySQL也一样,分布式锁,事务,查,扣,存
希望到时能把笔记中的技术都过一遍。
学习笔记
下面是我用JMeter测试的一些数据情况JMeter
这里两个http请求分别模拟,获取秒杀地址,开始秒杀。
jmeter500个并发,100件库存
报告一
这个平均响应是326ms,50的请求是245ms,99是1342ms,最小是21ms,最大是1359ms,吞吐量是605s。
这个成绩一言难尽,这还是用了MQ异步下单,还有内存标记,Redis预扣库存的结果,而且是预热了JVM的情况
这最大的开销应该是网络问题,要访问云服务器K8S中的Redis以及本地虚拟机上的MQ。
或者是我的老伙计性能问题,又得跑项目,还得测试,这CPU,内存,网卡估计也忙坏了。
简单分析下
获取秒杀地址,这里就访问一次Redis,执行Set命令。
开始秒杀中,涉及的网路操作有校验地址是否重复下单预扣库存lua脚本发送订单信息到MQ(虚拟机上)
后面把项目搭建到云服务器上再来测下。报告二
这里看到第一个请求的RT都比第二个请求的小。
Redis
Redis内存使用情况(测试前)
Redis内存使用情况(使用后)
可以看到,内存多了0。1M左右,这是多了601个key
至于怎么多了32条clientconnection,只能做个简单的推测先了
项目中使用了这个redisson做分布式锁,占用了25条
简单看下源码
拿到服务器上的所有连接,排掉之前的5条,刚好剩下32条。
这里看到使用resp3的有7条,刚好符合,应该是RedisTemplate相关创建的。
这里简单看下源码,Redis6开始默认使用RESP3的协议的
RabbitMQ
下面是从PrometheusGrafana监控截取的
RabbitMQ使用情况(测试前)
RabbitMQ使用情况(测试中)
这里发送端和消费端在一个应用上,共用一条connection,发送端创建了24个channel,消费端2个。
发送端第一条MQ数据
发送端第一条MQ数据被ACK
从这个监控图可以看到,消费端开始消费的时间点大概是16:47:00
而生产者发送第一条消息和被confirm的时间大概是16:46:30;这个有误差是因为这个监控自动刷新的频率是15s,目前是最小的了(可能是我挑的模板问题,或者是这并发太小)
消费者消费能力,大概每秒2个ack
channel
K8S
minikube节点,上面运行了Redis主从,MySQL主从。
K8S的情况(测试前)
K8S的情况(测试后)
基本没变化。
后面再把MQ和镜像仓库搭建一下,然后再把项目丢上去跑跑看看,到时再看看这个测试报告。
over!喜欢的小伙伴记得关注下哦,全网同名
宁可信其有,不可信其无新年步步高,寓意深远。我们今天攀登的是红旗峰,汽车沿着盘山公路一直开到山道的起点,我们下车沿着山道慢慢向上而行。前面也有几个游人在登山,一路上大声喧哗嬉闹,呼叫着彼此的名字。我摇摇
那些不落俗套的救赎治愈文案就在一次次日升月落里再爱一次人间。怀着爱意带着真诚保持温柔追逐星星。原来耀耀生辉的星星也会把角落里的孩子当做救赎。在我贫瘠的土地上你是最后的玫瑰。击鼓后,神把黑暗中跳舞的心脏叫做月
刀子嘴就是刀子心头条创作挑战赛经常有人说自己是刀子嘴。豆腐心,千万不要信,谁信谁倒霉地球是个能量场,一句话就是一个能量。攻击性,侮辱性,嘲讽性的话都会直接构成一个伤害风暴,伤害到内心,从而最后体现
中国影坛第一位300亿影人即将揭晓,目标人选有2位2023年春节档的预售票房排名让人有点意外,张艺谋的满江红和吴京主演的流浪地球2都没有登顶预售榜第一,反倒是梁朝伟和王一博主演的无名拿下了榜首,看来流量明星和知名影帝的组合在一定程
5部烂片再上热搜,当初离开沈腾的马丽,如今一点也不好笑前言马丽在离开沈腾后,真的发展不起来吗?01。马丽和沈腾在很多人心中,马丽和沈腾就是一对黄金搭档,在2015年,他们拍摄出了夏洛特烦恼这样的电影。电影夏洛特烦恼那个时候沈腾和马丽的
默多克新恋情曝光,邓文迪沉默不语数亿家产又多一个竞争者?91岁的传媒大亨身家超过170亿美元的默多克(RupertMurdoch)又谈恋爱了,他和新女友在巴巴多斯(Barbados)度假被拍到。当时,他们俩正手牵着手儿在海边散步!此时,
长月烬明阵容太养眼!本以为白鹿够惊艳,却被配角们迷住了!众所周知,仙侠剧很容易出爆款。从花千骨到三生三世十里桃花再到琉璃,都是热度与话题度齐飞的口碑佳作。新的一年里,网友们比较看好的作品有很多,其中热度最高的当属杨幂主演的狐妖小红娘月红
德凯大结局致敬泽塔?德凯剧场版上映信息公布本周六德凯奥特曼终于迎来大结局,先行剧照已经公开。德凯奥特曼第25话标题为彼方之光,监督为武居正能,编剧为根元岁三。地球的危机降临,满身疮痍的精英胜利队为了打倒强敌开始了最后的作战
丧尸危机游戏新春创作纪从前有114514个丧尸他们见人就咬首先人会通过痛苦的一个阶段,之后他们会变成一个叫做野兽先辈的丧尸他们会发动技能,114514被打中的人会经过痛苦的亨宁会直接变成野
游戏王怪兽卡龙族(18)中文名真红眼黑星龙日文名真紅眼黒星竜真红眼黑星龙中文名深渊之兽玛格巨龙日文名深淵之獸瑪格巨龍深渊之兽玛格巨龙中文名深渊之兽萨隆魔龙日文名深淵獣深渊之兽萨隆魔龙中文名深渊之兽德鲁伊鳞
外籍艺人粉丝大骂中国警察,流量明星何时休头号有新人加拿大籍选秀艺人余景天1月4号在上海机场现身,大量粉丝接机,造成机场通道拥堵。但是加拿大籍艺人仿佛状况外,眼看人群越来越密集,粉丝不停往中间挤。警察在大声询问过后,催促他