Appearance
Hello Sentinel
1. 快速开始
Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。
默认情况下 Sentinel 控制台配置的规则是在内存中的,所以我们需要 Nacos 来存储规则实现持久化。
1.1. Sentinel 核心库
在讲解如何使用 Nacos 存储规则之前,我们先来看下直接代码定义规则和资源的使用方式。
Sentinel 的使用步骤大致可以分为三步:
引入依赖
XML<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.6</version> </dependency>定义资源
使用
SphU.entry("resource_name")和entry.exit()将代码包围起来作为资源:Javapublic static void main(String[] args) { // 配置规则 initFlowRules(); while (true) { // 1.5.0 版本开始可以直接利用 try-with-resources 特性 try (Entry entry = SphU.entry("HelloWorld")) { // 被保护的逻辑 System.out.println("hello world"); } catch (BlockException ex) { // 处理被流控的逻辑 System.out.println("blocked!"); } } }也可以使用注解来定义资源:
Java@SentinelResource("HelloWorld") public void helloWorld() { // 资源中的逻辑 System.out.println("hello world"); }定义规则
Javaprivate static void initFlowRules(){ List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); rule.setResource("HelloWorld"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // Set limit QPS to 10. rule.setCount(10); rules.add(rule); FlowRuleManager.loadRules(rules); }这里定义了资源
HelloWorld每秒只能通过 10 个请求。
运行该 main 方法,可以看到控制台输出以下内容:
Log
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
blocked!
blocked!
blocked!
blocked!
...1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
可以看到请求通过 10 次打印 hello world 后再请求会阻塞打印 blocked!,等到下一秒才会继续打印 hello world。
1.2. Sentinel 控制台
Sentinel 控制台提供 Web 可视化页面配置规则,我们需要下载官方提供的 JAR 包安装启动该服务。
JAR 包下载:
可以从 Github release 页面下载最新版本的控制台 JAR 包。
启动脚本:
Bashjava -Dserver.port=8080 -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=sentinel -jar sentinel-dashboard.jar在 PowerShell 中执行
PowerShell 中命令行参数解析规则与 CMD 有所不同,尤其是在处理带有等号(
=)或特殊字符的参数(如-Dserver.port=8080)时,PowerShell 可能会将参数拆分或错误解析,导致 Java 无法正确识别这些参数。解决方案是在
java命令后添加--%操作符:PowerShelljava --% -Dserver.port=8080 -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=sentinel -jar sentinel-dashboard.jarPowerShell 提供
--%操作符,用于停止 PowerShell 的参数解析,并将后续内容直接传递给命令行工具。从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是
sentinel。所有可用的配置参数请参考 Sentinel 控制台官方说明文档。
客户端接入控制台:
客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信:
XML<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.8.6</version> </dependency>启动时加入 JVM 参数
-Dcsp.sentinel.dashboard.server=consoleIp:port指定控制台地址和端口。若启动多个应用,则需要通过-Dcsp.sentinel.api.port=xxxx指定客户端监控 API 的端口(默认是8719)。更多启动配置项参考官方说明文档。启动项目后需要访问一次资源才会向 Sentinel 控制台注册并发送心跳包。
查看机器列表以及健康情况:
访问 Sentinel 控制台
http://localhost:8080。可以在 Sentinel 控制台中对项目资源的规则进行管理,更多介绍请参考官方说明文档。
需要注意的是这里的控制台配置是内存态的,如果你的项目重新启动配置的规则就没了,所以我们需要一个可以持久化配置规则的地方,详情参考 Nacos 持久化存储 Sentinel 配置规则。
2. 使用文档
2.1. 流量控制
2.1.1. 阈值类型
- QPS:每秒最多允许请求多少次资源;
- 线程数:可以设置线程数,代表可以同时运行的线程数量。
2.1.2. 流控模式
直接:对资源 A 配置,统计 A 的 QPS,如果超过指定值,则限流 A 的调用;
关联:对资源 A 配置,关联资源 B。统计 B 的 QPS,如果 B 超过阈值,则限流 A 的调用;
链路:资源 A 可从入口 1 和入口 2 调用。链路模式配置在 A 上,指定入口 1。统计从入口 1 进入 A 的 QPS,如果超过阈值,则限流从入口 1 进入 A 的调用;从入口 2 进入的仍正常。
提示
Sentinel 默认启用 Web 上下文统一(Web Context Unification)功能,所有进入的 Web 请求会被统一命名为一个固定的上下文名称(通常是 sentinel_spring_web_context),不同的 URL 路径会被当作同一个资源来处理,适用于需要对整个 Web 应用进行统一限流的场景。
关闭 Web 上下文统一后,每个不同的 URL 路径会被识别为不同的资源,可以针对不同的 URL 路径设置不同的限流规则,适合更细粒度的流量控制。
Web 上下文统一功能会导致流控的链路模式失效,可以通过如下配置关闭该功能:
YAML
spring:
cloud:
sentinel:
web-context-unify: false1
2
3
4
2
3
4
2.1.3. 流控效果
快速失败:超过阈值后新的请求会被立即拒绝,拒绝方式为抛出
FlowException;Warm Up:让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间;
排队等待:让限流的请求排队等待系统空闲时再通过,需要配置超时时间,过了超时时间再拒绝请求。
2.2. 熔断降级
Sentinel 提供三种熔断策略:
慢调用比例(
SLOW_REQUEST_RATIO):设定最大响应时间(RT),超过则视为慢调用。当单位统计时间内请求数超过最小阈值且慢调用比例高于设定值时触发熔断,熔断结束后进入半开状态,根据下一个请求的响应时间决定是否恢复;异常比例(
ERROR_RATIO):设定异常比例阈值,当单位统计时间内请求数超过最小阈值且异常比例高于设定值时触发熔断。熔断结束后进入半开状态,若下一个请求成功则恢复,否则继续熔断;异常数(
ERROR_COUNT):设定单位统计时间内允许的最大异常数,超过则触发熔断。熔断结束后进入半开状态,若下一个请求成功则恢复,否则继续熔断。
信息
异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。
2.3. 热点参数限流
热点是指频繁访问的数据,如高频商品 Id 或用户 Id。热点参数限流用于统计并限制这些高频参数的访问,根据配置的阈值对包含热点参数的请求进行限流,是一种针对特定参数的精细化流量控制策略。
要使用热点参数限流功能,需要引入以下依赖:
XML
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>x.y.z</version>
</dependency>提示
热点参数限流对默认的 SpringMVC 资源无效,需要手动添加 @SentinelResource 注解。
2.4. 来源访问控制
在许多场景下,我们需要根据调用方的身份来控制资源的访问权限,这时可以利用 Sentinel 的黑白名单功能进行限制。黑白名单通过资源的请求来源(Origin)来决定是否允许访问:配置白名单时,只有来源在白名单内的请求才能通过;配置黑名单时,来源在黑名单内的请求会被拒绝,其余请求则允许通过。
Sentinel 通过 RequestOriginParser 接口来解析请求的来源(Origin):
Java
public interface RequestOriginParser {
String parseOrigin(HttpServletRequest request);
}我们可以使用客户端标识、IP 地址、用户 Id 等作为请求来源,例如从请求头中提取 origin 作为来源标识:
Java
@Component
public class CustomRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
String origin = request.getHeader("origin");
return StringUtils.isEmpty(origin) ? "anonymous" : origin;
}
}在 Gateway 中,我们可以通过网关的过滤器为请求添加 origin 头:
YAML
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=origin,PynaX2DV8VTHyTfngoiA1
2
3
4
5
2
3
4
5
通过这种方式,可以确保微服务中的服务仅允许通过 Gateway 发起的调用访问。
2.5. 自定义异常处理器
默认情况下,发生限流、熔断、授权拦截时,都会抛出异常到调用方。如果要自定义异常时的返回结果,需要实现 BlockExceptionHandler 接口:
Java
public interface BlockExceptionHandler {
void handle(HttpServletRequest request, HttpServletResponse response, BlockException e)
throws Exception;
}BlockException 包含很多子类,分别对应不同的场景:
FlowException限流异常;ParamFlowException热点参数限流异常;DegradeException降级异常;AuthorityException授权规则异常;SystemBlockException系统规则异常。
3. 适配整合
3.1. Spring Boot
Spring Boot 项目配置示例:
父项目
pom.xmlXML<properties> <spring-boot.version>2.7.6</spring-boot.version> <spring-cloud.version>2021.0.8</spring-cloud.version> <spring-alibaba-cloud.version>2021.0.6.0</spring-alibaba-cloud.version> </properties> <dependencyManagement> <dependencies> <!-- Spring Boot Dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Spring Cloud Dependencies --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Spring Cloud Alibaba Dependencies --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-alibaba-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>项目
pom.xmlXML<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>application.ymlYAMLspring: cloud: sentinel: transport: dashboard: DASHBOARD_HOST # eg: localhost:8080 port: 8719
3.2. Nacos 数据源
Sentinel 提供了多种数据源的支持,包括 Nacos、Zookeeper、文件数据源等。要使用 Nacos 作为 Sentinel 配置的数据源,需要先配置安装 Nacos,具体操作步骤可以参考这篇文章。
引入 Sentinel 的 Nacos 数据源依赖
XML<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>配置 Nacos 作为 Sentinel 的数据源
YAMLspring: cloud: sentinel: transport: dashboard: DASHBOARD_HOST # eg: localhost:8080 port: 8719 datasource: DATASOURCE_NAME: nacos: server-addr: SERVER_ADDR # eg: localhost:8848 data-id: RULE_NAME.json group-id: GROUP_ID data-type: json rule-type: flow1
2
3
4
5
6
7
8
9
10
11
12
13
14在 Nacos 中配置 Sentinel 规则
示例配置内容:
JSON[ { "resource": "/", "limitApp": "default", "grade": 1, "count": 2, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]
启动项目,配置好 Nacos 后,我们可以直接在 Sentinel 控制台看到 Nacos 的配置已经同步到 Sentinel 控制台了,并且规则已经生效了,以后该规则只需要在 Nacos 配置规则就能实时生效了。
提示
目前只支持 Nacos 规则同步到 Sentinel 控制台,不支持在 Sentinel 控制台配置规则同步到 Nacos。
提示
目前暂不支持通配符和正则表达式去匹配资源名称。
3.3. Feign 客户端
为启用 Sentinel 对 Feign 的支持,以实现对 Feign 的调用进行流量控制、熔断降级等功能,我们需要将 feign.sentinel.enabled 设置为 true:
YAML
feign:
sentinel:
enabled: true启用 Sentinel 对 Feign 客户端的支持后,Feign 调用会被 Sentinel 自动保护为资源,从而可以限制 Feign 接口的调用频率、线程数等。资源名默认格式为 HTTP_METHOD:PROTOCOL://URL(例如,GET:http://service-name/api/path)。
当 Feign 客户端调用远程服务失败(如超时、网络异常等)时,可以通过 FallbackClass 和 FallbackFactory 机制来触发备用逻辑(如:实现熔断降级):
FallbackClass:用于指定一个简单的降级类。这个类必须实现 Feign 客户端接口的所有方法,并在调用失败时执行对应方法的备用逻辑。它适合不需要捕获异常信息的简单降级场景;
假设有一个 Feign 客户端接口 UserClient:
Java@FeignClient(name = "user-service", fallback = UserFallback.class) public interface UserClient { @GetMapping("/user/{id}") User getUserById(@PathVariable("id") Long id); }1
2
3
4
5对应的降级类 UserFallback:
Java@Component public class UserFallback implements UserClient { @Override public User getUserById(Long id) { User user = new User(); user.setId(id); user.setName("默认用户"); return user; } }1
2
3
4
5
6
7
8
9
10当调用
getUserById失败时,会自动调用UserFallback中的getUserById方法。FallbackFactory:是一个工厂类,用于动态创建降级实例。它比 FallbackClass 更灵活,因为其
create方法可以接收Throwable参数,从而捕获调用失败的具体异常信息,并据此提供更智能的降级逻辑(如记录日志、返回不同响应)。使用相同的
UserClient接口:Java@FeignClient(name = "user-service", fallbackFactory = UserFallbackFactory.class) public interface UserClient { @GetMapping("/user/{id}") User getUserById(@PathVariable("id") Long id); }1
2
3
4
5对应的工厂类
UserFallbackFactory:Java@Component public class UserFallbackFactory implements FallbackFactory<UserClient> { private static final Logger logger = LoggerFactory.getLogger(UserFallbackFactory.class); @Override public UserClient create(Throwable cause) { logger.error("Feign 调用失败: ", cause); return new UserClient() { @Override public User getUserById(Long id) { User user = new User(); user.setId(id); user.setName("降级用户(原因:" + cause.getMessage() + ")"); return user; } }; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18当调用失败时,
create方法会先执行(传入异常),然后调用返回的实例的方法。