1. 背景
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
1. Sentinel 介绍
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。
1.1 知识
Sentinel 的组成:
- (1) Sentinel 核心库, 即基本的类库的使用。
- (2) Dashboard 控制台,即web页面的使用。
核心库介绍
本章节主要说 核心库 的使用。
使用 Sentinel 来进行资源保护,主要分为几个步骤:
- 定义资源
- 定义规则
- 检验规则是否生效
也就是说:
- 先把可能需要保护的资源定义好(即埋点)
- 之后再配置规则,规则描述了什么方式来保护资源。
- 声明了资源,后续在任何时候灵活地定义各种流量控制规则。
资源
资源:可以是指一个服务,一个服务里的方法,或者是一段代码。写代码时,考虑某段代码是否需要保护,如果需要就将之定义为一个资源。
定义资源的方式
sentinel 支持都多种方式来定义资源,常见的有:
- 方式一:整合到常见的主流框架,比如 Web Servlet、Dubbo、Spring Cloud
- 方式二:抛出异常的方式,使用 SphU 这个类的 try-catch 方式
- 方式三:返回布尔值方式定义资源,使用 SphO 提供 if-else 风格的 API
- 方式四:注解方式定义资源,使用 @SentinelResource 注解 。
- 方式五:异步调用支持,使用 SphU.asyncEntry 异步方法。
示例有:
抛出异常的方式 来定义资源
使用 SphU 这个类的 try-catch 风格的 API。当“资源”发生了限流之后会抛出 BlockException,然后捕捉异常进行限流之后的逻辑处理。
示例代码如下:
try (Entry entry = SphU.entry("resourceName")) {
// 被保护的业务逻辑
// do something here...
} catch (BlockException ex) {
// 资源访问阻止,被限流或被降级
// 在此处进行相应的处理操作
}
规则
Sentinel 支持以下几种规则:
- 流量控制规则
- 熔断降级规则
- 系统保护规则
- 来源访问控制规则
- 热点参数规则
流量控制规则(FlowRule)
支持 QPS 模式(1)或并发线程数模式(0)。
熔断降级规则(DegradeRule)
熔断策略,支持慢调用比例/异常比例/异常数策略
系统保护规则 (SystemRule)
结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡
来源访问控制规则 (AuthorityRule)
即黑名单,白名单规则。
规则的持久化
建议和 nacos 一起使用,方法见本文后面章节。
1.2 在service层使用 Sentinel
一般java web 项目都会有 controller 层, service 层,dao层,我们要在 service 层使用的是可以这么做。
(1)添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2) 在服务层加注解:
@Service
public class TestService {
@SentinelResource(value = "sayHello")
public String sayHello(String name) {
return "Hello, " + name;
}
}
@SentinelResource 注解用来标识资源是否被限流、降级。上述例子上该注解的属性 value 指示了一个资源名称。
@SentinelResource 还提供了其它额外的属性如 blockHandler,blockHandlerClass,fallback 用于表示限流或降级的操作
一般我们需要实现一个降级后的处理,比如上面的 fallback 指示一个降级后字符串返回值告知触发了熔断降级。
另外,Sentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。您只需要对应用进行简单的配置,就可以使用这些功能。我们在后面用一个章节来介绍它。
1.3 和 Feign 一起使用
Sentinel 适配了组件。
(1) 先引入 spring-cloud-starter-alibaba-sentinel
的依赖
(2) 再引入feign依赖
引入 spring-cloud-starter-openfeign
依赖**,使 Sentinel starter 中的自动化配置类生效:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(3) 配置文件打开
配置文件打开 Sentinel 对 Feign 的支持:
feign.sentinel.enabled=true
示例说明
比如下面的示例中你要了解的:
- 1.正常的业务调用: /echo/{str}。
- 熔断后的异常处理,指定了 fallback 处理,并返回 "echo fallback" 字符串。
详细示例:
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
class FeignConfiguration {
@Bean
public EchoServiceFallback echoServiceFallback() {
return new EchoServiceFallback();
}
}
class EchoServiceFallback implements EchoService {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
}
1.4 和 RestTemplate 一起使用
支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,加上 @SentinelRestTemplate 注解。
@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
return new RestTemplate();
}
说明:@SentinelRestTemplate 注解的属性
@SentinelRestTemplate 注解的属性支持限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)的处理。
比如上面的示例指示了 ExceptionUtil.handleException 是熔断降级后的异常处理方法,该方面用明确的方法签名格式,如下:
public class ExceptionUtil {
public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
...
}
}
方法返回值提供了 SentinelClientHttpResponse 用于构造返回信息。
注意
应用启动的时候会检查 @SentinelRestTemplate 注解对应的限流或降级方法是否存在,如不存在会抛出异常
实际项目中也会在网关层使用,见下一章节。
2. 在 Spring Cloud Gateway 网关中使用
可以结合 Spring Cloud Gateway 一起使用。
- (1) 添加 spring-cloud-alibaba-sentinel-gateway 依赖。
- (2) 添加 spring-cloud-starter-gateway 依赖
来让 spring-cloud-alibaba-sentinel-gateway 模块里的 Spring Cloud Gateway 自动化配置类生效:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- (3) 配置文件
指定 spring.cloud.sentinel.filter.enabled 为 false
注意:
网关流控规则数据源类型是 gw-flow
,若将网关流控规则数据源指定为 flow 则不生效。
支持两种资源标识维度的限流
Sentinel 提供的 Spring Cloud Gateway 的适配模块可以提供两种资源维度的限流:
- routeId:即在 gateway 中的路由 routeId。
- 自定义分组的名称:可以利用 API 来自定义一些分组名,将URL归类在一个组下。
- 默认不支持 URL 粒度
3. sentinel 的控制台
3.1 Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
3.2. 启动 sentinel 的控制台
下载最新版本的控制台 jar 包
可以从这个 release 页面 下载。
命令行启动
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456
说明:
- -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080,浏览器从这个端访问。打开页面,默认用户名和密码都是 sentinel。
3.3. 规则管理
管理和新增规则
打开 http://localhost:8080
您可以在 控制台web页 配置修改规则,进行规则管理。
点击新增规则按钮,如下:
规则的存储
默认是存储在内存的,应用重启之后该规则会丢失。建议通过一些配置来使用外部存储方式来保存。建议结合 nacos 动态实时的刷新规则。
3.4. 规则推送
规则推送分为 3 种模式,包括:
- 原始模式
- Pull 模式
- Push 模式"。
原始模式
通过 API 将规则推送至客户端并直接更新到内存中, 图例:
------> sentinel 客户端1
Sentinel ------> sentinel 客户端2
Dashboard
------> sentinel 客户端3
好处: 简单,无依赖;
坏处: 应用重启规则就会消失,不能用于生产环境
Pull模式
在客户端注册一个本地文件数据源:收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中。
本地文件数据源会定时轮询文件的变更,读取规则。
这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。
以本地文件数据源为例,过程如下图所示:
/---------- 在内存中更新规则(规则缓存)
/
Sentinel -----> Sentinel客户端 ----> 将规则写入本地文件 ----> 本地文件
Dashboard
好处:简单,不引入新的依赖
坏处:无法保证监控数据的一致性
Push模式
Sentinel 控制台 的规则到 统一配置中心(比如nacos),再到各个 客户端。
即: Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel
图例:
nacos
(1) / \
/ \ (2)
/ \
Sentinel |---- sentinel 客户端1
Dashboard |---- sentinel 客户端2
生产环境建议使用 PUSH 模式,改造方法见下一章节。
4. 和 nacos 集成
4.1 介绍
默认情况下,规则是存储在内存的,重启后就没了。因此在生产环境建议使用nacos 集成来使用。分成两个步骤:
- (1) 在sentinel dashboard 控制台的web管理页面创建规则,并将规则存储到nacs。需要改造sentinel 控制台。
- (2) 客户端应用获得从 nacos 推送(PUSH)而来的 “限流的配置规则”,并加载到sentinel中。
即:在sentinel dashboard 的web页设置限流规则 ---> 规则存储到 nacos ---> 再推送到客户端应用
4.2 改造 sentinel 控制台
改造的目标是:改造 sentinel 控制台,使得在控制台的web页修改的规则保存到nacos中去。
具体改造方法:略。
有同学已经改造好的在这里:https://gitee.com/schonglin/sentinel-nacos
4.3 配置客户端,读nacos数据源。
实现的目标是:从nacos 读取规则并应用到客户端应用中。
4.3.1 修改客户端服务的配置文件,添加一个数据源
下面的示例中,我添加了一个 sentinel 的数据源 ds2, 指定了 nacos服务的地址,data-id 配置文件名,规则是 rule-type 限流类型。
spring:
application:
name: business
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080 # 指定控制台地址和端口
port: 8721 # 这个端口和 Sentinel dashborad 做交互
datasource:
# 指定一个用于流控规则的数据源(来自nacos)
ds2:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-flow-rules # 比如流控的规则是 {appName}-flow-rules
group-id: SENTINEL_GROUP # 指定的一个分组名
data-type: json
rule-type: flow
4.3.2 在nacos中添加一个限流的配置文件,和数据源名称一致
我在nacos中添加一个限流的配置文件,名字叫做${spring.application.name}-sentinel-flow,它的格式和上面 data-id 要对应上。
[
{
"resource": "/hello",
"limitApp": "default",
"grade": 1,
"count": 6,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
上面的配置内容说明:
- resource:资源名
- limitApp:调用来源, default 则不区分调用来源
- grade:限流阈值类型(QPS 或并发线程数);0代表根据并发数量来限流,1代表根据QPS来进行流量控制
- count:限流阈值,和上面的类型相关
- strategy:调用关系限流策略
- controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
- clusterMode:是否为集群模式
访问几次接口后,就可以在Sentinel Dashboard 中看到在nacos中配置的规则信息,重启后也可以再次重nacos获取到配置好的规则。
我的示例demo 见: https://github.com/vir56k/java_demo/tree/master/sentinel/sentineldemo3 配合 改造后支持nacos的sentinel 来使用。
5. 参考
Sentinel 控制台
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel
https://www.cnblogs.com/gyli20170901/p/11279576.html
https://github.com/alibaba/Sentinel/wiki/Sentinel-%E6%8E%A7%E5%88%B6%E5%8F%B0%EF%BC%88%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7%E7%AE%A1%E7%90%86%EF%BC%89#%E8%A7%84%E5%88%99%E9%85%8D%E7%BD%AE
https://blog.csdn.net/qq_38723394/article/details/108991518