文中使用的nacos版本1.4.2、sentinel版本1.8.3
当集成了Sentinel的客户端应用重启之后,在控制台配置的规则全部都没有了,如果需要上生产环境需要将规则配置进行持久化。下面就来实现Sentinel规则配置持久化。
需要持久化至nacos就需要添加相关Maven依赖
com.alibaba.cloud
spring-cloud-alibaba-sentinel-datasource
com.alibaba.csp
sentinel-datasource-nacos
默认 Nacos 适配的 dataId 和 groupId 约定如下:
spring:
cloud:
sentinel:
datasource:
# 自定义命名
flow-rule:
# 支持多种持久化数据源:file、nacos、zk、apollo、redis、consul
nacos:
# naco服务地址
server-addr: localhost:8848
# 命名空间,根据环境配置
namespace: public
# 这里我做了一下细分,不同规则设置不同groupId
group-id: SENTINEL_FLOW_GROUP
# 仅支持JSON和XML类型
data-id: ${spring.application.name}-flow-rules.json
# 规则类型:flow、degrade、param-flow、system、authority
rule-type: flow
# nacos开启了认证需要配置username、password
# username: nacos
# password: nacos
[{
"clusterMode": false,
"controlBehavior": 0,
"count": 5.0,
"grade": 1,
"limitApp": "default",
"resource": "/sentinel/flow",
"strategy": 0
}]
规则配置详细官方文档:https://sentinelguard.io/zh-cn/docs/basic-api-resource-rule.html
配置完成后,重启项目可以看到规则配置依然存在。修改Nacos中的配置也可以实时同步至Sentinel控制台了。
从上面看来配置的规则可以持久化了,Nacos配置中心修改的规则可能实时同步至Sentinel控制台。但是在控制台中新增、修改、删除规则是无法同步至Nacos配置中心。在控制台添加了一个规则,如果客户端重启,规则就会丢失。下面就来实现控制台添加规则并推送至Nacos。
根据官方文档所述:Sentinel 控制台提供 DynamicRulePublisher 和 DynamicRuleProvider 接口用于实现应用维度的规则推送和拉取。
com.alibaba.boot
nacos-config-spring-boot-starter
0.2.10
groupId根据命名约束自定义命名。
# 配置nacos服务地址与命名空间,可根据环境配置命名空间
nacos.config.server-addr=localhost:8848
nacos.config.namespace=8b1673aa-38da-48c6-bc5a-6df956ed0956
# 配置nacos groupId,可以自定义groupId
# 跟上面一样按照不同规则设置不同groupId
sentinel.nacos.flow.group-id=SENTINEL_FLOW_GROUP
sentinel.nacos.degrade.group-id=SENTINEL_DEGRADE_GROUP
sentinel.nacos.auth.group-id=SENTINEL_AUTH_GROUP
sentinel.nacos.param.group-id=SENTINEL_PARAM_GROUP
sentinel.nacos.system.group-id=SENTINEL_SYSTEM_GROUP
/**
* @ClassName FlowRulePublisher
* @Description 推送流控规则
* @Author tigerkin
* @Date 2022/3/9 14:40
*/
@Component
public class FlowRulePublisher implements DynamicRulePublisher> {
private static final Logger LOG = LoggerFactory.getLogger(FlowRulePublisher.class);
@Value("${sentinel.nacos.flow.group-id}")
private String nacosFlowGroupId;
@Autowired
private NacosConfigProperties nacosConfigProperties;
/**
* 重要属性:
* resource 资源名,资源名是限流规则的作用对象
* count 限流阈值
* grade 限流阈值类型,QPS 或线程数模式 QPS 模式
* limitApp 流控针对的调用来源 default,代表不区分调用来源
* strategy 调用关系限流策略:直接、链路、关联 根据资源本身(直接)
* controlBehavior 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 直接拒绝
* @param app app name
* @param rules list of rules to push
* @throws Exception
*/
@Override
public void publish(String app, List rules) throws Exception {
if (StringUtil.isBlank(app)) {
return;
}
if (rules == null) {
return;
}
LOG.info("========> 流控规则推送 -> app: {} rules:{}", app, JSON.toJSONString(rules));
List flowFules = rules.stream().map(data -> {
FlowRuleEntity entity = new FlowRuleEntity();
entity.setResource(data.getResource());
entity.setCount(data.getCount());
entity.setGrade(data.getGrade());
entity.setLimitApp(data.getLimitApp());
entity.setStrategy(data.getStrategy());
entity.setControlBehavior(data.getControlBehavior());
return entity;
}).collect(Collectors.toList());
/**
* sentinel推送nacos命名约束
* 流控规则 dataId: {appName}-flow-rules,比如应用名为 appA,则 dataId 为 appA-flow-rules
*/
String dataId = String.format("%s-flow-rules.json", app);
HttpHandler.handler(flowFules, nacosConfigProperties, nacosFlowGroupId, dataId);
}
}
/**
* @ClassName HttpHandler
* @Description
* @Author tigerkin
* @Date 2022/3/10 11:06
*/
public class HttpHandler {
private static final Logger LOG = LoggerFactory.getLogger(HttpHandler.class);
public static void handler(Object rules, NacosConfigProperties nacosConfigProperties, String groupId, String dataId) throws IOException {
StringJoiner param = new StringJoiner("&");
param.add(String.format("tenant=%s", nacosConfigProperties.getNamespace())); // Nacos 的命名空间ID字段
param.add(String.format("dataId=%s", dataId));
param.add(String.format("group=%s", groupId));
param.add(String.format("content=%s", URLEncoder.encode(JSON.toJSONString(rules), "UTF-8")));
param.add(String.format("type=%s", "json"));
String url = String.format("http://%s/nacos/v1/cs/configs?%s", nacosConfigProperties.getServerAddr(), param.toString());
HttpPost httpPost = new HttpPost(url);
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = httpclient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
LOG.info("========> 发布成功:{}", result);
} else {
LOG.error("========> 发布失败:{}", response.toString());
}
}
}
实现在推送接口后,找到Sentinel规则配置的Controller,并添加推送逻辑。我这里改造的是FlowControllerV1。
添加依赖注入属性:
最后在Controller中找到publisherRules方法,添加推送方法调用就可以了。
Sentinel在规则变更后会给客户端发送一个请求,去同步规则配置。
下面在控制台添加规则,就会推送至Nacos配置中心了。至此Sentinel配置规则持久化至Nacos就完成了。
参考:
Nacos Open API 文档:https://nacos.io/zh-cn/docs/open-api.html
Sentinel github地址:https://github.com/alibaba/Sentinel/releases
Sentinel官方文档:
https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel
https://github.com/alibaba/Sentinel/wiki/Sentinel-控制台(集群流控管理)#规则配置
提供相关业务逻辑处理源码位置,有兴趣的童鞋可以看一看。
客户端处理Sentinel请求的源码位置:
jar: sentinel-transport-common-1.8.3.jar
package: com.alibaba.csp.sentinel.command.handler
jar: sentinel-datasource-nacos-1.8.3.jar
package: com.alibaba.csp.sentinel.datasource.nacos