blog:java:seckill

秒杀系统设计

  • 流量巨大。区别于正常的交易流程,在短时间内有大量的访问和交易。访问的并发可能是平时的几百倍甚至更多
  • 全平台的商品数量巨大,但是参与秒杀的商品数量是有限的
  • 在特定的时间点开始和结束
  • 用户操作手法与平时的购物不一样。平时的购物流程需要关注用户体验,优化商品展示信息。秒杀页面更多的是不停的刷新操作,对于商品信息的一些细节部分并不是很关注
  • 独立部署,隔离秒杀业务的流量冲击对正常业务带来的风险
  • 从业务上看,它是和普通商品完全不一样的售卖流程,它需要一个提报过程。
  • 大部分的电商平台,会有一个专门的提报系统(提报系统的建设不是秒杀的核心部分,这里不再赘述),商家或者业务可以根据自己的运营计划在提报系统里进行活动提报,提供参与秒杀的商品编号、活动起止时间、库存量、限购规则、风控规则以及参与活动群体的地域分布、预计人数、会员级别等基本信息。
  • 你别小看这个提报过程和这些基本信息,有了这些信息作为输入,我们就能预估出大致的流量、并发数等,并结合系统当前能支撑的容量情况,评估是否需要扩容,是否需要降级或者调整限流策略等,因此业务隔离的重要性可见一斑。
  • 理论上讲,需要把交易链路上涉及到的系统都单独复制部署一套,隔离干净,但这样做成本比较高,一般大点的电商平台都采用分布式微服务的部署架构,服务数量少则几十个,多则几百个,全部复制一套进行隔离不现实。
  • 所以比较常见的实践是对会被流量冲击比较大的核心系统进行物理隔离,而相对链路末端的一些系统,经过前面的削峰之后,流量比较可控了,这些系统就可以不做物理隔离。
  • 我们知道,用户的秒杀习惯,一般是打开商品详情页进行倒计时等待,时间到了点击秒杀按钮进行抢购。因此第一个需要关注的系统就是商品详情页,我们需要申请独立的秒杀详情页域名,独立的 Nginx 负载均衡器,以及独立的详情页后端服务,并采用 Dubbo 独立分组的方式单独提供秒杀服务。
  • 为了能水平扩展服务的能力,一般我们在流量入口都会通过负载均衡器来进行流量分配,常用的有硬件负载均衡,比如 F5,其功能和性能优于软件方式,但一般比较昂贵。
  • 为了不让流量互相影响,我们都有必要对负载均衡进行隔离,需要单独部署一套。隔离的方式也比较简单,部署之后,把相应的 IP 地址挂载到不同的 DNS 域名下就好了。
  • 我们可以向运维部门申请一个独立的域名,专门用来承接秒杀流量,流量从专有域名进来之后,分配到专有的负载均衡器,再路由到专门的微服务分组,这样就做到了应用服务层面从入口到微服务的流量隔离。
  • 在数据层面,我们也应该进行相应的隔离,否则如果共用缓存或者共用数据库,一旦瞬时流量把它们冲垮,照样会影响无辜商品的交易。
  • 数据层的专有部署,需要结合秒杀的场景来设计部署拓扑结构,比如 Redis 缓存,一般的场景一主一从就够了,但是在秒杀场景,需要一主多从来扛读热点数据。
  • 防止跳过秒杀页面直接下单
  • 防止有些人通过技术手段,跳过秒杀直接购买商品
  • 缓存:降低响应时间,提高服务的负载能力
    • 浏览器本地缓存
    • CDN缓存
  • 每次刷新的时候,都会加载秒杀页面。秒杀页面信息尽可能简单
  • 添加预约逻辑,控制参与秒杀的人数
  • 预约期内,开放用户预约,获取秒杀抢购资格;秒杀期内,具备抢购资格的用户真正开始秒杀。在预约期内,关键是锁定用户,这也是我们能够用来做流量管控的核心。在展开通过预约进行流量管控的细节之前,我们先看下如何来设计一个简单的预约系统。

  • 流控
    • 防止黄牛的狂刷 (针对IP做防轰炸)
    • 控制进入后续流程的请求 (只允许有限数量的请求进入后续流程)
  • 并发场景下的数据一致性问题
  • 通过缓存降低读压力
    • 商品信息、价格信息这些经常查询的数据放缓存
  • 通过mq降低写压力
    • 购物车、订单信息。通过MQ的方式,削峰填谷。控制消费的速度,降低数据库的写压力
  • blog/java/seckill.txt
  • 最后更改: 2022/04/28 11:08
  • okami