1、秒杀场景
前端层面
前端优化(前端按钮点击频率限制、限制用户维度访问频率、限制商品维度访问频率、验证码机制等)
页面数据的静态化+多级缓存(CDN加速+Nginx+Redis)
服务层面
web服务器优化(tomcat、undertow)
nginx限流
负载均衡
服务器硬件升级
削峰处理
服务降级、熔断
jvm性能调优
业务层面
数据库分库分表、读写分离
sql调优
代码调优
超卖常用解决方案
事务
我们可以使用使用redis的 watch + multi 指令,去监听秒杀商品库存,如果库存数发生改变,则后续无法进行修改库存操作。
缺点:(1)由于watch采用乐观锁机制,没有对其它线程修改操作作限制,因此事务有可能频繁失败;需要用while循环去重复尝试;
(2)增加服务器压力
分布式锁
利用分布式锁,保证同一时刻只有一个线程进行读库存---修改库存操作。
缺点:同一个商品多用户同时下单的时候,会基于分布式锁串行化处理,导致没法同时处理同一个商品的大量下单的请求,并发处理能力较弱。
redis 队列
将库存缓存到redis队列,队列里面放sku_id,例如库存为5个,就放5个id。
通过rightPop操作取出商品,预扣减库存,如果pop出来的元素为空,说明售罄 。
这里利用了redis单线程操作特性,队列取id即扣减库存,相当于原子操作,高并发场景下不需要开事务,也不用加锁同步,性能、数据一致性均好于以上两种方案。
重复下单问题
MQ在整个秒杀流程中扮演了很重要的角色,因为下单数据全部暂存在MQ中,一旦消费者重复消费,就有可能出现一个用户秒杀到两个商品的重复下单情况。
所以代码有必要进行重复消息判断。
解决方案:
利用redis:发送消息时指定消息的全局唯一id;收到消息后查询redis是否有该id,有则说明是重复消息。然后立即将id存入redis中。
业务校验:生成订单时校验用户是否已经秒杀过该商品。
下单消息丢失
如果下单消息丢失了,用户秒的这个商品就可能永远卖不出去了,造成少卖问题。
以rabbit为例:
生产者丢失消息
(1)使用事务;
(2)使用confirm模式;
(3)异步监听确认模式
MQ丢失消息
开启消息持久化
消费者丢失消息
消费者消费完成后回执确认,如果一段时间后MQ没有收到消费者的回执确认,MQ就认为消息没有被成功消费,会将消息重新发送给其他消费者。