SpringCloud Alibaba五大组件之------Sentinel(文末附有完整项目GitHub链接)
前言
前文,我们已经介绍了SpringCloud Alibaba五大组件中的两个:dubbo和nacos,文章连接:太细了有手就行,SpringCloud Alibaba+Nacos+Dubbo整合,有需要的可以去查阅。
ps:本文用到的项目demo也是基于这篇文章去扩展的,包括模块结构和版本依赖等等。
一、什么是Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
-
丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
-
完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
-
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
-
完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Sentinel 的主要特性:
上面内容都是引用于官网
二、Sentinel控制台
官方提供两种方式跑控制台,我建议没有特殊需求下,通通用第一种就行
1.下载jar包
打来Sentinel的官网:https://github.com/alibaba/Sentinel/releases,找到自己需要的版本下载,本文编写时最高版本是1.8.8,本文用的是1.8.6版本
版本问题作者这里再啰嗦一句,一定要选对,因为我这一系列文章,SpringCloud alibaba定的是2021.0.6.0,所以一切版本如下图来选,直接毕业版本。
2.自己打包
下载整个工程,用mvn clean package打成jar包
3.启动控制台
打开cmd,进入jar包的目录,执行一下代码:
java
java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
其中 -Dserver.port=8180 用于指定 Sentinel 控制台端口为 8180,默认8080
dashboard.server:网页的端口,客户端必须按指定的访问,也可以省略,默认是127.0.0.1:8080
4.浏览器访问
访问:http://localhost:8180,默认账户和密码都是sentinel
登录,显示这个界面则成功
三、项目中引入Sentinel
1.在api-service模块的pom文件引入依赖:
csharp
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.application.yml
修改配置文件,新加如下配置:
yaml
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:8180
此处的port,默认是8179,主要就是项目启动后,会自行启动一个HTTP server,通过这个端口和sentinel客户端进行交互,来传输数据。
dashboard: localhost:8180,这个要和上一步启动sentinel控制台时候的ip端口一致。
3.补充:jvm启动参数
只要你前面配置和项目都正确,这一步可以省略,但是如果你项目启动,sentinel控制台服务注册不上,你就jvm加入下面参数:
java
-Dcsp.sentinel.dashboard.server=127.0.0.1:8180
4.编写简单的测试程序
controller:
java
@RestController
@RequestMapping("/testSentinel")
public class SentinelController {
@Resource
UserInfoService userInfoService;
@RequestMapping("/one")
public void testThree() {
userInfoService.testSentinel();
}
}
service:
java
@Service
public class UserInfoServiceImpl{
@Override
@SentinelResource(value = "testSentinel", blockHandler = "testBlockHandler", fallback = "testFallback")
public void testSentinel() {
System.out.println("testSentinel");
//这行代码是为了测试报错熔断,如果只是流控测试,此行代码可以屏蔽
//int a = 1/0;
}
public void testBlockHandler(BlockException ex) {
System.out.println("进入testBlockHandler");
}
public void testFallback(Throwable e) {
System.out.println("进入testFallback");
e.printStackTrace();
}
}
浏览器访问一下接口
查看控制台,这里可以看到我们的测试接口,项目已经集成好了sentinel
PS:1.因为sentinel是懒加载,这里一定要浏览器随便访问一个接口,不然服务注册不上,也可以添加配置:spring.cloud.sentinel.eager:true实现服务器启动了自动心跳注册。
2.访问了要等个几秒钟,有延迟,刷新一下就能看到了。
5.@SentinelResource注解
常用的几个注解参数:
- value:定义资源名
- blockHandler:会在原方法被限流/降级/系统保护的时候调用,记得方法定义在同一个类中。
- fallback: 会针对所有类型的异常,出现时调用
- defaultFallback:全局默认出异常时候调用,定义了fallback,则此参数不生效
6.其他方式
当然除了注解之外,还提供了其他编码方式去控制一段代码或者一个方法的访问,比如最常见的SphU.entry,大家也可以去官网上查阅根据需求选择
java
try {
// 资源名可使用任意有业务语义的字符串,注意数目不能太多(超过 1K),超出几千请作为参数传入而不要直接作为资源名
// EntryType 代表流量类型(inbound/outbound),其中系统规则只对 IN 类型的埋点生效
entry = SphU.entry("自定义资源名");
// 被保护的业务逻辑
// do something...
} catch (BlockException ex) {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
} catch (Exception ex) {
// 若需要配置降级规则,需要通过这种方式记录业务异常
Tracer.traceEntry(ex, entry);
} finally {
// 务必保证 exit,务必保证每个 entry 与 exit 配对
if (entry != null) {
entry.exit();
}
}
四、规则讲解
这里会讲几个常用的配置,其余的配置大家可以去官方查看:sentinel官网,配置规则主要有两种方式,第一种是代码中硬编码,第二种是通过控制台配置的形式
1.代码中硬编码
先介绍下,java代码中的几个规则对象:
- DegradeRule:熔断降级,主要是当一个接口不可访问后,进行的一系列操作,避免所有请求堵塞
- AuthorityRule: 授权规则(来源访问),判断来源请求是否放行,常用的场景是黑白名单
- FlowRule: 流量控制规则,监控QPS,避免系统被瞬时的流量高峰冲垮
- ParamFlowRule: 热点参数限流,可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
- SystemRule:系统保护规则,当系统负载高于某个阈值,就禁止或者减少流量的进入;当 load 开始好转,则恢复流量的进入
当然还有网关控制和集群流量控制,这两者在代码中无法实现,只有通过控制台配置。
我们就拿熔断规则来举例,在service中,增加如下规则初始化方法:
java
@PostConstruct
public void initRule() {
//熔断规则: 5s内调用接口出现异常次数超过5的时候, 进行熔断
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource("testSentinel");
rule.setCount(5);
//统计时长
rule.setStatIntervalMs(5000);
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);//熔断规则
//熔断时长
rule.setTimeWindow(10);
degradeRules.add(rule);
DegradeRuleManager.loadRules(degradeRules);
}
大家可以在文末获取代码自行去测试。
2.控制台配置(生产环境中不推荐)
控制台中我们有两种方式去添加流控规则
第一种方式:
(1)左侧菜单栏添加
注意这里的资源名,和我们代码中的资源名要匹配,不然配置不会生效。
(2)簇点链路中添加
在链路中添加,可以保证我们的资源名是一定存在的,两种添加方式,你自己选择喜欢的。
3.为何不推荐控制台中添加
因为控制台中添加规则,会推送到项目的内存中,重启就没了,不能持久化,所以在生产环境中不推荐,总不能你每次重启项目都要单独配置一次。
五、生产环境下,规则集成Nacos
生产环境下,都用的Nacos统一管理规则,就是常说的push规则,通过Nacos推送到sentinel控制台,然后再更新到项目中。这样即使项目重启,只要Nacos还在,配置就是接近持久化的状态。
1.引入依赖
由于spring-cloud-starter-alibaba-sentinel 的Maven依赖并没有引入Nacos相关的,所以我们要单独引入依赖:
xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
2.Nacos中新增config
新增一个流量控制的config
选取json格式:
yaml
[
{
"resource": "testSentinel",
"limitApp": "default",
"grade": 1,
"count": 2,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- resource:资源名,即限流规则的作用对象
- limitApp:流控针对的调用来源,若为 default 则不区分调用来源
- grade:限流阈值类型(QPS 或并发线程数);0代表根据并发数量来限流,1代表根据QPS来进行流量控制
- count:限流阈值
- strategy:调用关系限流策略
- controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
- clusterMode:是否为集群模式
3.application.yml文件修改
在前面的基础上,新增datasource的配置:
注意,这里的nacos一定要和上一步新增的对应,
yaml
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:8180
datasource:
ds:
nacos:
server-addr: 172.16.72.132:8848
data-id: sentinel-rule
namespace: 76dae550-4133-44d8-b591-dc82f5f97b6e
group-id: SENTINEL_PROVIDER_GROUP
username: nacos
password: nacos
data-type: json
rule-type: flow
由于spring.cloud.sentinel.datasource属性对应的是一个Map,所以它的需要自定义指定Map的KEY,下面的配置中ds就作为KEY,然后后面就可以配置不同的数据源
4.重启
重启后,查看sentinel控制台,可以看到我们在nacos定义的规则
测试一下新加的流控规则,我们是定义的qps不超过2,超过的请求全部拒绝(默认),这里补充一下拒绝策略。
- 快速失败:超过设置阈值的请求全部拒绝,请求失败
- Warm Up :
- 排队等待:
可以看到,标记1和标记2都能正常打印,当第三个请求来了的时候,"进入testFallback"就不打印了,转而进入了blockHandler方法,说明流控是生效了的。
六、结语
到这里,SpringCloud alibaba五大组件之一的流控熔断降级sentinel就讲解完了,欢迎大家评论区指点,后面还剩两个组件:分布式队列RocketMQ和分布式事务Seata,RocketMQ可能会找个时间再写一篇文章,但是Seata的话,如果项目比较庞大,加上事务会顶不住,qps明显降低很多,我一个阿里工作的朋友给我谈过,他们项目组的微服务,都是裸奔的没有用事务,所以这文章我再考虑出不出,其实本文项目中的一个分支seata,我是已经实现了整合的,但是感觉生产环境中又不试用,就没有发出来,后面看情况吧
附上项目GitHub链接:https://github.com/wangqing-github/DubboAndNacos/tree/sentinel,选取sentinel分支。