第2章 微服务架构中的雪崩效应
2.1 什么是雪崩效应
简单来说,雪崩就是一个小故障像多米诺骨牌一样,把整个系统拍在地上。
我记得刚接触微服务那会儿,觉得每个服务拆得挺干净,心里还挺美。结果线上一次密钥服务抖动,直接让全站接口全部报 503。那会儿我才真正体会到,什么叫牵一发而动全身。
微服务架构里,服务之间通过 RPC 或 HTTP 互相调用。一旦某个底层服务变慢或挂掉,上游服务会一直等它返回。等待的过程中,上游的线程池、连接池被慢慢占满。新请求进不来,就开始排队超时。超时又触发重试,重试再加重下游压力……恶性循环,直到整个链路崩溃。这就是雪崩。
核心特征:局部故障 → 资源耗尽 → 级联扩散 → 全局不可用
你想想看,密钥服务在鉴权链路里是刚需,几乎每个接口都要调它。一旦它出问题,影响面是几何级放大的。我见过一个项目,因为密钥服务响应时间从 5ms 涨到 500ms,上游 20 个服务开始排队超时,最终导致整个集群 OOM。嗯,这种事故谁都不想半夜被拉起来处理。
2.2 雪崩的典型成因
我把常见成因归了归类,拿密钥服务举例来说:
| 成因类别 | 具体表现 | 密钥服务场景 |
|---|---|---|
| 资源耗尽 | 线程池/连接池占满,新请求拒绝 | 密钥加解密操作太慢,占住所有 Worker 线程 |
| 超时堆积 | 调用方设置超时过长,请求排队积压 | 默认超时 60s,下游慢导致大量请求堆积在中游队列 |
| 重试放大 | 失败后立即重试,流量翻倍 | 客户端重试策略没配退避,每秒重试上千次 |
| 阻塞级联 | 单点故障导致上游全部阻塞 | 密钥服务依赖的 HSM 硬件卡死,所有调用方同步阻塞 |
| 缓存击穿 | 缓存失效瞬间,大量请求穿透到后端 | 密钥轮换时旧缓存过期,所有服务同时请求新密钥 |
我单独说说「重试放大」这个坑。曾经有个同事写重试逻辑时忘了加指数退避,结果密钥服务慢了一秒,客户端直接重试了 10 次,等于流量一下子放大到 10 倍。服务本来就扛不住,这下直接打挂。所以我在团队里定了个规矩:重试必须带退避,且总重试次数不超过 3 次。
2.3 雪崩的形成过程(流程图)
下面这张图可以直观地看到雪崩怎样一步步蔓延。从左到右看,正常时流量均匀,一旦下游出问题,上游积累,最终全局崩溃。
整个过程其实很快,从第一个请求超时到全站不可用,可能只需要几十秒。我亲眼见过 Grafana 面板上错误率从 0% 瞬间跳到 100%,连预警都来不及发。
2.4 雪崩的量化指标
为了及时发现雪崩前兆,我习惯关注这几个关键指标。一旦它们出现异常,就要立刻干预。
- 错误率(Error Rate):5xx 比例持续超过 1%,需要警觉。
- 响应时间(P99):密钥接口 P99 超过基线 3 倍,说明已经开始排队。
- 线程池活跃数:接近最大线程数时,基本已经处于阻塞边缘。
- 连接池使用率:达到 80% 以上,新连接可能要等待。
- 重试次数:客户端重试次数突然增多,往往是被动触发。
我的实战建议:把密钥服务的线程池使用率和错误率做成聚合告警,两条同时触发时直接打 P0 电话。光一个指标波动可能是误报,两条一起动基本没跑。
2.5 一个真实案例的反思
几年前我负责一个支付平台的密钥服务。某次上线后,密钥缓存 TTL 设得太短,导致每分钟都有大量请求穿透到 HSM 硬件。硬件扛不住,开始超时。上游的订单服务、风控服务、通知服务都在同步等待,线程数猛涨。不到 3 分钟,整个集群 JVM 堆内存溢出了。
事后复盘,有三点教训:
- 没有设置调用超时:所有客户端都用的默认 60 秒超时,等于给雪崩留了充足的扩散时间。
- 没有限流机制:哪怕密钥服务自己扛不住,也该直接拒绝而不是傻傻排队。
- 没有熔断隔离:任何一个依赖方出问题,都会拖死整个调用链。
警告:千万不要以为密钥服务只在内网调用就不会崩。内网延迟再低,一旦流量爆发,或者硬件故障,效果跟外网是一样的。我曾经见过一个内网密钥服务因为磁盘 IO 打满,导致所有调用方阻塞,最后把整个微服务平台都拖挂了。
后来我们给所有依赖密钥服务的调用方加上了熔断器,配合超时和限流,再也没出过同级别的事故。下一个章节我会详细讲熔断降级的具体原理,这里先记住一件事:雪崩不是突如其来的,它有一连串的信号,关键是你有没有提前准备好手段去拦截它。