太傻了!下次二面再回答不好“秒杀系统“设计原理,我就捶死自己( 二 )


解决方案:假设下单服务器集群有10台服务器 , 每台服务器只接受最多10个下单请求 。在还没有人提交订单成功之前 , 如果一台服务器已经有十单了 , 而有的一单都没处理 , 可能出现的用户体验不佳的场景是用户第一次点击购买按钮进入已结束页面 , 再刷新一下页面 , 有可能被一单都没有处理的服务器处理 , 进入了填写订单的页面 , 可以考虑通过cookie的方式来应对 , 符合一致性原则 。当然可以采用最少连接的负载均衡算法 , 出现上述情况的概率大大降低 。
7、如何进行下单前置检查
下单服务器检查本机已处理的下单请求数目:

  • 如果超过10条 , 直接返回已结束页面给用户;
  • 如果未超过10条 , 则用户可进入填写订单及确认页面 。
检查全局已提交订单数目:
  • 已超过秒杀商品总数 , 返回已结束页面给用户;
  • 未超过秒杀商品总数 , 提交到子订单系统 。
秒杀一般是定时上架
该功能实现方式很多 。
不过目前比较好的方式是:提前设定好商品的上架时间 , 用户可以在前台看到该商品 , 但是无法点击“立即购买”的按钮 。但是需要考虑的是 , 有人可以绕过前端的限制 , 直接通过URL的方式发起购买 , 这就需要在前台商品页面 , 以及bug页面到后端的数据库 , 都要进行时钟同步 。越在后端控制 , 安全性越高 。
定时秒杀的话 , 就要避免卖家在秒杀前对商品做编辑带来的不可预期的影响 。这种特殊的变更需要多方面评估 。一般禁止编辑 , 如需变更 , 可以走数据订正的流程 。
减库存的操作
有两种选择 , 一种是拍下减库存 另外一种是付款减库存;目前采用的“拍下减库存”的方式 , 拍下就是一瞬间的事 , 对用户体验会好些 。
库存会带来“超卖”的问题:售出数量多于库存数量
由于库存并发更新的问题 , 导致在实际库存已经不足的情况下 , 库存依然在减 , 导致卖家的商品卖得件数超过秒杀的预期 。方案:采用乐观锁 。
update auction_auctions setquantity = #inQuantity#where auction_id = #itemId# and quantity = #dbQuantity#还有一种方式 , 会更好些 , 叫做尝试扣减库存 , 扣减库存成功才会进行下单逻辑:
update auction_auctions set quantity = quantity-#count# where auction_id = #itemId# and quantity >= #count#秒杀器的应对
秒杀器一般下单个购买及其迅速 , 根据购买记录可以甄别出一部分 。可以通过校验码达到一定的方法 , 这就要求校验码足够安全 , 不被破解 , 采用的方式有:秒杀专用验证码 , 电视公布验证码 , 秒杀答题 。
秒杀架构原则尽量将请求拦截在系统上游
传统秒杀系统之所以挂 , 请求都压倒了后端数据层 , 数据读写锁冲突严重 , 并发高响应慢 , 几乎所有请求都超时 , 流量虽大 , 下单成功的有效流量甚小【一趟火车其实只有2000张票 , 200w个人来买 , 基本没有人能买成功 , 请求有效率为0】 。
读多写少的常用多使用缓存
这是一个典型的读多写少的应用场景【一趟火车其实只有2000张票 , 200w个人来买 , 最多2000个人下单成功 , 其他人都是查询库存 , 写比例只有0.1% , 读比例占99.9%】 , 非常适合使用缓存 。
秒杀架构设计秒杀系统为秒杀而设计 , 不同于一般的网购行为 , 参与秒杀活动的用户更关心的是如何能快速刷新商品页面 , 在秒杀开始的时候抢先进入下单页面 , 而不是商品详情等用户体验细节 , 因此秒杀系统的页面设计应尽可能简单 。
商品页面中的购买按钮只有在秒杀活动开始的时候才变亮 , 在此之前及秒杀商品卖出后 , 该按钮都是灰色的 , 不可以点击 。
下单表单也尽可能简单 , 购买数量只能是一个且不可以修改 , 送货地址和付款方式都使用用户默认设置 , 没有默认也可以不填 , 允许等订单提交后修改;只有第一个提交的订单发送给网站的订单子系统 , 其余用户提交订单后只能看到秒杀结束页面 。要做一个这样的秒杀系统 , 业务会分为两个阶段:


推荐阅读