前言:
最近在体验Spring Cloud Alibaba,其中用到了Sentinel-Dashboard组件提供限流熔断
在Sentinel-Dashboard中配置规则是存储在内存之中,重启应用就会丢失,所以实际生产环境中需要配置规则的持久化实现。
Sentinel提供多种不同的数据源来持久化规则配置,包括file,redis、nacos、zk、apollo。
因为正在尝试使用Spring Cloud Alibaba组件,并且也上了Nacos作为项目的注册中心与配置中心,所以考虑用Nacos来作为Sentinel规则的远程配置中心。
一、准备工作
Sentinel-Dashboard持久化
这就需要涉及到Sentinel Dashboard的规则管理及推送功能:集中管理和推送规则。sentinel-core提供 API 和扩展接口来接收信息。开发者需要根据自己的环境,选取一个可靠的推送规则方式;同时,规则最好在控制台中集中管理。
而规则管理推送主要有以下三种模式:
这里采用是第三种Push模式,即Sentinel-Dashboard统一管理配置,然后将规则统一推送到Nacos并持久化(生成配置文件),最后客户端监听Nacos(这一部了解使用过Nacos的话应该很熟,采用ConfigService.getConfg()方法获取配置文件),下发配置生成Rule。如下图(虚线部分不推荐):
换句话说就是实现Sentinel Dashboard与Nacos之间的相互通信:
Sentinel-Dashboard界面配置流控规则---发布/推送--->Nacos生成配置文件并持久化;
通过Nacos配置文件修改流控规则---拉取--->Sentinel-Dashboard界面显示最新的流控规则。
正因为Sentinel-Dashboard当前版本(截至目前为止是1.8.1-SNAPSHOT)暂不支持,但是可以通过改造部分源码实现此功能,具体请看下面介绍。
二、Sentinel-Dashboard流控规则源码改造须知
下载Sentinel-Dashboard-Nacos源代码,然后对sentinel-dashboard模块进行改造
下载地址:https://github.com/eacdy/Sentinel-Dashboard-Nacos.git
改造前,我们所要了解实现Sentinel-Dashboard与Nacos相互通信需要经历哪些流程或者说是缺少哪些流程,我们才好对症下药,根据我的理解我归纳总结出一下几点:
- 流控规则Controller入口
Sentinel-Dashboard-Nacos的流控规则下的所有操作,都会调用sentinel-dashboard源码中的FlowControllerV1类,这个类中包含流控规则本地化的CRUD操作;
在com.alibaba.csp.sentinel.dashboard.controller.v2包下存在一个FlowControllerV2;类,这个类同样提供流控规则的CURD,与V1不同的是,它可以实现指定数据源的规则拉取和发布。
官方说明:
从 Sentinel 1.4.0 开始,我们抽取出了接口用于向远程配置中心推送规则以及拉取规则:DynamicRuleProvider
DynamicRulePublisher
以 Nacos 为例,若希望使用 Nacos 作为动态规则配置中心,用户可以提取出相关的类,然后只需在FlowControllerV2中指定对应的 bean 即可开启 Nacos 适配
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher> rulePublisher;
所以根据官网说明,我们知道,FlowControllerV2依赖两个非常重要的类
DynamicRuleProvider:动态规则的拉取,从指定数据源中获取控制后在Sentinel中展示。
DynamicRulePublisher:动态规则发布,将在Sentinel中修改的规则同步到指定数据源中。
只需要扩展这两个类,然后集成Nacos来实现Sentinel Dashboard规则同步。
- sentinel-dashboard缺少Nacos配置
如下截图test目录,官方提供关于Nacos等持久化示例,copy至rule目录创建nacos文件目录
在源码中虽然官方提供了test示例(即test目录)下关于Nacos等持久化示例但是具体的实现还需要一些细节,比如在Sentinel Dashboard配置Nacos的serverAddr、namespace、groupId,并且通过Nacos获取配置文件获取服务列表等
例如:NacosConfig中ConfigFactory.createConfigService("localhost")并没有实现创建具体的nacos config service,而是默认localhost 修改参考如下代码:
@Configuration
public class NacosConfig {
@Value("${nacos.address}")
private String address;
@Value("${nacos.namespace}")
private String namespace;
@Value("${nacos.username}")
private String username;
@Value("${nacos.password}")
private String password;
@Bean
public Converter, String> flowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter, String> authorityRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter, String> degradeRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter, String> paramFlowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter, String> systemRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, address);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
properties.put(PropertyKeyConst.USERNAME, username);
properties.put(PropertyKeyConst.PASSWORD, password);
return ConfigFactory.createConfigService(properties);
}
}
application.properties文件中也没有Nacos的相关配置,修改参考如下:
nacos.address=127.0.0.1:8848
nacos.namespace=
nacos.username=nacos
nacos.password=nacos
注意:官方只提供了一种基于流控规则模块的修改,但是sentinel-dashboard对应菜单提供了好几种规则、则都需要进行配置持久化到Nacos。但官方提供的流控规则不符合我们要求,所以修改其中代码规则如下:
-
流控规则见如下截图:
参考代码:
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider> {
@Autowired
private ConfigService configService;
@Override
public List getRules(String appName) throws Exception {
return NacosConfigUtil.getRuleEntitiesFromNacos(
this.configService,
appName,
NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
FlowRuleEntity.class
);
}
}
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher> {
@Autowired
private ConfigService configService;
@Override
public void publish(String app, List rules) throws Exception {
NacosConfigUtil.setRuleStringToNacos(
this.configService,
app,
NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
rules
);
}
}
基于其他规则修改见上面截图、创建对应目录、几种规则代码中基本一样,其中修改对应的实体类和NacosConfigUtil.XXX对应的Nacos创建的应用名、这个默认对应一种规则,重复会导致读取配置失败不生效问题
-
配置Controller层方法同步配置于Nacos进行持久化;(基于流控规则 -FlowControllerV2)
1)添加截图中配置、进行持久化操作
2)在对应Controller 添加如下代码中的构造方法,在每个方法(CRUD)调用完毕之后,调用此方法,参数存储于Nacos中进行持久化。
private void publishRules(String app)throws Exception {
List rules =repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
三、流控规则持久化测试
- 编写technical-service-platform客户端
(1)创建springboot应用,引入maven包pom文件如下:
com.alibaba.csp
sentinel-core
1.8.1-SNAPSHOT
com.alibaba.csp
sentinel-datasource-nacos
1.8.1-SNAPSHOT
com.alibaba.csp
sentinel-annotation-aspectj
1.8.1-SNAPSHOT
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
2.1.2.RELEASE
com.alibaba.csp
sentinel-transport-simple-http
1.8.1-SNAPSHOT
(2)配置nacos,配置sentinel-dashboard datasource信息:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/XXX?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
username: XXX
password: XXX
driver-class-name: com.mysql.jdbc.Driver
druid:
db-type: com.alibaba.druid.pool.DruidDataSource
cloud:
sentinel:
transport:
dashboard: localhost:8080
datasource:
flow:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow
degrade:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
system:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
rule-type: system
authority:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-authority-rules
groupId: SENTINEL_GROUP
rule-type: authority
param-flow:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-param-flow-rules
groupId: SENTINEL_GROUP
rule-type: param-flow
(3)编写TestController,指定/test资源节点
package com.test.controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/base/api")
@CrossOrigin
public class TestController {
@RequestMapping("/test")
public String sayHello(){
return "hello Wold";
}
}
-
启动Nacos
我使用的是Centos启动nacos,之后登录Nacos(具体Nacos参考阿里官方文档)
查看起初是没有${spring.application.name}-flow-rules配置文件,也没有SENTINEL-GROUP分组;
- 启动sentinel-dashboard控制台
(1)启动sentinel dashboard
找到target/sentinel-dashboard.jar,执行命令:
nohup java -jar sentinel-dashboard.jar &
(2)登录sentinel-dashboard配置流控规则
1)输入localhost:8080访问sentinel-dashboard控制台(登录用户/密码默认sentinel)
2)选择technical-service-platform菜单-流控规则-新增流控规则-输入配置-新增
如图所示,我们选择QPS阈值类型,并且count为2,流控模式为默认的直接模式,流控效果快速失败(这些配置具体含义参看官网wiki)
注意:一开始可能会空白页面,这可能是由于机器时间机制导致的,此时可能还未发送心跳,加之technical-service-platform控制台默认的又是懒加载模式(可去除该设置),所以最好是我们访问technical-service-platform客户端的/base/api/test接口然后刷新页面即可出现应用。
- 访问/base/api/test接口
不停刷新访问/base/api/test接口,观察sentinel-dashboard界面中的实时监控。看到有通过QPS与拒绝QPS的实时监控情况,说明该technical-service-platform客户端已成功接入sentinel-dashboard。
5、测试sentinel-dashboard流控规则到Nacos的持久化
(1)确认sentinel-dashboard是否能正确发布流控规则到Nacos
在sentinel-dashboard针对sentinel客户端的/base/api/test资源节点已经配置了流控规则
(2)此时Nacos会对此次流控规则生成持久化配置文件,切换到Nacos-配置列表查看确实存在分组SENTINEL_GROUP下的technical-service-platform-flow-rules配置文件
点击查看具体内容,发现关键信息都是正确的,说明sentinel-dashboard发布到Nacos通信已经打通
注意:Nacos配置列表出现两个列表配置具体可参考NacosConfigUtil 代码内逻辑
technical-service-platform-flow-rules 存储持久化规则
technical-service-platform-flow-rules-dashboard 存储返回给前端页面展示内容(具体也可以修改前端页面调用方法,返回参数给页面展示内容)
(3)验证流控规则是否生效
此时我们的QPS阈值为2,也就是说1s之间内我们需要超过访问2次,则会被technical-service-platform限流。不断访问/base/api/test资源节点,观察返回
备注:针对于返回状态是我在客户端代码自定义返回的格式异常
正常返回Blocked By Sentinel(flow limiting)说明限流规则已经生效
(4)簇点链路流控方法修改
簇点链路列表流控按钮调用方法是默认调用存储在内存中的方法,如下图:
修改如下找到 identity.js 修改 FlowServiceV1为FlowServiceV2
备注:
至此所有规则方法持久化到Nacos,默认修改配置还是在sentinel-dashboard页面上进行修改,持久化到Nacos配置列表。
如果操作Nacos配置列表修改,需要修改两个配置文件,否则页面显示和实际存储的规则不一样,容易导致规则出错。