商品秒杀功能的高并发解决方案
一。业务逻辑分析
- 所谓秒杀: 从业务角度看,是短时间内多个用户“争抢”资源,这里的资源在大部分秒杀场景里是商品;将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确
1.秒杀业务的大概运行流程
- 提交秒杀商品申请(审核通过),录入秒杀商品数据,主要有:商品标题,商品原价,秒杀价格,商品图片,介绍等信息
- 运营商审核秒杀申请
- 秒杀频道首页列出秒杀商品,点击秒杀商品图片可以跳转到秒杀商品详细页面
- 商品详细页面显示秒杀商品信息,点击立即抢购实现秒杀下单,下单时扣减库存,当库存为0或者不存在活动时间范围内时无法秒杀
- 秒杀下单成功,直接跳转到支付页面(扫码),支付成功,跳转到成功页面,填写收货、电话、收件人等信息,完成订单。
- 当用户秒杀下单5分钟内未支付,取消预订单,调用支付的关闭订单接口,恢复库存。
A:查询模块(查询库存)并发查询,库存数存在缓存中,(商品信息和图片信息等)静态化处理(生成静态页)和库存剩余数量缓存化处理。
B: 下订单模块(秒杀关键部分),队列控制异步化处理,首先判断这个队列是否已满, 如果没满就将请求放入队列中排队,队列满以后的所有请求直接返回秒杀失败。
C: 支付模块,异步付款,等待付款成功结果。(付款成功更新库存,也可下单的时候扣库存)。
2.秒杀/抢购技术特点
-
读多写少 (一趟火车其实只有2000张票,200w个人来买,最多2000个人下单成功,其他人都是查询库存)
- 使用(Redis)缓存解决
-
高并发
-
限流 (限制同一时间访问的流量)
-
负载均衡 (单体tomcat并发200完美胜任,突破五,六百就力不从心)
-
缓存 (预先把秒杀商品加载进内存)
-
异步 (将同步的并发请求转换为异步,多线程处理)
-
队列 (使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行)
-
3.秒杀架构思想
(1).设计思路
-
超买超卖问题的解决。
-
**将请求拦截在系统上游,降低下游压力: ** 秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时
-
**充分利用缓存: **利用缓存可极大提高系统读写速度。
-
消息队列: 消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。
二。秒杀中的问题解决方案
1.秒杀页面(恶意刷新页面)
-
秒杀活动开始前,其实就有很多用户访问该页面了。如果这个页面的一些资源,比如 CSS、JS、图片、商品详情等,都访问后端服务器,甚至 DB 的话,服务肯定会出现不可用的情况。
-
解决方案: 所以要创建静态页面让这个页面整体进行静态化,并将页面静态化之后的页面分发到 CDN(类似于资源服务器) 边缘节点上,起到压力分散的作用
-
生成的静态页面会遇到的问题: 由于我们以后开发的系统肯定不是给自己用的,用户可能处于不同的时区,他们的当前系统时间也是不同的,所以我们写一个通用的时间规范:就是当前服务器的时间;
2.防止提前下单
- 在之前我们做的后端项目中,跳转到某个详情页一般都是:根据ID查询该详情数据,然后将页面跳转到详情页并将数据直接渲染到页面上。但是秒杀系统不