Java
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

README.md

goods-seckill

高性能电商秒杀解决方案

秒杀的关键点是对线程资源的抢夺,思路肯定是串行化,但关键在于串行粒度的控制。

最为简单的就是java代码里面添加synchronized同步锁,但是这样会导致所有购买请求(无论是否是同一个商品), 都会进入阻塞状态,性能极低,企业开发没有这样实现的。

并发压力测试使用jmeter,因为是模拟测试,QPS并不准确,但也能说明问题

初级方案,使用mysql排他锁完成抢购

参考:https://www.cnblogs.com/boblogsbo/p/5602122.html

使用mysql排他锁,控制抢购按顺序进行 排他锁,参考:https://www.cnblogs.com/boblogsbo/p/5602122.html mysql在innoDB引擎下,默认update,insert,delete语句都会添加排他锁 在操作同一行数据时,在排他锁未释放的情况下,该行数据无法再被添加任何锁(排他锁和共享锁) 所以,这里修改库存,是在排他锁下,按顺序减库存,会出现阻塞的情况

mysql排他锁方案一般应对并发量较为小的秒杀场景可以使用,秒杀过程中QPS在100左右。

不足:所有请求都会访问mysql数据库,查询库存;并且在库存足够的情况下,在减库存的时候,还会使用排他锁。 高并发情况下,这样直接操作数据库性能比较低

jmeter测试:500个线程循环4次,也就是模拟2000用户抢购请求,秒杀20件商品。 耗时9秒,等于是能够支持的QPS = 2000 / 9 = 222。

优化方案一,使用redis悲观锁单线程特性完成抢购

redis悲观锁介绍:https://blog.csdn.net/p_ython/article/details/76600001

用户抢购请求过来后redis预减库存,所有用户都先打到redis上, 抢购成功后,才会进行数据库操作,避免了大量的数据库读请求

不足:redis读写速度是非常快的,很快请求就会通过redis, 如果抢购商品数量特别大的话,比如有1万的手机参与抢购,那么透过redis的这1万请求还是会马上 打到mysql数据库,数据库还是会吃不消

jmeter测试:500个线程循环4次,也就是模拟2000用户抢购请求,秒杀20件商品。 耗时3秒,等于是能够支持的QPS = 2000 / 3 = 666。

优化方案二,使用redis和activeMQ降低数据库压力,完成抢购

这种方式还有待优化

适用于库存量较为大的秒杀,缓冲请求数据库

用户抢购请求过来后redis预减库存,所有用户都先打到redis上, 然后通过activeMQ缓冲用户请求,排队进入队列,然后逐个消费, 生成订单,避免大量透过redis的请求直接高并发的打到mysql数据库上