本文实现基于拉模式的 Alibaba Sentinel 规则持久化。

一、拉模式架构

Alibaba Sentinel 规则持久化-拉模式-基于文件 - 图1

TIPS 图片来自官方。 引用自 https://github.com/alibaba/Sentinel/wiki / 在生产环境中使用 - Sentinel

二、原理简述

  • FileRefreshableDataSource 定时从指定文件中读取规则 JSON 文件【图中的本地文件】,如果发现文件发生变化,就更新规则缓存。
  • FileWritableDataSource 接收控制台规则推送,并根据配置,修改规则 JSON 文件【图中的本地文件】。

三、编写

修改 Spring Cloud Alibaba 微服务。

3.1 加依赖

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-datasource-extension</artifactId>
  4. </dependency>

3.2 写代码

  1. /**
  2. * 拉模式规则持久化
  3. *
  4. * @author itmuch.com
  5. */
  6. public class FileDataSourceInit implements InitFunc {
  7. @Override
  8. public void init() throws Exception {
  9. // TIPS: 如果你对这个路径不喜欢,可修改为你喜欢的路径
  10. String ruleDir = System.getProperty("user.home") + "/sentinel/rules";
  11. String flowRulePath = ruleDir + "/flow-rule.json";
  12. String degradeRulePath = ruleDir + "/degrade-rule.json";
  13. String systemRulePath = ruleDir + "/system-rule.json";
  14. String authorityRulePath = ruleDir + "/authority-rule.json";
  15. String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
  16. this.mkdirIfNotExits(ruleDir);
  17. this.createFileIfNotExits(flowRulePath);
  18. this.createFileIfNotExits(degradeRulePath);
  19. this.createFileIfNotExits(systemRulePath);
  20. this.createFileIfNotExits(authorityRulePath);
  21. this.createFileIfNotExits(paramFlowRulePath);
  22. // 流控规则
  23. ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
  24. flowRulePath,
  25. flowRuleListParser
  26. );
  27. // 将可读数据源注册至FlowRuleManager
  28. // 这样当规则文件发生变化时,就会更新规则到内存
  29. FlowRuleManager.register2Property(flowRuleRDS.getProperty());
  30. WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
  31. flowRulePath,
  32. this::encodeJson
  33. );
  34. // 将可写数据源注册至transport模块的WritableDataSourceRegistry中
  35. // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
  36. WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
  37. // 降级规则
  38. ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
  39. degradeRulePath,
  40. degradeRuleListParser
  41. );
  42. DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
  43. WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
  44. degradeRulePath,
  45. this::encodeJson
  46. );
  47. WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
  48. // 系统规则
  49. ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
  50. systemRulePath,
  51. systemRuleListParser
  52. );
  53. SystemRuleManager.register2Property(systemRuleRDS.getProperty());
  54. WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
  55. systemRulePath,
  56. this::encodeJson
  57. );
  58. WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
  59. // 授权规则
  60. ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
  61. authorityRulePath,
  62. authorityRuleListParser
  63. );
  64. AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
  65. WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
  66. authorityRulePath,
  67. this::encodeJson
  68. );
  69. WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
  70. // 热点参数规则
  71. ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
  72. paramFlowRulePath,
  73. paramFlowRuleListParser
  74. );
  75. ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
  76. WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
  77. paramFlowRulePath,
  78. this::encodeJson
  79. );
  80. ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
  81. }
  82. private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
  83. source,
  84. new TypeReference<List<FlowRule>>() {
  85. }
  86. );
  87. private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
  88. source,
  89. new TypeReference<List<DegradeRule>>() {
  90. }
  91. );
  92. private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
  93. source,
  94. new TypeReference<List<SystemRule>>() {
  95. }
  96. );
  97. private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
  98. source,
  99. new TypeReference<List<AuthorityRule>>() {
  100. }
  101. );
  102. private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(
  103. source,
  104. new TypeReference<List<ParamFlowRule>>() {
  105. }
  106. );
  107. private void mkdirIfNotExits(String filePath) throws IOException {
  108. File file = new File(filePath);
  109. if (!file.exists()) {
  110. file.mkdirs();
  111. }
  112. }
  113. private void createFileIfNotExits(String filePath) throws IOException {
  114. File file = new File(filePath);
  115. if (!file.exists()) {
  116. file.createNewFile();
  117. }
  118. }
  119. private <T> String encodeJson(T t) {
  120. return JSON.toJSONString(t);
  121. }
  122. }

3.3 配置

在项目的 resources/META-INF/services 目录下创建文件,名为 com.alibaba.csp.sentinel.init.InitFunc ,内容为:

  1. # 改成上面FileDataSourceInit的包名类名全路径即可。
  2. com.itmuch.contentcenter.FileDataSourceInit

四、优缺点分析

  • 优点
    • 简单易懂
    • 没有多余依赖(比如配置中心、缓存等)
  • 缺点
    • 由于规则是用 FileRefreshableDataSource 定时更新的,所以规则更新会有延迟。如果 FileRefreshableDataSource 定时时间过大,可能长时间延迟;如果 FileRefreshableDataSource 过小,又会影响性能;
    • 规则存储在本地文件,如果有一天需要迁移微服务,那么需要把规则文件一起迁移,否则规则会丢失。

五、你可能会有的疑问

Spring Cloud Alibaba 不是提供了如下配置了吗?为什么要全部自己写呢?

  1. spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
  2. spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
  3. #spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
  4. #spring.cloud.sentinel.datasource.ds1.file.data-type=custom
  5. #spring.cloud.sentinel.datasource.ds1.file.converter-class=com.alibaba.cloud.examples.JsonFlowRuleListConverter
  6. #spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

关于这个问题,可以看我提的 Issue:https://github.com/alibaba/spring-cloud-alibaba/issues/756

六、参考文档

https://github.com/alibaba/Sentinel/wiki / 在生产环境中使用 - Sentinel#pull 模式

来源丨Alibaba Sentinel 规则持久化 - 拉模式 - 手把手教程【基于文件】
作者丨周立