Sentinel分布式系统的流量防卫兵
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以通过HTTP/RPC相互调用,在Spring cloud中可以用 RestTemplate + LoadBalanceClient 和 Feign来调用。为保证1其高可用,单个服务通常会集群部署。由于网络原因或自身的原因,服务并不能保证100%可用,如果单个服务出问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,servlet容器的线程资源会被消耗完毕,导致服务瘫痪,服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩” 效应。为了解决这个问题,业界提出了 熔断器模型。
一、 基本概念
1.1 流量控制 (Flow Control)
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制,Sentinel 作为一个调配器,可以根据需要把随机的请求整合成合适的形状。
Sentinel以流量为切入点,从流量控制,熔断降级,系统负载保护,等多个角度维护服务的稳定性。
流量控制有以下几个角度:
- 资源的调用关系:例如资源的调用链路,资源和资源之间的关系。
- 运行指标:例如 QPS、线程池、系统负载等。
- 控制的效果:例如直接限流、冷启动(WarmUp)、排队等。
Sentinel的特征:
- 丰富的应用场景:
- Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷(对于突然到来的大量请求,您可以配置流控规则,以稳定的速度逐步处理这些请求,从而避免流量突刺造成系统负载过高)、集群流量控制、实时熔断下游不可用应用等
- 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况
- 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架 / 库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel
- 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等
1.2 熔断降级 (Circuit Breaking)
除了流量控制以外,及时对调用链路中不稳定的因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
Sentinel 和 Hystrix 的原则是一致的:当检测到调用链路中某个资源出现不稳定的表现(例如请求响应时间长或异常比例升高)的时候,(对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
Sentinel 熔断降级设计理念:
- 并发线程数限制: 和资源池隔离(Hystrix 采用的方式)不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要预先分配线程池的大小。当某个资源出现不稳定的情况下(如响应时间变长),对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
- 响应时间降级: 除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
二、 基本使用
2.1 Spring Boot 集成
1. 引入依赖
<!-- Sentinel 核心依赖 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.5.RELEASE</version>
</dependency>
2. 定义资源 (@SentinelResource)
@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。
| 属性名 | 说明与配置规则 |
|---|---|
| value | 资源名称,必填项。这是 Sentinel 控制台配置规则时引用的唯一标识。 |
| blockHandler / blockHandlerClass | 处理 Sentinel 规则限制触发的异常 (BlockException),如限流、熔断。 1. 修饰符必须是 public。 2. 返回值必须与原方法匹配。 3. 参数必须与原方法匹配,且最后加一个 BlockException 参数。 4. 默认在同一个类中,若使用 blockHandlerClass 指向其他类,则函数必须是 static。 |
| fallback / fallbackClass | 处理程序运行异常(Java 运行时异常)。 1. 作用范围:针对所有类型的异常(除了 exceptionsToIgnore 中排除的)。 2. 返回值必须与原函数一致。 3. 参数与原函数一致,或者可以额外多一个 Throwable 参数。 4. 若指定 fallbackClass,函数必须为 static。 |
| defaultFallback | 默认的通用 fallback 逻辑。 1. 参数列表需要为空,或者可以额外多一个 Throwable 参数。 2. 优先级低于 fallback。 |
| exceptionsToIgnore | 指定哪些异常被排除,不会计入异常统计,也不会进入 fallback 逻辑,原样抛出。 |
辨析 BlockHandler vs Fallback:
- BlockHandler: 违反 Sentinel 规则(限流/熔断) -> 捕获
BlockException。 - Fallback: 程序代码抛错(NPE/RunTimeException) -> 捕获
Throwable。
代码示例:
@RestController
public class DriverController {@SentinelResource(value = "info", blockHandler = "blockExHandler")@RequestMapping(value = "/info/{id}")public Driver info(@PathVariable(value = "id") String id) throws BlockException {// 模拟业务逻辑if ("0".equals(id)) {throw new RuntimeException("系统异常"); // 会走 fallback(如果配置了的话),或者直接报错}return driverService.findById(id);}/*** info 资源出现 BlockException 后的降级处理*/public Driver blockExHandler(String id, BlockException e) {Driver driver = new Driver();driver.setId(id);driver.setName("系统繁忙, 被 Sentinel限流了, 稍后再试");return driver;}
}
2.2 集成 OpenFeign
1. 开启 Feign 对 Sentinel 的支持
在 application.yml 中配置:
feign:sentinel:enabled: true
2. 创建 FallbackFactory
推荐使用 FallbackFactory,因为它可以获取到具体的异常信息。
@Component
public class DriverFeignFallbackFactory implements FallbackFactory<DriverFeign> {@Overridepublic DriverFeign create(Throwable throwable) {return new DriverFeign() {@Overridepublic Driver status(String id, Integer status) {Driver driver = new Driver();driver.setId(id);driver.setName("Feign 降级:系统比较繁忙,请您稍后再试!错误信息:" + throwable.getMessage());return driver;}};}
}
3. 在 FeignClient 中指定
@FeignClient(name = "hailtaxi-driver", fallbackFactory = DriverFeignFallbackFactory.class)
public interface DriverFeign {@PutMapping(value = "/driver/status/{id}/{status}")Driver status(@PathVariable(value = "id") String id, @PathVariable(value = "status") Integer status);
}
2.3 集成 Gateway
Sentinel 支持对 Spring Cloud Gateway 网关进行网关流控(针对 Route ID 或 API 分组)。
1. 引入依赖
<!-- Sentinel 适配 Gateway 的依赖 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!-- Sentinel 核心 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2. 配置自定义异常处理 (BlockRequestHandler)
网关限流默认返回文本,生产环境通常需要返回 JSON。
@Configuration
public class GatewaySentinelConfig {@PostConstructpublic void doInit() {BlockRequestHandler blockRequestHandler = (exchange, t) -> {Map<String, Object> map = new HashMap<>();map.put("code", 429);map.put("message", "网关限流:请求太快,请稍后重试");return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}
}
3. 初始化规则 (示例)
// 针对路由ID "order_route" 限流
GatewayFlowRule rule = new GatewayFlowRule("order_route").setCount(1).setIntervalSec(1);
GatewayRuleManager.loadRules(Collections.singleton(rule));
三、 规则详解
3.1 流量控制规则
核心属性:
| 属性 | 说明 |
|---|---|
| resource | 资源名 (唯一标识)。 |
| count | 限流阈值。 |
| grade | 阈值类型:QPS (1) 或 并发线程数 (0)。 |
| strategy | 流控模式:直接、关联、链路。 |
| controlBehavior | 流控效果:快速失败、WarmUp (预热)、排队等待 (匀速排队)。 |
Strategy 流控模式说明:
- 直接 (Direct): 自身请求达到阈值,直接限流。
- 关联 (Related): 当关联的资源(RefResource)达到阈值时,限流自己。适用于:支付接口达到阈值,限流下订单接口(优先保证核心业务)。
- 链路 (Chain): 只记录指定入口(Context)进来的流量。如果从入口 A 进来调用 C 达到阈值则限流,从入口 B 进来调用 C 不限流。
ControlBehavior 流控效果说明:
- 快速失败: 直接抛出异常。
- WarmUp: 冷启动。当流量突然激增,让通过的流量在
warmUpPeriodSec时间内缓慢增加至阈值,防止系统被压垮。 - 排队等待: 漏桶算法。让请求以均匀的速度通过,多余请求排队,超时则丢弃。
3.2 熔断降级规则
熔断降级基本概念:监控一些请求的异常情况或完成调用的时间,当在单位时间内达到阈值即触发降级
| 属性 | 说明 |
|---|---|
| resource | 资源名,即规则的作用对象 |
| grade | 熔断策略:慢调用比例、异常比例、异常数。 |
| count | 阈值(根据 grade 不同而定)。 |
| timeWindow | 熔断时长 (秒)。熔断触发后,在此时间内拒绝所有请求。 |
| minRequestAmount | 最小请求数(默认5)。只有单位时长内请求数 > 这个值,才会计算比例。 |
| statIntervalMs | 统计时长 (ms)。 |
熔断策略详解:
- 慢调用比例 (SLOW_REQUEST_RATIO):
- 需设置
MaxAllowedRt(最大响应时间)。 - 若 请求RT >
MaxAllowedRt,记为慢调用。 - 触发条件:请求数 >
minRequestAmount且 慢调用比例 >count。
- 需设置
- 异常比例 (ERROR_RATIO):
- 触发条件:请求数 >
minRequestAmount且 异常比例 >count(0.0~1.0)。
- 触发条件:请求数 >
- 异常数 (ERROR_COUNT):
- 触发条件:异常数 >
count。
- 触发条件:异常数 >
3.3 系统保护规则
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的Load,CPU使用率、总体平均RT、入口QPS和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
| 指标 | 说明 |
|---|---|
| Load (仅仅 Linux) | 当系统 load1 (1分钟负载) > 阈值,且并发线程数 > 系统容量时触发。 |
| RT | 单台机器所有入口流量的平均 RT > 阈值。 |
| 线程数 | 单台机器所有入口流量的并发线程数 > 阈值。 |
| 入口 QPS | 单台机器所有入口流量的 QPS > 阈值。 |
| CPU 使用率 | 机器 CPU 使用率 > 阈值 (0.0~1.0)。 |
3.4 访问控制规则
用于实现黑白名单控制。
-
前提:获取 Origin (来源)。
默认 origin 解析为空,需自定义实现
RequestOriginParser接口,并注册为 Bean:@Component public class MyOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {return request.getParameter("source"); // 例如 ?source=appA} } -
授权规则,即黑白名单规则(AuthorityRule)非常简单,主要是以下配置:
- resource:资源名,即规则作用对象
- limitApp:对应黑名单/白名单,不同origin用
逗号分隔,填写来源标识(如appA)。 - Strategy: 限制模式,WHITE (白名单,只允许 appA),BLACK (黑名单,拒绝 appA)。
3.5 热点参数规则
针对资源中的特定参数进行限流(例如:针对 ID 为 1 的商品进行限流,ID 为 2 的不限流)。
必须引入额外依赖:
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-parameter-flow-control</artifactId>
</dependency>
配置说明:
-
参数索引 (ParamIdx): 第几个参数(0, 1, 2…)。
-
单机阈值: 默认的限流阈值。
-
参数例外项 (Exception Items):
特殊值处理。
- 例如:参数索引 0,默认阈值 100。
- 例外项:当参数值为 “vip” 时,阈值设为 500。
四、 安装教程 (Sentinel Dashboard)
Sentinel 控制台用于可视化监控和规则管理。
4.1 服务端安装
-
下载
前往 GitHub Release 下载sentinel-dashboard-x.x.x.jar。 -
启动
使用 Java 命令启动(建议指定端口,避免冲突):
java -Dserver.port=8858 -jar sentinel-dashboard-1.8.6.jar- 默认用户名/密码:
sentinel / sentinel
- 默认用户名/密码:
-
访问
浏览器打开http://localhost:8858。
4.2 客户端连接配置
在微服务的 application.yml 中添加配置,使其连接到控制台。
spring:application:name: my-app-service # 必填,用于控制台显示服务名cloud:sentinel:transport:dashboard: localhost:8858 # 控制台地址port: 8719 # 客户端监控API端口(如果被占用会自动+1)eager: true # 饥饿加载,启动时直接向控制台发送心跳(可选)
注意事项:
- 懒加载机制: 默认情况下,启动服务后控制台是空的。你需要先请求一次该微服务的接口,触发 Sentinel 初始化,服务才会出现在控制台中。
- 规则丢失问题: 默认在控制台配置的规则是保存在内存中的,服务重启后规则会消失。生产环境需要配置 规则持久化(如集成 Nacos)。