Sentinel默认把规则存储在jvm内存,分布式系统自然要存储在配置中心,供所有服务去拉取规则。客户端可以通过配置中心去实时监听到,同时sentinel-dashboard也能动态刷新,但是默认是不支持sentinel-dashboard推送到配置中心的,之前曾经给官方上报过issues,他们的回复是自己去扩展实现。
当时就没多去在意,后来才明白过来人家有实现了,只不过是商业版的,去阿里云开通AHAS即可。昨天看文档说提供的有接口供我们扩展实现,下面就演示一个sentinel-dashboard推送到配置中心的实现。这里配置中心以阿里的配置中心Nacos为例。
1.注入一个 Nacos
配置中心对象
/**
* <p>配置Nacos配置中心对象
*
* @author tianqingzhao
* @since 2021/7/4 18:26
* @see {@link ConfigService}
*/
@Configuration
public class NacosConfig {
/**
* 这里将FlowRuleEntity转换成FlowRule才会对客户端生效
*
* @return
*/
@Bean
public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
return s -> JSON.parseArray(s, FlowRuleEntity.class);
}
@Bean
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "ip:port");
properties.setProperty("group", "SENTINEL_GROUP");
properties.setProperty(PropertyKeyConst.NAMESPACE, "7a7e435c-73e4-4204-9191-72ee3d4a1767");
properties.setProperty(PropertyKeyConst.USERNAME, "nacos");
properties.setProperty(PropertyKeyConst.PASSWORD, "nacos");
return ConfigFactory.createConfigService(properties);
}
}
2.Nacos配置工具类,用于获取配置和设置配置的顶层实现,可用策略模式以及模板模式具体实现,这里简单演示一下
/**
* <p>Nacso配置工具类
*
* @author tianqingzhao
* @since 2021/7/4 17:31
*/
public final class NacosConfigUtil {
public static final String GROUP_ID = "SENTINEL_GROUP";
public static final String FLOW_DATA_ID_POSTFIX = "-sentinel-flow";
public static final String DEGRADE_DATA_ID_POSTFIX = "-sentinel-degrade";
public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-sentinel-param-flow";
public static final String SYSTEM_FULE_DATA_ID_POSTFIX = "-sentinel-system";
public static final String AUTHORITY_DATA_ID_POSTFIX = "-sentinel-authority";
public static final String DASHBOARD_POSTFIX = "-dashboard";
private NacosConfigUtil() {
}
/**
* 从nacos服务上获取配置
*
* @param configService nacos配置服务
* @param appName 应用微服务名称
* @param postfix {@link NacosConfigUtil#FLOW_DATA_ID_POSTFIX}
* @param clazz 反序列化class类型
* @param <T> 规则实体类泛型
* @return
* @throws NacosException
*/
public static <T> List<T> getRuleEntities4Nacos(ConfigService configService, String appName, String postfix,
Class<T> clazz) throws NacosException {
// 去nacos注册中心获取配置
String rules = configService
.getConfig(genDataId(appName, postfix) + DASHBOARD_POSTFIX, NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return (List<T>) JSON.parseObject(rules, clazz);
}
/**
* 存在规则到nacos server上
*
* @param configService nacos配置服务
* @param app 微服务名称
* @param postfix sentinel规则后缀
* @param rules 规则列表
* @param <T> 规则实体类泛型
* @throws NacosException
*/
public static <T> void setRuleString2Nacos(ConfigService configService, String app, String postfix, List<T> rules)
throws NacosException {
AssertUtil.assertNotBlank(app, "app name not be empty");
List<Rule> ruleList = new ArrayList<>();
for (T t : rules) {
RuleEntity ruleEntity = (RuleEntity) t;
Rule realRule = ruleEntity.toRule();
ruleList.add(realRule);
}
// 生成dataId
String dataId = genDataId(app, postfix);
// 发布配置
configService.publishConfig(dataId, NacosConfigUtil.GROUP_ID, JSON.toJSONString(ruleList));
// 存储,给控制台使用
configService.publishConfig(dataId + DASHBOARD_POSTFIX, NacosConfigUtil.GROUP_ID, JSON.toJSONString(rules));
}
/**
* 生成配置中心的dataId
*
* @param appName 服务名称
* @param postfix 规则后缀
* @return 拼接的dataId
*/
private static String genDataId(String appName, String postfix) {
return appName + postfix;
}
}
3.获取配置中心的规则,首先获取一个配置中心对象,实现 DynamicRuleProvider
接口,注入我们配置的nacos配置中心,然后通过nacos的api获取规则即可。
/**
* <p>自定义限流规则从nacos配置中心获取
*
* @author tianqingzhao
* @since 2021/7/4 18:26
* @see {@link FlowRuleEntity}
*/
@Component("customFlowRuleNacosProvider")
public class CustomFlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<FlowRuleEntity>> converter;
@Override
public List<FlowRuleEntity> getRules(String appName) throws Exception {
String rules = configService
.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
4.推送规则到配置中心,也是先获取一个配置中心对象,然后实现 DynamicRulePublisher
接口
/**
* <p>自定义限流规则发布到nacos
*
* @author tianqingzhao
* @since 2021/7/4 18:26
*/
@Component("customFlowRuleNacosPublisher")
public class CustomeFlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<FlowRuleEntity>, String> converter;
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID,
converter.convert(rules));
}
}
5.这里只演示一个限流规则的获取以及发布,在 FlowControllerV1
类里面注入我们自定义的实现
@Autowired
@Qualifier("customFlowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("customFlowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
获取规则的接口为get方式请求的rules
保存的接口为post方式的rules接口
注释掉之前的发布规则方法,重新去实现
private void publishRules(String appName) throws Exception {
List<FlowRuleEntity> rules = repository.findAllByApp(appName);
rulePublisher.publish(appName,rules);
}
6.先来测试从sentinel-dashboard从nacos配置中心获取规则,nacos控制台为1
sentinel-dashboard刷新也显示为1
nacos配置中心更改为10
sentinel-dashboard刷新也显示为10
再来测试sentinel-dashboard推送到nacos配置中心,控制台改为1
nacos配置中心也显示为1
然后打包即可用了。。。。。。