Sentinel改造
一、准备工作
在开始二次开发之前,我们需要将 Sentinel 的代码下载到本地。你可以从GitHub 的 Releases 页面中找到 1.8.2 版本,在该版本下的 Assets 面板中下载 Source code 源文件。
我们把源码下载到本地并解压之后,你就可以将项目导入到开发工具中了。Sentinel 项目下有很多子模块,我们这次主要针对其中的 sentinel-dashboard 子模块做二次开发。整个改造过程按照先后顺序将分为三个步骤:
-
修改 Nacos 依赖项的应用范围,将其打入 jar 包中;
-
后端程序对接 Nacos,将 Sentinel 限流规则同步到 Nacos;
-
开放单独的前端限流规则配置页面。接下来我就带你按照上面的步骤来对 Sentinel 源码做改造。
二、修改 Nacos 依赖项
在 Sentinel 的源码中,sentinel-datasource-nacos 的 scope 是 test,意思是依赖项只在项目编译期的 test 阶段才会生效。所以接下来,你需要将这个依赖项的标签注释掉。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<!-- 将scope注释掉,改为编译期打包 -->
<!--<scope>test</scope>-->
</dependency>
三、 后端程序对接 Nacos
首先,你需要打开 sentinel-dashboard 项目下的 src/test/java 目录(注意是 test 目录而不是 main 目录),然后定位到 com.alibaba.csp.sentinel.dashboard.rule.nacos 包。在这个包下面,你会看到 4 个和 Nacos Config 有关的类,它们的功能描述如下。
-
NacosConfig:初始化 Nacos Config 的连接;
-
NacosConfigUtil:约定了 Nacos 配置文件所属的 Group 和文件命名后缀等常量字段;
-
FlowRuleNacosProvider:从 Nacos Config 上获取限流规则;
-
FlowRuleNacosPublisher:将限流规则发布到 Nacos Config。为了让这些类在 Sentinel 运行期可以发挥作用,你需要在 src/main/java 下创建同样的包路径,然后将这四个文件从 test 路径拷贝到 main 路径下。
接下来,我们要做两件事,一是在 NacosConfig 类中配置 Nacos 连接串,二是在 Controller 层接入 Nacos 做限流规则持久化。
我们先从 Nacos 连接串改起。你需要打开 NacosConfig 类,找到其中的 nacosConfigService 方法。这个方法创建了一个 ConfigService 类,它是 Nacos Config 定义的通用接口,提供了 Nacos 配置项的读取和更新功能。FlowRuleNacosProvider 和 FlowRuleNacosPublisher 这两个类都是基于这个 ConfigService 类实现 Nacos 数据同步的。我们来看一下改造后的代码。
@Bean
public ConfigService nacosConfigService() throws Exception {
// 将Nacos的注册地址引入进来
Properties properties = new Properties();
properties.setProperty("serverAddr", "127.0.0.1:8848");
properties.setProperty("namespace", "dev");
return ConfigFactory.createConfigService(properties);
}
在上面的代码中,我通过自定义的 Properties 属性构造了一个 ConfigService 对象,将 ConfigService 背后的 Nacos 数据源地址指向了 127.0.0.1:8848,并指定了命名空间为 dev。这里我采用了硬编码的方式,你也可以对上面的实现过程做进一步改造,通过配置文件来注入 serverAddr 和 namespace 等属性。
接下来,我们就在 FlowControllerV2 中正式接入 Nacos 吧。FlowControllerV2 对外暴露了 REST API,用来创建和修改限流规则。在这个类的源代码中,你需要修改两个变量的 Qualifier 注解值。你可以参考下面的代码。
@Autowired
// 指向刚才我们从test包中迁移过来的FlowRuleNacosProvider类
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
// 指向刚才我们从test包中迁移过来的FlowRuleNacosPublisher类
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
在代码中,我通过 Qualifier 标签将 FlowRuleNacosProvider 注入到了 ruleProvier 变量中,又采用同样的方式将 FlowRuleNacosPublisher 注入到了 rulePublisher 变量中。FlowRuleNacosProvider 和 FlowRuleNacosPublisher 就是上一步我们刚从 test 目录 Copy 到 main 目录下的两个类。
修改完成之后,FlowControllerV2 底层的限流规则改动就会被同步到 Nacos 服务器了。这个同步工作是由 FlowRuleNacosPublisher 执行的,它会发送一个 POST 请求到 Nacos 服务器来修改配置项。我来带你看一下 FlowRuleNacosPublisher 类的源码。
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
// 底层借助configService与Nacos进行通信
@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;
}
// 发布到Nacos上的配置文件名是:
// app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX
//
// 所属的Nacos group是NacosConfigUtil.GROUP_ID的值
configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules));
}
}
在上面的代码中,FlowRuleNacosPublisher 会在 Nacos Config 上创建一个用来保存限流规则的配置文件,这个配置文件以“application.name”开头,以“-flow-rules”结尾,而且它所属的 Group 为“SENTINEL_GROUP”。这里用到的文件命名规则和 Group 都是通过 NacosConfigUtil 类中的常量指定的,我把这段代码贴在了下面,你可以参考一下。
public final class NacosConfigUtil {
// 这个是Sentinel注册的配置项所在的分组
public static final String GROUP_ID = "SENTINEL_GROUP";
// 流量整形规则的后缀
public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
四、前端页面改造
首先,我们打开 sentinel-dashboard 模块下的 webapp 目录,该目录存放了 Sentinel 控制台的前端页面资源。我们需要改造的文件是 sidebar.html,这个 html 文件定义了控制台的左侧导航栏。
接下来,我们在导航列表中加入下面这段代码,增加一个导航选项,这个选项指向一个全新的限流页面。
<li ui-sref-active="active">
<a ui-sref="dashboard.flow({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则 改造</a>
</li>
如果你点击这个新加入的导航选项,就会定向到一个全新的限流页面,你在这个页面上做的所有修改,都会同步到 Nacos Config。同时,当 Sentinel Dashboard 启动的时候,它也会主动从 Nacos Config 获取上一次配置的限流规则。
五、微服务调整
引入jar
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
添加配置文件
datasource:
# 数据源的key,可以自由命名
depart-flow:
# 指定当前数据源是nacos
nacos:
# 设置Nacos的连接地址、命名空间和Group ID
server-addr: 127.0.0.1:8848
namespace: dev
groupId: SENTINEL_GROUP
#Nacos配置文件格式
data-type: json
# 设置Nacos中配置文件的命名规则
dataId: ${spring.application.name}-flow-rules
# 必填的重要字段,指定当前规则类型是"限流"
rule-type: flow
在上面的配置项中,有几个重要的点需要强调一下。
-
我们在微服务端的 sentinal 数据源中配置的 namespace 和 groupID,一定要和 Sentinal Dashoboard 二次改造中的中的配置相同,否则将无法正常同步限流规则。Sentinal Dashboard 中 namespace 是在 NacosConfig 类中指定的,而 groupID 是在 NacosConfigUtil 类中指定的。
-
dataId 的文件命名规则,需要和 Sentinel 二次改造中的 FlowRuleNacosPublisher 类保持一致,如果你修改了 FlowRuleNacosPublisher 中的命名规则,那么也要在每个微服务端做相应的变更。到这里,我们所有的改造工作就已经完成了,接下来我们就启动程序来验证改造效果吧。
六、验证效果
首先,你需要整体编译 Sentinel 源代码,编译完成之后从命令行进入到 sentinel-dashboard 子模块下的 target 目录,你会看到一个 sentinel-dashboard.jar 文件。启动后测试通过流控规则 改造
添加限流规则,nacos中会自动创建一个新配置文件,重启项目后配置也不会丢失。