一句话先澄清
Spring Boot 原生本身没有熔断 / 舱壁 / 限流保护机制! Spring Boot 只提供基础的异常捕获、Web 容器线程池、优雅关闭;真正让服务不雪崩、不宕机的弹性保护(熔断、舱壁、限流)是 Resilience4j / Sentinel / Hystrix 这类组件,Spring Cloud 做了自动装配整合到 SpringBoot 应用里。
服务 "不宕机" 不是保证永远不出错,而是:局部故障不会耗尽全局资源,故障不会连锁扩散,核心接口继续可用。
一、SpringBoot 原生自带基础保护(底层底座)
1. Tomcat 内嵌容器线程池隔离
SpringBoot Web 默认内嵌 Tomcat,有固定大小的容器线程池处理 HTTP 请求。 原理:
- 所有 HTTP 请求从 Tomcat 线程池拿线程;
- 线程池有最大线程数 + 队列上限;
- 当请求量打爆上限,新请求直接拒绝(Connection refused),不会无限创建线程导致 OOM 。 局限:全局共享同一个 Tomcat 线程池。如果某个下游接口慢、阻塞,会把 Tomcat 线程全部占满,所有接口全部卡死,服务雪崩。👉 这就是为什么需要额外弹性组件。
2. 全局异常捕获(@RestControllerAdvice)
SpringMVC 全局异常处理器,捕获 Controller 层异常,不让异常直接抛到 JVM 导致进程退出。
- 业务异常、外部调用异常被 catch,返回友好响应;
- 但是:阻塞线程、死锁、OOM、内存泄漏,全局异常捕获救不了。
3. 优雅关闭 server.shutdown=graceful
收到停止信号时:
- 停止接收新请求;
- 等待正在处理的请求执行完毕(超时时间);
- 再销毁 Bean、关闭连接池,避免请求中途被强行打断。
4. JVM + Spring 容器基础保护
- Spring Bean 生命周期、连接池(Druid/HikariCP)自带最大连接限制,防止数据库连接打爆;
- JVM OOM killer、内存参数只是兜底,不属于业务保护机制。
二、弹性保护组件(Resilience4j / Sentinel,SpringBoot 集成)【核心,防止雪崩】
四大核心机制:舱壁隔离 Bulkhead、熔断 CircuitBreaker、限流 RateLimiter、重试 Retry
1. 舱壁 Bulkhead(最关键:防止一个慢依赖吃光全局线程)
船舶水密舱:一个舱漏水,船不沉。两种实现:
- 线程池隔离(Hystrix 经典) :给每一个下游调用单独创建独立线程池。调用慢、阻塞只会耗尽这个独立线程池,不会占用 Tomcat 主线程池,其他接口不受影响。缺点:线程上下文切换开销大。
- 信号量隔离(Resilience4j 默认常用):不新建线程,限制最大并发数。使用 Tomcat 线程,但限制最多 N 个并发去调用这个下游;超过并发直接走 fallback,适合轻量同步调用,开销小Spring。
✅ 作用:资源隔离,单个依赖故障,不耗尽整个服务资源。
2. 熔断 CircuitBreaker(断路器)
状态机:关闭 CLOSED → 打开 OPEN → 半开 HALF_OPEN阿里云开发...
- CLOSED:正常放行,统计失败率(滑动窗口统计);
- 失败率超过阈值(例如 50%) → OPEN:直接跳过远程调用,立刻执行降级 fallback;不再去调用故障下游,避免大量线程卡在等待超时;
- OPEN 等待一段时间 → HALF_OPEN:放少量探测请求,测试下游是否恢复;探测成功→CLOSED;失败重新 OPEN。
✅ 作用:切断故障链路,防止大量超时请求占满线程,雪崩。
3. 限流 RateLimiter
限制单位时间内允许通过的请求数量,超出直接快速失败,保护服务整体 CPU / 内存,应对突发流量。
4. Retry 重试
短暂瞬时故障(网络抖动)自动重试;配合熔断,重试失败才计入失败指标;不会无限重试。
5. Fallback 降级兜底
熔断 / 舱壁满 / 限流触发时,不走原始逻辑,执行兜底方法:返回缓存数据、默认值,保证接口能正常返回,不是报错 500。
三、完整链路:为什么这样就能做到服务不宕机?
故障场景举例:订单服务调用商品服务,商品服务挂了、响应很慢
- 调用商品接口打上
@Bulkhead + @CircuitBreaker; - 商品接口变慢,请求不断堆积;舱壁限制最多 20 个并发访问商品接口;
- 超过 20 并发,直接 fallback,不会继续占用 Tomcat 线程;
- 持续失败达到阈值 → 熔断打开;后续请求不再发起远程调用,直接降级返回缓存;
- Tomcat 主线程池没有被阻塞耗尽,支付、用户等其他核心接口正常接收请求;
- 故障被限制在「商品调用」这个舱内,不会扩散到整个应用,服务整体不宕机。
⚠️ 边界:这套保护不能防止 JVM OOM、死锁、内存泄漏、CPU 打满、数据库整体宕机 。这些场景依然会让服务挂掉。弹性保护是防止分布式调用雪崩,不是万能护身符。
四、SpringBoot + Resilience4j 极简代码示例
java
@Service
public class OrderService {
// 舱壁+熔断+降级
@CircuitBreaker(name = "productService", fallbackMethod = "getProductFallback")
@Bulkhead(name = "productService")
public String getProductInfo(Long productId){
return restTemplate.getForObject("http://product/"+productId,String.class);
}
// 降级兜底
public String getProductFallback(Long productId, Exception e){
log.error("调用商品服务异常",e);
return "缓存商品信息";
}
}
五、原生 SpringBoot 和 Resilience4j 保护对比表
表格
| 能力 | SpringBoot 原生 | Resilience4j/Sentinel |
|---|---|---|
| Tomcat 线程池 | ✅全局共享 | ✅舱壁隔离(分组资源隔离) |
| 异常捕获 | ✅全局异常 | ✅捕获并统计失败指标 |
| 熔断 | ❌无 | ✅状态机熔断,切断故障调用 |
| 限流 | ❌无 | ✅QPS 限流 |
| 降级 Fallback | ❌需要自己手写 | ✅注解式兜底 |
| 防止依赖拖垮全局 | ❌不能 | ✅核心能力 |
| 优雅关闭 | ✅支持 | 不冲突,配合使用 |
六、面试一句话总结版(背这个)
SpringBoot 本身只提供 Tomcat 线程池、全局异常、优雅关闭等基础能力,原生不具备熔断隔离能力 。要做到服务不雪崩,需要集成 Resilience4j/Sentinel:通过舱壁隔离把不同下游调用资源分开,避免慢依赖耗尽全局线程;熔断器统计失败率,故障达到阈值后切断调用,执行降级兜底;配合限流、重试,让局部故障不会扩散,保障核心接口可用,从而避免服务整体宕机。