之前完成了一个秒杀下单系统的开发,现在总结一下,

起因

业务场景是社区电商, 疫情期间,社区准备了一批口罩,打算分批让用户抢购。那时我们还在过年,客户也没通知我们,然后我们这个小电商系统,在当晚就挂掉了。下面是我们当时的架构:类似下面

Redis 队列实现秒杀 redisson实现秒杀_数据库查询

稍微思考到这个架构的问题,用户下单时,redisson进行加锁时,会让其他线程等待。所以在并发大时,会导致tomcat连接数超限。后面查询日志也证明了如此,所以当时临时的解决方案是,重启+增加应用容器。总算勉强度过。

后面我们紧急改造了我们的业务j流程,变成了下面这样:

Redis 队列实现秒杀 redisson实现秒杀_redis_02

主要做了两点改变:

1.将查询库存放到了redis中

2.将实际的下单功能放到了,MQ应用中。

这样极大的提高了前端应用的承载能力,经实战测试 2万的口罩,3分钟内全部卖空,系统平稳运行。

首先先看一下我们现在具体的秒杀流程。

秒杀流程概览:

Redis 队列实现秒杀 redisson实现秒杀_redis_03

文字表述如下:

  • 客户提交订单,包含多个商品
  • 后台应用
  • 对商品id加锁,
  • 循环判断商品库存是否在redis中存在
  • redis没有库存,从数据库查询库存,减去本次构购买数,放入到redis中
    (如果库存不够此次贩卖,将数据库库存放入到redis中)
  • redis中有库存,减去本次购买数,重新放到redis中。
  • 解锁生成订单号,将本次订单信息发送到mq,异步消费
  • 返回订单号,
  • 客户端获取订单号,轮询查询订单状态。
  • MQ消费应用
  • 对商品,促销商品,优惠券,积分进行加锁
  • 扣减优惠券,积分,生成订单,扣减库存,保存订单信息
  • 将订单结果存入redis。解锁
  • 完成实际下单
  • 前端轮询查询订单是否下单成功

问题

看完整个详细流程,已经解决了主要的高并发问题,现在讲讲实际遇到的一些问题:

1.如果redis缓存被清空了怎么办?

因为我们公司目前将redis的作用就是缓存,所以当redis快满了时,运维会将redis进行清空。(虽然有做redis 内存淘汰侧率,但是主要是总有人使用redis时没设置redis的过期时间),所以redis缓存失效的情况,需要考虑,所以我们mq消费时,会重新加锁,如果发现库存不足,会将结果存入redis。前端通过oderNo轮询就知道订单失败。

2.库存不足

情景一 :提交两个商品,一个redis 库存够,另一个redis库存不够如何处理?

情景二:提交两个商品,一个在redis中有库存,但库存不足,另一个redis没有库存,需要从数据库查询,但库存足够本次购买:

答:这个我们处理思路是,判断是否超卖 循环中判断,但是所有redis存库存的操作,解锁前统一保存到redis。(我们是 redis cluster,分片了不支持事务);

3.秒杀开始后能否修改库存?

这个当时我们是考虑到库存存到redis了,并设置过期时间,所以无论商家改大或者该小,都不会导致错误。但是,由于MQ消费消息,是有并发锁的,这个时候去看的库存,是不真实的,因为有许多订单是已经提交,但是没有落库。所以我们禁止了秒杀开始后修改库存