Sentinel 是由阿里巴巴开发的开源项目,面向分布式微服务架构的轻量级高可用流量控制组件。以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度帮助用户保护服务的稳定性。可以说,Sentinel 就是取代 Hystrix 组件的。因为 Hystrix 已经进入了维护状态,不再更新。
Hystrix 官网:https://github.com/Netflix/Hystrix
Sentinel 官网:https://github.com/alibaba/Sentinel
Sentinel 中文使用文档:https://sentinelguard.io/zh-cn/docs/introduction.html
官网地址:https://github.com/alibaba/Sentinel/releases
目前最新版本 1.8.6(2022年12月5日)
在我们下载好的 sentinel jar 包的同一级目录,我们创建一个名字叫做:sentinelRun.bat 文件,bat文件是dos下的批处理文件,它包含一条或多条命令。
然后,使用记事本打开 sentinelRun.bat 文件,输入如下启动命令:
java -Dserver.port=8898 -Dcsp.sentinel.dashboard.server=localhost:8898 -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=admin -jar sentinel-dashboard-1.8.6.jar
pause
说明:
如图所示,sentinel 控制台启动成功。
访问地址:http://localhost:8898/ 账号密码都是:admin (端口号、账号密码根据自己配置的来)
页面如图:
注意:sentinel 服务内部通讯端口是 8719
控制台启动后,客户端(客户端,就是具体的微服务)需要按照以下步骤接入控制台:
1、添加依赖(pom.xml 依赖)
2、定义资源(Java 方法)
3、定义规则
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
2.2.8.RELEASE
说明:如果想查看 sentinel 的版本(注意不是控制台版本,避免混淆),可以查看 Maven 中央仓库:https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel
yml 配置文件增加对 sentinel 的配置:
spring:
cloud:
# sentinel 配置
sentinel:
transport:
# 内部通讯端口号
port: 8719
dashboard: localhost:8898
这时候客户端就算搭建好了,但是在 sentinel 的控制台还看不到效果,因为还需要客户端触发一次请求,才能初始化 sentinel 的相关配置。
在客户端某个 controller 类里增加测试代码:
@GetMapping("/demo/sayHello")
@SentinelResource(value = "helloWorld",
blockHandler = "myBlockHandler", fallback = "myFallback")
public String hello(){
return "Hello,Welcome to the Sentinel world!";
}
/**
* 触发了限流,直接拒绝后面的请求。
* @return
*/
public String myBlockHandler(BlockException blockException){
blockException.printStackTrace();
return "blockHandler";
}
/**
* 触发了降级,直接返回快速失败的数据(熔断)。
* @return
*/
public String myFallback(Throwable throwable){
throwable.printStackTrace();
return "fallback";
}
说明:
属性 | 说明 | 必填与否 | 使用要求 |
---|---|---|---|
value | 用于指定资源的名称 | 必填 | |
entryType | entry 类型 | 可选项(默认为 EntryType.OUT) | |
blockHandler | 服务限流后会抛出 BlockException 异常,而 blockHandler 则是用来指定一个函数来处理 BlockException 异常的。 简单点说,该属性用于指定服务限流后的后续处理逻辑。 |
可选项 |
|
blockHandlerClass | 若 blockHandler 函数与原方法不在同一个类中,则需要使用该属性指定 blockHandler 函数所在的类。 | 可选项 |
|
fallback | 用于在抛出异常(包括 BlockException)时,提供 fallback 处理逻辑。 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。 |
可选项 |
|
fallbackClass | 若 fallback 函数与原方法不在同一个类中,则需要使用该属性指定 blockHandler 函数所在的类。 | 可选项 |
|
defaultFallback | 默认的 fallback 函数名称,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。 默认 fallback 函数可以针对所以类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。 |
可选项 |
|
exceptionsToIgnore | 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。 | 可选项 | - |
重启客户端,发送测试请求。http://localhost:9050/demo/sayHello
然后查看 Sentinel 控制台:
可以看到我们的客户端(微服务)已经受到 Sentinel 控制了。至此,客户端与 sentinel 打通。
规则可以通过配置文件定义,也可以在控制台中定义。在配置文件定义的话,在客户端初始化之后,就会同步到 Sentinel 控制台上来。如果通过控制台设置,在客户端(微服务)重启后失效,也就是说,限流规则并没有持久化在 Sentinel 服务端。
通过控制台设置流控规则
设置阈值类型是:QPS (Queries Per Second,意思是“每秒查询率”)。阈值 1 秒内接受1次请求。测试:1秒内多次请求接口,
模拟程序出现异常的情况:
@GetMapping("/demo/sayHello")
@SentinelResource(value = "helloWorld",
blockHandler = "myBlockHandler", fallback = "myFallback")
public String hello(){
int k = 1/0;
return "Hello,Welcome to the Sentinel world!";
}
测试:
第一次请求直接 fallback(因为抛出了异常)。但是后面多次请求后,会出现 handler,因为触发了流控规则。
2、动态配置规则
通过控制台新增规则,重启微服务客户端规则就失效了。显然不符合我们实际生产所需。生产上一般通过动态规则源的方式来动态管理规则。因此需要动态配置规则。一方面,可以跟 nacos 整合,另一方面,可以写到配置文件中。
SentinelProperties 内部提供了 TreeMap 类型的 datasource 属性用于配置数据源信息,支持:
讲解一下用到最多的【文件配置规则】,在配置文件中的 sentinel 节点增加 datasource 节点:
spring:
cloud:
# sentinel 配置
sentinel:
transport:
# 内部通讯端口号
port: 8719
dashboard: localhost:8898
datasource:
ds1:
file:
# 配置文件地址和类型
file: classpath:myRule.json
data-type: json
rule-type: flow
对应的,在项目的根目录增加 myRule.json 文件,文件内容如下:
[
{
"resource": "helloWorld",
"count": 1,
"grade": 1,
"limitApp": "default",
"strategy": 0,
"controlBehavior": 0
}
]
流量控制规则 (FlowRule):
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS 或线程数模式 | QPS 模式 |
limitApp | 流控针对的调用来源 | default ,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 | 直接拒绝 |
更多动态配置参考官网:dynamic-rule-configuration | Sentinel
配置完毕,重启客户端的微服务。调用一次接口:
可以看到流控规则已经包含了我们配置文件里设置的规则了,注意到配置文件里的流控规则不允许修改资源名。生产环境一般都是这样配置使用。
org.springframework.cloud
spring-cloud-starter-openfeign
2.2.8.RELEASE
代码与 Feign 整合 Hystrix 的一样,如:
API 接口定义如下:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
@Component
@FeignClient(name = "xxx-service", fallbackFactory = TestFactory.class, contextId = "TestApi")
public interface TestApi {
@GetMapping("/test")
String test();
}
注意:我们增加了一个 contextId 等于当前类名,主要是因为旧版本的 springboot 是支持 2 个或者 2 个以上接口类 @FeignClient 有相同的 value 或者 name,但是 SpringBoot 2.2.x 版本以后,就不支持了,会抛出异常:
could not be registered. A bean with that name has already been defined and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
可以通过配置文件里设置:spring.main.allow-bean-definition-overriding=true,也可以通过 contextId 作为区分。推荐后者。
对应的 TestFactory 类(核心代码):
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class TestFactory implements FallbackFactory {
/**
* 如果调用异常,使用熔断机制返回错误信息
* @param cause
* @return
*/
@Override
public TestApi create(Throwable cause) {
return new TestApi() {
@Override
public String test() {
log.error("远程调用异常:"+cause);
return "远程调用异常,这是托底数据";
}
};
}
}
增加一个测试的 controller:
@RestController
public class TestController {
@Autowired
private TestApi testApi;
@GetMapping("/test")
public String test() {
return testApi.test();
}
}
配置文件增加配置:feign.sentinel.enabled=true 即可。
重启客户端的微服务,发送一次测试请求:http://localhost:9050/test
这时候是有异常的,因为我们没有配置对应的远程服务,但不影响。我们查看控制台,已经将 feign 接口纳入管理了。
远程调用异常:java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: xxx-service
只要我们增加对应的远程微服务,提供对应的测试接口,就可以打通整条链路的调用。