2026年8月2日
秒杀系统 02 系统内部的隔离与自我保护机制
这里不再关注"怎么挡住外部流量",而是关注万一挡不住,系统内部要怎么保护自己不被拖垮。
一、服务单一职责 + 独立部署
要解决的问题: 很多系统在设计初期,秒杀功能是直接写在"商品服务"或者"订单服务"里的,跟正常下单逻辑混在一起、部署在同一批机器上。这样做的风险是:秒杀这种瞬时高并发场景一旦把服务打挂,会连带把正常的日常购物功能也一起拖垮。
具体做法:
- 秒杀服务独立拆分成一个微服务,比如叫
seckill-service,跟商品服务、订单服务、用户服务在代码层面完全解耦 - 独立部署,独立的机器/容器集群,不与主站共享服务器资源
- 独立的数据库/缓存实例:秒杀专用的Redis集群、甚至专用的数据库实例,不与主站商品库、订单库共用连接池
- 独立域名/独立网关入口:比如秒杀走
seckill.xxx.com,主站走www.xxx.com,即使秒杀的Nginx被打满,也不会影响主站的Nginx
为什么这样做很关键: 举个具体场景——双11零点秒杀,100万人涌入抢购,如果秒杀服务和商品详情页服务部署在一起,当秒杀接口把服务器CPU、内存、数据库连接池全部耗尽的时候,一个普通用户只是想打开首页看看别的商品,也会因为服务器资源耗尽而打不开页面。做了独立部署之后,即使秒杀服务整体挂掉,主站其他功能完全不受影响,这就是"故障域隔离"的思想。
进一步延伸——数据隔离: 秒杀商品的库存数据,通常会从主商品库里单独复制一份出来,放到秒杀专用的Redis或者轻量级存储里。秒杀期间所有的读写都针对这份"影子数据",活动结束后再跟主库做数据同步和核对。这样即使秒杀把这份数据打得再狼藉,也不会影响主商品库的正常数据。
二、限流 & 熔断 & 降级
这三个是三个不同层面的保护手段,很多人会把它们混为一谈,实际上要分开理解:
1. 限流(Rate Limiting)—— 提前控制流量,不让系统超载
目的: 系统知道自己的极限承载能力是多少(比如压测出来单机能扛5000 QPS),那就主动把超过这个阈值的请求拒绝掉,而不是硬扛导致雪崩。
限制维度:
- 限制次数:比如同一个用户ID,在秒杀活动的10分钟内,只允许提交3次抢购请求,超过直接拒绝
- 限制总量:系统整体设置一个"当前正在处理中"的并发请求上限,比如同时最多处理1万个请求,第10001个请求进来直接返回"系统繁忙"
常见实现算法:
- 令牌桶算法(Token Bucket):系统以固定速率往桶里放令牌,请求进来要拿到令牌才能被处理,桶满了就不再放,请求拿不到令牌就被拒绝。这个算法允许一定程度的突发流量(桶里存着的令牌可以一次性被拿光)
- 漏桶算法(Leaky Bucket):请求先进入一个固定容量的桶,系统以固定速率从桶里取出请求处理,桶满了新请求直接丢弃。这个算法能强制把请求处理速率控制得非常平稳,不允许突发
在秒杀里的落地位置:
- 网关层限流:Nginx+Lua脚本,或者用阿里开源的Sentinel,在请求真正进入应用服务器之前就做限流判断
- 接口级限流:即使通过了网关,具体到"秒杀下单"这个接口本身,也可以再设置一层限流,双保险
2. 熔断(Circuit Breaker)—— 依赖出问题时,快速止损
要解决的问题: 秒杀下单接口内部往往要调用多个下游服务(比如库存服务、用户服务、优惠券服务)。如果其中某个下游服务因为压力过大响应变慢(比如从原来10ms变成5秒),调用方的线程会大量堆积在等待这个慢响应上,线程池被占满,最终导致调用方自己也被拖垮——这就是经典的"雪崩效应"。
熔断器的工作原理(以Hystrix/Sentinel为例),类似电路里的保险丝:
- 关闭状态(Closed):正常调用下游服务,同时统计失败率
- 打开状态(Open):一旦失败率在短时间内超过阈值(比如50%的请求都超时或报错),熔断器立刻"跳闸",在接下来的一段时间内(比如30秒),所有请求直接快速失败,根本不再真正去调用那个出问题的下游服务
- 半开状态(Half-Open):30秒后,熔断器放几个请求试探性地调用一下下游服务,如果恢复正常了就重新关闭熔断器恢复调用,如果还是失败就继续保持打开状态
核心价值: "快速失败"比"等待然后失败"要好得多——与其让1万个请求都傻等5秒最后超时,不如直接告诉用户"库存服务繁忙,请稍后重试",这样能立刻释放线程资源,避免自己也被拖入雪崩。
3. 降级(Degradation)—— 保住核心,舍弃非核心
核心思路: 秒杀这一刻,系统资源是有限的,要把资源优先保障给"最核心的链路"(能不能成功下单、扣库存),而把非核心功能主动关闭或者简化。
秒杀场景里常见的降级手段:
- 关闭优惠券/积分抵扣计算:秒杀商品通常价格已经很低了,活动期间直接不允许叠加使用优惠券,减少一次下游服务调用和计算逻辑
- 关闭个性化推荐:秒杀页面不再实时计算"猜你喜欢"这种个性化模块,改成走静态兜底数据
- 简化订单创建流程:比如物流地址校验、库存分仓计算等相对复杂的逻辑,在秒杀瞬间先跳过或者简化,活动结束后再异步补全和校验
- 返回缓存的兜底数据:比如库存数量的展示,不再实时查询,允许有几秒的延迟,直接读缓存里的值
降级的触发方式:
- 自动降级:系统监控到CPU、内存、响应时间超过阈值,自动触发降级开关
- 手动降级:运营/运维提前预判秒杀会有超大流量,提前手动把非核心功能关闭,活动结束后再手动打开
降级和熔断的关系: 熔断是"手段",降级是"结果"——熔断器跳闸之后,系统往往需要一个"降级逻辑"去兜底(比如库存服务熔断了,不能直接报错给用户,而是走一个"降级返回:库存不足,请稍后重试"的逻辑),两者通常是配合使用的。
这一阶段串起来看
经过第一阶段过滤后的"干净流量"进入系统
→ 独立部署的秒杀服务接收请求(不影响主站其他服务)
→ 网关/接口层限流:超过承载能力的直接拒绝,不硬扛
→ 调用库存/用户等下游服务时,用熔断器保护,防止某个服务变慢拖垮整体
→ 熔断触发或系统压力大时,自动降级非核心功能,把资源留给"下单扣库存"这条核心链路
到这一步,系统已经具备了"进不来的流量被挡在外面"+"进来的流量系统能扛住、扛不住能自保"这两层能力。库存预热+原子扣减、队列削峰才是真正处理"到底怎么把库存正确地卖出去"这个核心业务问题,这也是整个秒杀系统里技术含量最高、面试最爱追问细节的部分。