Sentinel-配置持久化

上文通过硬编码的方式配置了服务的限流和降级, 在 sentinel 的可视化界面中,也可以直接去设置这些东西,比如下面这样:

image

配置资源名, QPS 阈值,或者线程数等等,这样操作比在微服务应用中写代码要方便一点,但是默认情况下,在可视化界面创建的这些规则都是存在内存中的,服务重启之后就失效了,还得重新再设置一下,这种情况显然是不能接受的,所以要把这些配置给持久化, Sentinel 提供了三种持久化的方式 zookeeper, apollo ,nacos

本文将使用最常见的 zookeeper 来实现 sentinel 的持久化,下面记录一下配置过程,以及配置过程中遇到的一些坑

源码下载

Github 中把 Sentinel 的源码拉下来

这里有一堆项目, 拉下来之后切换到对应版本的分支上去

sentinel-dashboard 修改后端代码

其他代码不用管,只打开 sentinel-dashboard 这个项目

第一步,打开pom文件, 找到 zookeeper 相关配置,如下:

image

这里把这个 <scope>test</scope> 注释掉即可

第二步,项目的test目录下,找到zookeeper的相关配置,如下:

image

之后复制到 com.alibaba.csp.sentinel.dashboard.rule 这个目录下面,如图:

image

这里可以看到 test 目录下已经提供了 zookeeper, apollo ,nacos 这三种持久化方式的代码,需要哪个复制哪个就好了

第三步, 配置 zookeeper 地址, 在 ZookeeperConfig 这个类中,设置自己的 zookeeper 地址

image

第四步, 修改 com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2 这个类,如下:

image

这里只修改 ruleProviderrulePublisher 即可,指定是 zookeeper 相关的类

到这儿后端相关的代码就改造完毕了, 前端方面还有几个要注意的地方

前端代码修改

前端页面上要修改两个html页面, 第一个是 sidebar.html ,如下:

image

这里有两个流控规则的 <li> 标签, 上面一个注释掉, 下面一个 ui-sref 值改成 dashboard.flow({app: entry.app})

然后还有一个界面是 flow_v2.html 修改如图:

image

这里踩的一个坑是,他页面默认调用的是 FlowControllerV1 这个 Controller ,这个类中操作都是在内存中的, 并没有走持久化的操作,我们上面修改的是 FlowControllerV2 , 所以只要让前端调用 FlowControllerV2 这个类中的接口就可以了, 至于前端页面中修改的几个地方的意思就涉及到我的知识盲区了, 总之最重要的一点就是前端调用的接口是要有持久化操作的接口

应用代码修改

上面 sentinel 源码修改完成之后,就可以直接启动了, 之后页面操作的配置数据都会放到 zookeeper 中去, 所以我们在具体应用的代码中,还得从 zookeeper 中读取数据, 修改步骤如下:

引入依赖

1
2
3
4
5
6
<!-- 哨兵持久化配置数据源 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-zookeeper</artifactId>
<version>1.5.2</version>
</dependency>

修改配置文件

1
2
3
4
sentinel:
zookeeper:
address: 127.0.0.1:2181
path: /sentinel_rule_config

这里这个 path 就是 sentinel 存数据的节点, 默认就是 /sentinel_rule_config

加载配置

新建类 SentinelConfig 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Component
class SentinelConfig(
@Value("\${sentinel.zookeeper.address}")
val zkServer: String,

@Value("\${sentinel.zookeeper.path}")
val zkPath: String,

@Value("\${spring.application.name}")
val appName: String
) {

private val log:Logger = LoggerFactory.getLogger(this.javaClass)

override fun toString(): String {
return "SentinelConfig(log=$log, zkServer='$zkServer', zkPath='$zkPath', appName='$appName')"
}

init {
log.info("SentinelConfig:[{}]", this.toString())

// 声明一个zookeeper数据源
// 从zookeeper中根据 $zkPath/$appName 读出一段配置来,然后转成 FlowRule 这个对象
val zookeeperDataSource = ZookeeperDataSource(zkServer, "$zkPath/$appName") { source: String? -> JSON.parseArray(source, FlowRule::class.java) }
// 添加到规则中
FlowRuleManager.register2Property(zookeeperDataSource.property)
}
}

这里也很简单,先从 application 中加载几个属性, 然后在类初始化的时候,声明一个 zookeeper 数据源,然后通过 FlowRuleManager 加载即可

然后之前通过硬编码方式设置的那些规则就都可以删掉了,然后通过可视化界面配置即可

zookeeper版本

这里再记录一个坑, 我用的 zookeeper 版本是 3.4.13, sentinel 项目中使用的 curator 版本是 4.0.1, 这俩是不兼容的,会导致新建数据失败, 解决办法就是排除 curator 中的 zookeeper 依赖,然后再引入我们自己的版本,pom文件修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!--for Zookeeper rule publisher sample-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
<!-- <scope>test</scope>-->
</dependency>

<!--zookeeper-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>

到这儿,持久化的配置就OK了, sentinel 端操作的数据都是放到 zookeeper 端, 然后应用通过 zookeeper 获取数据

总结

sentinel修改流程:

  1. 修改pom文件,支持持久化
  2. 从test中复制持久化配置到代码中
  3. 修改 provider 和 publisher 为对应的持久化类
  4. 修改前端代码调用持久化的接口

应用代码修改流程:

  1. 引入持久化相关的包
  2. 配置zk地址及节点
  3. 读取配置数据源并读取