赞
踩
sentinel-dashboard改造的时候模仿的是官方demo中进行改造的
sentinel源码中提供的sentinel-dashboard下test的改造dmeo, 我会在添加相应的注释进行说明
@Configuration public class NacosConfig { /** * 将FlowRuleEntity对象转换为JSON字符串 */ @Bean public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() { return JSON::toJSONString; } /** * 将JSON字符串转换为FlowRuleEntity对象 */ @Bean public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() { return s -> JSON.parseArray(s, FlowRuleEntity.class); } /** * nacos配置服务, 这里指向本地nacos */ @Bean public ConfigService nacosConfigService() throws Exception { return ConfigFactory.createConfigService("localhost"); } }
按照上述风格改造后的NacosConfig
@Slf4j @Configuration public class NacosConfig { // ---------- nacos相关的配置 start ---------- @Value("${sentinel.nacos.serverAddr}") private String serverAddr; @Value("${sentinel.nacos.username}") private String username; @Value("${sentinel.nacos.password}") private String password; @Value("${sentinel.nacos.namespace}") private String namespace; /** * nacos配置服务 */ @Bean public ConfigService nacosConfigService() throws Exception { Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr); properties.put(PropertyKeyConst.NAMESPACE, namespace); properties.put(PropertyKeyConst.USERNAME, username); properties.put(PropertyKeyConst.PASSWORD, password); return ConfigFactory.createConfigService(properties); } // ---------- nacos相关的配置 end ---------- /** * 网关API * * @return * @throws Exception */ @Bean public Converter<List<ApiDefinitionEntity>, String> apiDefinitionEntityEncoder() { return JSON::toJSONString; } @Bean public Converter<String, List<ApiDefinitionEntity>> apiDefinitionEntityDecoder() { return s -> JSON.parseArray(s, ApiDefinitionEntity.class); } /** * 网关flowRule * * @return * @throws Exception */ @Bean public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() { return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class); } @Bean public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() { return JSON::toJSONString; } }
问题就出在sentinel和nacos交互时候
List<GatewayFlowRuleEntity>
和JSON
直接发生了转换, 而实际上sentinel使用的是List<GatewayFlowRule>
Sentinel-Nacos的GatewayFlowRule规则的[增删改查]交互的原流程如下
改造前–dashboard从nacos获取限流规则流程 UML时序图源码
如果对使用代码编写这种时序图感兴趣的, 到时候可以考虑单独出一期教程
改造前–dashboard同步nacos中新增限流规则 UML时序图源码
改造前–dashboard同步nacos中修改限流规则 UML时序图源码
改造前–dashboard同步nacos中删除限流规则 UML时序图源码
将原来的
List<GatewayFlowRuleEntity>
<->JSON
流程中修改成以下
List<GatewayFlowRuleEntity>
<—>List<GatewayFlowRule>
<—>JSON
存储到sentinel中就是
List<GatewayFlowRule>
的JSON而不是原来的List<GatewayFlowRuleEntity>
, 此时限流规则就可以生效了
@Slf4j @Configuration public class NacosConfig { // 其他代码省略.... // -------------- 改动 start -------------- // 注释掉下述代码, 将修改转换规则, 应该将GatewayFlowRuleEntity转换成GatewayFlowRule再转换成JSON /*@Bean public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() { return JSON::toJSONString; }*/ /** * 网关flowRule * * @return * @throws Exception */ @Bean public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() { return entityList -> { List<GatewayFlowRule> ruleList = entityList.stream() .map(GatewayFlowRuleEntity::toGatewayFlowRule) .collect(Collectors.toList()); String jsonStr = JSONObject.toJSONString(ruleList); log.info("转换后的JSON字符串:{}", jsonStr); return jsonStr; }; } // ---------- 规则转换器 end ---------- // -------------- 改动 end -------------- }
将原来的GatewayFlowRulesNacosProvider
类替换成
@Slf4j @Component("gatewayFlowRulesNacosProvider") public class GatewayFlowRulesNacosProvider { @Autowired private ConfigService configService; /** * 获取网关流控规则 * @param app application服务名 * @param ip ip地址 * @param port 端口 * @return 转换号的List<GatewayFlowRuleEntity> * @throws Exception */ public List<GatewayFlowRuleEntity> getRules(String app, String ip, Integer port) throws Exception { String jsonStr = configService.getConfig( app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000); if (StrUtil.isEmpty(jsonStr)) { return new ArrayList<>(); } // 将获取到的JSON字符串转换成GatewayFlowRule列表 List<GatewayFlowRule> ruleList = JSON.parseArray(jsonStr, GatewayFlowRule.class); // 将GatewayFlowRule列表转换成GatewayFlowRuleEntity列表 List<GatewayFlowRuleEntity> entityList = ruleList.stream() .map(rule -> GatewayFlowRuleEntity.fromGatewayFlowRule(app, ip, port, rule)) .collect(Collectors.toList()); log.info("JSON字符串:{}, " + "JSON->List<GatewayFlowRule>:{}, " + "List<GatewayFlowRule>->List<GatewayFlowRuleEntity>:{},", jsonStr, JSONObject.toJSONString(ruleList), JSONObject.toJSONString(entityList)); return entityList; } }
// -------------- 改动 start --------------
// @Autowired
// @Qualifier("gatewayFlowRulesNacosProvider")
// private DynamicRuleProvider<List<GatewayFlowRuleEntity>> gatewayFlowProvider;
@Autowired
@Qualifier("gatewayFlowRulesNacosProvider")
private GatewayFlowRulesNacosProvider gatewayFlowProvider;
// -------------- 改动 end --------------
时序图如下
改造后–dashboard从nacos中获取限流规则 UML时序图源码
改造后–dashboard同步nacos中新增限流规则 UML时序图源码
改造后–dashboard同步nacos中修改限流规则 UML时序图源码
改造后–dashboard同步nacos中删除限流规则 UML时序图源码
其实笔者在写这块的时候, 参考了大量的博客, 但是那些博客实现了持久化是有缺陷的, sentinel-dashboard中操作缺失能同步到nacos, 但是这里的规则是有问题的, 无法使用的, 和我们理想中的效果大相径庭, 排查的思路大概如下
queryFlowRules
会计算intervalSec
的值, 而这个值又依赖interval
和intervalUnit
, 最后发现有一部操作会将JSON转换成List<GatewayFlowRule>
, 也就说我们JSON必须是List<GatewayFlowRule>
, 到此就恍然大悟了Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。