转载自   Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则

在之前的两篇教程中我们分别介绍了如何将Sentinel的限流规则存储到Nacos和Apollo中。同时,在文末的思考中,我都指出了这两套整合方案都存在一个不足之处:不论采用什么配置中心,限流规则都只能通过Nacos界面或Apollo界面来完成修改才能得到持久化存储,而在Sentinel Dashboard中修改限流规则虽然可以生效,但是不会被持久化到配置中心。而在这两个配置中心里存储的数据是一个Json格式,当存储的规则越来越多,对该Json配置的可读性与可维护性会变的越来越差。所以,下面我们就来继续探讨这个不足之处,并给出相应的解决方案。本文以Apollo存储为例,下一篇介绍Nacos的改在示例。

问题分析

在实际操作之前,我们先通过下图了解一下之前我们所实现的限流规则持久化方案的配置数据流向图:

  • 蓝色箭头代表了限流规则由配置中心发起修改的更新路径
  • 橙色箭头代表了限流规则由Sentinel Dashboard发起修改的更新路径

从图中可以很明显的看到,Sentinel Dashboard与业务服务之间本身是可以互通获取最新限流规则的,这在没有整合配置中心来存储限流规则的时候就已经存在这样的机制。最主要的区别是:配置中心的修改都可以实时的刷新到业务服务,从而被Sentinel Dashboard读取到,但是对于这些规则的更新到达各个业务服务之后,并没有一个机制去同步到配置中心,作为配置中心的客户端也不会提供这样的逆向更新方法。

改造方案

关于如何改造,现来解读一下官方文档中关于这部分的说明:

要通过 Sentinel 控制台配置集群流控规则,需要对控制台进行改造。我们提供了相应的接口进行适配。

从 Sentinel 1.4.0 开始,我们抽取出了接口用于向远程配置中心推送规则以及拉取规则:

  • DynamicRuleProvider: 拉取规则
  • DynamicRulePublisher: 推送规则

对于集群限流的场景,由于每个集群限流规则都需要唯一的 flowId,因此我们建议所有的规则配置都通过动态规则源进行管理,并在统一的地方生成集群限流规则。

我们提供了新版的流控规则页面,可以针对应用维度推送规则,对于集群限流规则可以自动生成 flowId。用户只需实现 DynamicRuleProvider 和 DynamicRulePublisher 接口,即可实现应用维度推送(URL: /v2/flow)。

这段内容什么意思呢?简单的说就是Sentinel Dashboard通过DynamicRuleProviderDynamicRulePublisher两个接口来获取和更新应用的动态规则。默认情况下,就如上一节中Sentinel Dashboard与各业务服务之间的两个箭头,一个接口负责获取规则,一个接口负责更新规则。

所以,只需要通过这两个接口,实现对配置中心中存储规则的读写,就能实现Sentinel Dashboard中修改规则与配置中心存储同步的效果。

具体的配置数据流向图如下:

其中,绿色箭头为公共公共部分,即:不论从培中心修改,还是从Sentinel Dashboard修改都会触发的操作。这样的话,从上图的两处修改起点看,所有涉及的部分都能获取到一致的限流规则了。

代码实现

下面继续说说具体的代码实现,这里参考了Sentinel Dashboard源码中关于Apollo实现的测试用例。但是由于考虑到与Spring Cloud Alibaba的结合使用,略作修改。

第一步:修改pom.xml中的Apollo OpenAPi的依赖,将<scope>test</scope>注释掉,这样才能在主程序中使用。

<dependency><groupId>com.ctrip.framework.apollo</groupId><artifactId>apollo-openapi</artifactId><version>1.2.0</version><!--<scope>test</scope>-->
</dependency>

第二步:找到resources/app/scripts/directives/sidebar/sidebar.html中的这段代码:

<li ui-sref-active="active"><a ui-sref="dashboard.flowV1({app: entry.app})"><i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则</a>
</li>

修改为:

<li ui-sref-active="active"><a ui-sref="dashboard.flow({app: entry.app})"><i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则</a>
</li>

第三步:在com.alibaba.csp.sentinel.dashboard.rule包下新建一个apollo包,用来编写针对Apollo的扩展实现。

第四步:创建Apollo的配置类,定义Apollo的portal访问地址以及第三方应用访问的授权Token(通过Apollo管理员账户登录,在“开放平台授权管理”功能中创建),具体代码如下:

@Configuration
public class ApolloConfig {@Beanpublic Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {return s -> JSON.parseArray(s, FlowRuleEntity.class);}@Beanpublic ApolloOpenApiClient apolloOpenApiClient() {ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder().withPortalUrl("https://apollo.xxx.com")  // TODO 根据实际情况修改.withToken("open api token") // TODO 根据实际情况修改.build();return client;}}

第五步:实现Apollo的配置拉取实现。

@Component("flowRuleApolloProvider")
public class FlowRuleApolloProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {@Autowiredprivate ApolloOpenApiClient apolloOpenApiClient;@Autowiredprivate Converter<String, List<FlowRuleEntity>> converter;@Value("${env:DEV}")private String env;@Overridepublic List<FlowRuleEntity> getRules(String appName) throws Exception {// flowDataId对应String flowDataId = "sentinel.flowRules";OpenNamespaceDTO openNamespaceDTO = apolloOpenApiClient.getNamespace(appName, env, "default", "application");String rules = openNamespaceDTO.getItems().stream().filter(p -> p.getKey().equals(flowDataId)).map(OpenItemDTO::getValue).findFirst().orElse("");if (StringUtil.isEmpty(rules)) {return new ArrayList<>();}return converter.convert(rules);}
}
  • getRules方法中的appName参数是Sentinel中的服务名称,这里直接通过这个名字获取Apollo配置是由于Apollo中的项目AppId与之一致,如果存在不一致的情况,则需要自己做转换。
  • 这里注入了一个env属性,主要由于我们在使用Apollo的时候,通过启动参数来控制不同环境。所以这样就能在不同环境区分不同的限流配置了。
  • 这里的flowDataId对应各个微服务应用中定义的spring.cloud.sentinel.datasource.ds.apollo.flowRulesKey配置,即:Apollo中使用了什么key来存储限流配置。
  • 其他如Cluster、Namepsace都采用了默认值:default和application,这个读者有特殊需求可以做对应的修改。

第六步:实现Apollo的配置推送实现。

@Component("flowRuleApolloPublisher")
public class FlowRuleApolloPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {@Autowiredprivate ApolloOpenApiClient apolloOpenApiClient;@Autowiredprivate Converter<List<FlowRuleEntity>, String> converter;@Value("${env:DEV}")private String env;@Overridepublic void publish(String app, List<FlowRuleEntity> rules) throws Exception {String flowDataId = "sentinel.flowRules";AssertUtil.notEmpty(app, "app name cannot be empty");if (rules == null) {return;}OpenItemDTO openItemDTO = new OpenItemDTO();openItemDTO.setKey(flowDataId);openItemDTO.setValue(converter.convert(rules));openItemDTO.setComment("modify by sentinel-dashboard");openItemDTO.setDataChangeCreatedBy("apollo");apolloOpenApiClient.createOrUpdateItem(app, env, "default", "application", openItemDTO);// Release configurationNamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();namespaceReleaseDTO.setEmergencyPublish(true);namespaceReleaseDTO.setReleaseComment("release by sentinel-dashboard");namespaceReleaseDTO.setReleasedBy("apollo");namespaceReleaseDTO.setReleaseTitle("release by sentinel-dashboard");apolloOpenApiClient.publishNamespace(app, env, "default", "application", namespaceReleaseDTO);}
}
  • 这里的大部分内容,如:env、flowDataId、app说明与上一步中的实现一致
  • openItemDTO.setDataChangeCreatedBy("apollo");namespaceReleaseDTO.setReleasedBy("apollo");这两句需要注意一下,必须设置存在并且有权限的用户,不然会更新失败。

第七步:修改com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2DynamicRuleProviderDynamicRulePublisher注入的Bean,改为上面我们编写的针对Apollo的实现:

@Autowired
@Qualifier("flowRuleApolloProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleApolloPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

代码示例

本文介绍内容的客户端代码,示例读者可以通过查看下面仓库中的alibaba-sentinel-dashboard-apollo项目:

  • Github:https://github.com/dyc87112/SpringCloud-Learning/
  • Gitee:https://gitee.com/didispace/SpringCloud-Learning/

Sentinel(二十五)之Sentinel Dashboard同步Apollo存储规则相关推荐

  1. Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则

    点击蓝色"程序猿DD"关注我哟 加个"星标",不忘签到哦 在之前的两篇教程中我们分别介绍了如何将Sentinel的限流规则存储到Nacos和Apollo中.同时 ...

  2. Sentinel(二十三)之使用Apollo存储规则

    转载自  Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则 上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则.Apollo是国内用户非常多的配置中心 ...

  3. java常见面试考点(二十五):CAS是什么

    java常见面试考点 往期文章推荐:   java常见面试考点(二十):Elasticsearch 和 solr 的区别   java常见面试考点(二十一):单点登录   java常见面试考点(二十二 ...

  4. 2021年大数据Hadoop(二十五):YARN通俗介绍和基本架构

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 YARN通俗介绍和基本架构 Yarn通俗介绍 Yarn基本 ...

  5. VMware vSphere 服务器虚拟化之二十五 桌面虚拟化之终端服务池

    VMware vSphere 服务器虚拟化之二十五 桌面虚拟化之终端服务池 终端服务池是指由一台或多台微软终端服务器提供服务的桌面源组成的池.终端服务器桌面源可交付多个桌面.它具有以下特征: 1.终端 ...

  6. 未处理异常和C++异常——Windows核心编程学习手札之二十五

    未处理异常和C++异常 --Windows核心编程学习手札之二十五 当一个异常过滤器返回EXCEPTION_CONTINUE_SEARCH标识符时是告诉系统继续上溯调用树,寻找另外的异常过滤器,但当每 ...

  7. linux exec 二程序,二十五、Linux 进程与信号---exec函数

    25.1 介绍 在用 fork 函数创建子进程后,子进程往往要调用一种 exec 函数以执行另一个程序 当进程调用一种 exec 函数时,该进程完全由新程序代换,替换原有进程的正文,而新程序则从其 m ...

  8. 二十五、求单点的最短路径

    二十五.求单点的最短路径 文章目录 二十五.求单点的最短路径 题目描述 解题思路 上机代码 题目描述 求从指定源点出发到各个顶点的最短路径. **假设:**图中结点名均为单个互不相同的字母,权值均&g ...

  9. Python之精心整理的二十五个文本提取及NLP相关的处理案例

    一.提取 PDF 内容 # pip install PyPDF2 安装 PyPDF2 import PyPDF2 from PyPDF2 import PdfFileReader# Creating ...

最新文章

  1. 武大首位女院士逝世,国际再生资源领域最高奖中国第一人,享年80岁
  2. java_内存的划分
  3. 关于毕业租房的一些碎碎念。
  4. pythondjango教程_Python 中Django安装和使用教程详解
  5. Unix下C程序内存泄露检测工具:valgrind的安装使用
  6. Python学习 :函数
  7. c语言如何扩大字体,C语言图形汉字及放大显示程序
  8. 团队作业9——测试与发布(Beta版本)(含展示博客)
  9. [mooc]open course on github
  10. 简单的遗传算法实例(MATLAB版)
  11. zigbee学习之串口通信
  12. HTML页面显示时间——网页数字时钟、钟表
  13. Matlab学习手记——非线性拟合方法:压缩因子粒子群算法
  14. markdown编辑器的基本使用
  15. Google Earth Engine(GEE)——S2影像异常值
  16. 从联邦学习角度聊人工智能隐私
  17. Cannot read properties of undefined (reading ‘extraneous‘) npm install时
  18. 【实验五 一维数组】7-9 sdut-C语言实验- 排序
  19. 深入浅出使用python编程_深入浅出Python元编程
  20. 腾讯云轻量应用服务器CentOS系统使用docker安装tomcat,MySQL 并发布SSM maven项目

热门文章

  1. 7-34 任务调度的合理性 (25 分)(思路加详解+兄弟们冲呀)
  2. php yaf smarty,Yaf 结合用户自定义的视图(模板)引擎Smarty(Yaf + Smarty)
  3. [剑指offer]面试题42:翻转单词顺序 VS左旋转字符串
  4. [蓝桥杯2018初赛]全球变暖-dfs,bfs,连通块
  5. Java Number Math 类
  6. b树与b+树的区别_面试必考:B树、B树、B+树、B*树图文详解
  7. rjdbc读取mysql_R通过RJDBC连接外部数据库 (转)
  8. 【IOI2018】狼人【Kruscal重构树】【主席树】
  9. 2021牛客暑期多校训练营9
  10. CF938E Max History