在微服务架构中,如果某个服务中的一个接口因网络故障、资源瓶颈或其他异常原因变得不可用,而此时仍有大量请求持续涌入该接口,就可能导致该服务所依赖的线程池或连接池(如 Tomcat 的线程资源)被迅速耗尽。一旦关键资源被占满,不仅该接口无法响应,整个服务中的其他正常接口也可能因无法获取必要资源而相继失效。
更严重的是,若该服务还需调用其他下游微服务,其自身的瘫痪会进一步传导至依赖它的上游或下游服务,引发连锁反应,最终导致多个微服务大面积不可用------这种现象被称为"服务雪崩"(Service Avalanche)。
要有效应对微服务中的雪崩问题,通常可采用以下三种核心策略:
- 请求限流(Rate Limiting):通过限制单位时间内进入系统的请求数量,防止突发流量压垮服务,保障系统在高负载下的稳定性。
- 线程隔离(Thread Isolation):将不同接口或服务调用分配到独立的线程池中,避免某个慢接口或故障服务耗尽整个应用的线程资源,从而保护其他功能正常运行。
- 服务熔断(Circuit Breaking):当某个服务的失败率超过阈值时,自动"熔断"对该服务的调用,在一段时间内快速失败而不发起实际请求,既减轻下游压力,也为故障恢复争取时间。
1. Sentinel
1. 安装
Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中,我们可以使用 Sentinel 轻松解决服务雪崩问题。
需要再虚拟机中部署。
点击下面连接下载对应的 jar 包:
sentinel-dashboard
https://github.com/alibaba/Sentinel/releases也可以使用下面网盘中的 jar 包
下载好后将其放在没有中文路径的目录下,注意文件名改为 sentinel-dashboard.jar,打开命令行,执行下面命令:
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
访问 http://localhost:8090/ 页面进行登录,用户和密码默认都为 sentinel
2. 微服务整合
1. 引入依赖
在项目的 pom.xml 中添加 Sentinel 的 Spring Cloud Starter 依赖:
XML
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2. 配置 Sentinel 控制台地址
在 application.yml(或 application.yaml)中配置 Sentinel Dashboard 的地址:
XML
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
启动应用后,首次访问任意被 Sentinel 监控的接口,Sentinel 客户端会自动将该服务的调用信息上报到 sentinel-dashboard 控制台。
进入 Sentinel Dashboard,点击对应的服务,在 「簇点链路」 页面即可看到刚刚访问的接口。

说明:「簇点链路」展示的是单机维度的调用链路,即一次请求进入服务后所经过的、被 Sentinel 监控的资源节点。默认情况下,Sentinel 会自动监控 Spring MVC 中的所有 Controller 接口,并将其注册为资源。
针对这些资源,我们可以灵活配置限流规则、熔断策略、隔离机制等服务保护措施。

可开启 HTTP 前缀识别功能
在 RESTful 风格的 API 设计中,同一个路径(如 /api/users)可能对应多种 HTTP 方法(如 GET 查询、POST 新增、PUT 更新、DELETE 删除)。默认情况下,Sentinel 仅以 URL 路径作为资源名称,会将不同 HTTP 方法的请求视为同一个资源,从而无法进行细粒度控制。
为解决此问题,可开启 HTTP 方法前缀识别功能,在配置文件中添加如下设置:
XML
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
http-method-specify: true # 开启 HTTP 方法前缀,使资源名包含请求方法
启用该配置后,Sentinel 会将资源名称格式化为 HTTP_METHOD:/path(例如 GET:/api/users、POST:/api/users),从而实现对每个 RESTful 接口的精准识别与独立管控。
2. 请求限流
接下来就可以通过 sentinel 进行限流控制,点击流按钮,

在单机阈值中设置想要限制的请求数量,便可轻松实现请求限流。

3. 线程隔离
线程隔离 (在 Sentinel 中通常体现为 并发控制)的核心作用是:为服务中的每个受保护资源(例如一个 HTTP 接口或一次远程调用)限定其最大并发请求数(即同时执行的线程数),从而防止单个慢接口或故障调用因响应延迟或超时而长时间占用系统资源(如 Tomcat 线程池),进而导致整个服务的其他正常接口也无法响应------即避免"局部故障引发全局雪崩"。
在微服务场景中,线程隔离最常用于保护本服务在调用下游依赖时的安全性。当下游服务响应缓慢或不可用时,若不加以限制,大量请求会阻塞在等待下游响应的过程中,迅速耗尽本服务的线程资源,最终导致上游服务完全卡死。
要让 Sentinel 对 Feign 客户端发起的下游调用生效,需在配置文件中显式启用 Feign 与 Sentinel 的集成:
XML
feign:
sentinel:
enabled: true # 启用 Feign 与 Sentinel 的集成
启用后,Sentinel 会自动将每个 Feign 接口方法注册为独立的资源(例如 GET:http://order-service/orders/{id}),你便可以在 Sentinel Dashboard 中对该资源配置流控或熔断规则。
在 Sentinel 中配置线程隔离策略非常简单:
- 在流控规则中,将 阈值类型 从默认的 "QPS" 改为 "并发线程数"(对应常量 FLOW_GRADE_THREAD)
- 并设置一个合理的并发上限值(例如 10)
当该资源的当前并发请求数达到阈值时,后续新请求将被立即拒绝(抛出 FlowException),不再进入实际调用逻辑,从而有效限制资源占用,实现对下游依赖的隔离保护。
虽然常被称为"线程隔离",但 Sentinel 实际采用的是信号量机制(基于并发计数),而非为每个接口创建独立线程池,因此开销更低、性能更高。
4. 服务熔断
当请求因限流或者资源耗尽导致资源访问不到,当服务访问失败率过高就需要触发熔断,直接拒接访问这个接口,这个时候,就需要更加业务需要返回错误提示,或者默认数据,这就称之为降级逻辑。
1. 编写降级逻辑
1. 降级逻辑:提升系统容错能力与用户体验
当请求因限流 或资源耗尽 (如并发超限)而被拒绝,或者因下游服务持续失败导致访问成功率过低 时,Sentinel 会触发熔断机制,直接拒绝后续请求以防止故障扩散。此时,若直接向用户返回"服务不可用"或异常堆栈,体验较差。
为此,我们通常会提供降级逻辑(Fallback):在服务不可用时,返回默认值、缓存数据或友好提示,既保障系统稳定性,又提升用户体验。
2. 为 Feign Client 配置降级逻辑
在 Spring Cloud Alibaba + Sentinel 的体系中,为 Feign 接口配置降级逻辑有两种方式,其中推荐使用 FallbackFactory,因为它能捕获具体的异常信息,便于日志记录和问题排查。
3. 场景示例
假设我们在 api-service 模块中通过 Feign 调用 user-service 的用户积分查询接口:
java
@FeignClient(name = "user-service")
public interface UserClient {
/**
* 查询用户积分
* @param pw
* @param amount
*/
@GetMapping("/users/integral/inquire")
Integer inquireIntegral(@RequestParam("pw") String pw);
}
步骤 1:实现 FallbackFactory
在 api 模块中创建专门存放降级逻辑的类,例如 fallback/UserClientFallback.java:
java
@Slf4j
public class UserClientFallback implements FallbackFactory<UserClient> {
@Override
public UserClient create(Throwable cause) {
return new UserClient() {
@Override
public Integer InquireIntegral(String pw) {
log.error("查询用户积分失败", cause);
// 查询失败后返回默认积分 0
return 0;
}
};
}
}
步骤 2:在 FeignClient 中关联降级类
java
@FeignClient(value = "user-service",
fallbackFactory = UserClientFallback.class)
public interface UserClient {
/**
* 查询用户积分
* @param pw
* @param amount
*/
@GetMapping("/users/integral/inquire")
Integer InquireIntegral(@RequestParam("pw") String pw);
}
工作流程说明
- 当 api-service 调用 user-service 的 /users/integral/inquire 接口时;
- 若因网络故障、超时或服务宕机导致连续失败;
- Sentinel 根据配置的熔断规则(如异常比例 > 50%)触发熔断;
- 后续请求不再真正发起远程调用,而是直接执行 UserClientFallback 中的降级逻辑;
- 返回默认值 0,避免系统崩溃,同时保证业务流程继续。
2. 熔断
熔断操作也可以在 Sentinel 进行配置,点击熔断之后就会弹出下面窗口:

然后就可以在这里进行配置内容。

这种是按照慢调用比例来做熔断,上述配置的含义是:
-
RT超过200毫秒的请求调用就是慢调用
-
统计最近1000ms内的最少5次请求,如果慢调用比例不低于0.5,则触发熔断
-
熔断持续时长20s
总结
"好的系统不是永不失败,而是在失败时依然可控。"