最近在学习场景题,记录一下自己的学习。秒杀很常见,手机秒杀,茅台酒类的秒杀,为的就是以很低的价格购入超值的产品。
业务特点
- 瞬间并发量大,定点秒杀的话,时间到来之前,已经开始接受考验了。
- 库存少,上万人抢1个也是常见的
- 业务流程比较简单
技术特点
- 高并发,快响应
- 防止超卖,固定少量库存
- 防机器人等各类刷子
- 页面资源访问较多
- 秒杀按钮点击一次和秒杀链接的隐藏
- 订单异步处理及订单处理失败补偿
- 服务降级
架构设计
拙劣的画图
架构详解
看了好几个视频,这个比较让我能接受,自上而下的介绍相关的架构的设计
应用层
- 需要将静态页面缓存到离的最近的CDN处,减少对于服务器的请求;
- CDN(Content Delivery Network)主要存储静态网络资源,比如图片、视频、css。可以减少服务器的请求量,因节点较多可以提升高可用性。通过不断的CDN query,可以匹配最近的CDN的cname,然后确定具体的ip地址。
- CDN相比于cache:节点数量多;距离远;数据类型较少;无超时设置
- 秒杀按钮设计:秒杀开启前,按钮置灰,秒杀开始后,按钮点击一次后置灰,增加滑动验证码,避免机器人秒杀,增加用户排队体验。
负载层
- 根据秒杀访问的QPS设计了四层负载均衡,第一层为F5/LVS,硬件级别的负载均衡器,第二层为Nginx的集群,可以实现限流,第三层为服务网关,可以进行限流和熔断,第四层为服务集群通过ribbon实现负载均衡。
- 利用云环境的动态扩容机制,秒杀开始前增加云机器数量,结束时回收云机器
中间件层
- 使用redis储存热点信息,进行库存的增减,
- 使用redis的lua脚本,比对库存是否大于零,将获取到的数据减一,替换原来的库存,表示秒杀成功一次
- setNX加锁,防止重复秒杀
- 增加分布式锁
- MQ
- 支持异步下单
- 限流
- 订单失败通知补偿策略
数据层
使用mysql的读写分离机制
细节
在高并发的订单处理下,如何避免超卖呢?
1 在数据库设置乐观锁(version),通过新旧版本的比对实现更新库存,减少超卖情况
start tranction;
select stock,version from orders where id=xxx;
if stock >= order_require:
update orders set stock = stock -order_require,version=version+1
where id=xxx and version=old_version;
if row >0:
insert into pruducts(order_id,quantity) values(1,order_require);
commit;
else:
rollback;
end if;
else
rollback;
end if;
2 设置redis的分布式锁,在进行同一商品的一个用户的订单的处理的时候,确保仅一个服务进行,保证服务幂等性