如何应对服务雪崩?详解 服务降级与服务熔断

在微服务、分布式系统架构下,"服务雪崩"几乎是所有架构师和后端工程师都会面对的问题。一次偶发的慢查询、一个下游依赖的异常,就可能引发连锁反应,最终拖垮整个系统。

服务雪崩

服务雪崩是指:在分布式系统中,一个或多个下游服务出现异常(变慢、不可用),导致上游服务请求线程大量阻塞、堆积,进而上游服务也变慢甚至崩溃,最终使一系列服务都不可用的"连锁故障"现象。

典型过程:

  1. 某个核心服务 A 依赖多个下游服务 B、C、D。
  2. 由于网络抖动、DB 慢查询、GC 卡顿等原因,服务 B 响应突然变慢。
  3. 服务 A 发往 B 的请求线程开始大量阻塞,连接池占满、线程池打满。
  4. A 自身延时飙升,CPU 飙高,进而超时/失败率上升。
  5. 上游还依赖 A 的其他服务(如网关、其他业务服务)同样出现阻塞、资源耗尽,最终一大片服务连锁宕机。

触发因素常见有:

  • 下游服务宕机或不可达(网络、机房、DNS 等)
  • 下游服务响应极度变慢(慢查询、锁竞争、GC、磁盘 IO 等)
  • 流量突增,超过容量上限(热点活动、恶意攻击)
  • 配置错误(超时时间过长、重试次数过大等)

要想系统具备"韧性(Resilience)",就必须在架构与代码层面对"雪崩"进行防御。服务降级服务熔断就是关键手段。

服务降级

什么是服务降级?

服务降级指:在系统高压力、依赖不可用或故障场景下,主动降低非核心功能的服务质量,牺牲部分体验或功能,以保证核心能力可用、整体系统存活。

一句话:"宁可部分功能不可用,也要保证核心路径不死"

典型场景

  • 下游服务不可用或严重超时(比如推荐服务挂了)
  • 总体 QPS 暴涨,系统即将被压垮
  • 批量任务/非核心功能影响主链路
  • 节假日大促、预估流量高峰期,需要预防性降级

典型策略

可以按是否可预期是否自动触发来划分:

(1)预案式、人工开关降级

针对重要活动或核心业务,预先设计好降级策略和"开关":

  • 提前准备降级配置(如:关掉非必要查询、合并订单信息、关闭部分个性化功能)
  • 通过配置中心/管理后台,一键开关降级
  • 适合集中流量、高风险活动场景(双 11、大促)

(2)自动化降级(基于系统指标触发)

系统监控的关键指标达到阈值时自动触发,如:

  • CPU 超过 80%
  • 平均响应时间(RT)超过某个阈值
  • 错误率/超时率超过一定比例

降级返回内容的设计

降级不是简单"抛异常",而是要提供可接受的退路,常见策略:

  1. 返回默认值或兜底文案

  2. 使用缓存或静态数据

  3. 部分字段为空、隐藏功能

服务熔断

什么是服务熔断?

服务熔断(Circuit Breaker)借鉴的是电路中的"保险丝"概念:当调用某个下游服务错误率过高时,主动短路后续请求,不再继续向下游发起真实调用,而是快速失败或走降级逻辑,以保护自己和下游服务。

目的:避免在下游已经不健康的情况下继续大量消耗资源、放大故障。

熔断器的三种状态

典型的熔断模型(如 Hystrix、Resilience4j)包含三种状态:

  1. Closed(关闭)状态

    • 说明当前依赖服务健康
    • 所有请求正常透传到下游
    • 但会持续统计调用的错误率、RT 等指标
  2. Open(打开)状态

    • 一段时间内错误率达到阈值(例如:10 秒内请求超过 100 次且错误率 > 50%)
    • 熔断器"打开",直接拒绝请求或走降级逻辑
    • 不再真正调用下游,快速失败,减轻自身与下游压力
  3. Half-Open(半开)状态

    • 经过一段"冷静期"(如 5 秒、10 秒)后
    • 熔断器进入半开,只放行少量"探测请求"到下游
    • 若探测请求成功率较高 → 认为下游恢复 → 切回 Closed
    • 若继续大量失败 → 重新回到 Open,继续熔断

熔断与超时、重试的关系

  • 超时控制:防止单次调用长时间占用线程,是熔断的基础。
  • 重试机制:在可恢复、幂等的场景下可以适度重试,但过多重试会加剧雪崩。
  • 熔断:在错误率"持续偏高"时,从整体上限制调用,防止进一步加压。

常见错误做法:

  • 超时时间配置过长(例如 HTTP 客户端默认 30s)
  • 重试次数太多(如同步接口自动重试 3~5 次)
  • 没有熔断,导致所有服务都去死扛一个已经"挂掉"的依赖

服务降级服务熔断的区别与协同

很多人会把"降级"和"熔断"混为一谈,它们确实密切相关,但重点不同:

核心区别

维度 服务降级 服务熔断
出发点 在高压或故障场景下降低系统负载、保证核心可用 保护调用方和被调方,避免故障持续放大
触发依据 系统整体负载、手动开关、业务策略 特定依赖的错误率、超时率、RT 等
作用范围 可全局(某业务域)、也可单接口 通常针对"某个下游依赖"
返回内容 一般是"降级结果"(缓存/默认值/空结果等) 多为快速失败,但常与降级同时使用
粒度 更偏"业务策略级" 更偏"技术防护级"

简单理解:

  • 熔断更像"防火墙":检测到下游不健康就断路。
  • 降级更像"备用预案":当情况不佳时用次优方案维持运行。

实战中的协同方式

一个典型链路:

  1. 调用下游服务前,先检查是否已熔断。
    • 若已熔断(Open)→ 直接走"降级处理"(本地缓存、默认值等)。
    • 若未熔断(Closed/Half-Open)→ 发起远程调用。
  2. 调用失败或超时时,由熔断器统计错误。
  3. 在错误率持续高的情况下,熔断器会打开,并自动把后续请求引导到"降级逻辑"。

因此:熔断负责"何时不再调用下游",降级负责"在不调用下游时返回什么"。

相关推荐
liwulin05061 小时前
【JAVA】AES加密
java
阿宁又菜又爱玩1 小时前
Maven基础知识
java·maven
S***q3771 小时前
【Springboot】@Autowired和@Resource的区别
java·spring boot·mybatis
南部余额1 小时前
SpringBoot自定义场景启动器
java·spring boot·场景启动器
p***s911 小时前
【SpringBoot】日志文件
java·spring boot·spring
z***D6481 小时前
SpringBoot 新特性
java·spring boot·后端
冷雨夜中漫步1 小时前
Maven BOM(Bill of Materials)使用指南与常见错误
java·数据库·maven
客梦1 小时前
Java教室管理系统
java·笔记