商城系统中,抢购和秒杀是很常见的营销场景,在一定时间内有大量的用户访问商场下单,主要需要解决的问题有两个:
- 高并发对数据库产生的压力;
- 竞争状态下如何解决商品库存超卖;
高并发对数据库产生的压力
对于第一个问题,使用缓存来处理,避免直接操作数据库,例如使用Redis。
竞争状态下如何解决商品库存超卖
对于第二个问题,需要重点说明。
常规写法:查询出对应商品的库存,判断库存数量否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数。
测试表 sql
把如下表数据导入到数据库中
1 | /* |
下单处理代码
1 |
|
将库存字段字段设为unsigned
因为库存字段不能为负数,在下单后更新商品库存时,如果出现负数将返回false
1 |
|
使用mysql的事务,锁住操作的行
在下单处理过程中,使用mysql的事务将正在下单商品行数据锁定
1 |
|
使用非阻塞的文件排他锁
在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户”服务器繁忙”,计数器存储抢购的商品数量,避免查询数据库。
阻塞(等待)模式:并发时,当有第二个用户请求时,会等待第一个用户请求完成、释放锁,获得文件锁之后,程序才会继续运行下去。
1 |
|
非阻塞模式:并发时,第一个用户请求,拿得文件锁之后。后面请求的用户直接返回系统繁忙,请稍后再试
1 |
|
使用redis队列
- 因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用
- mysql事务在高并发下性能下降很厉害,文件锁的方式也是
- 先将商品库存到redis队列
1 |
|
- 抢购、秒杀逻辑
1 |
|
redis乐观锁防止超卖
1 |
|