持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
前面已经完成sentinel-dashboard全局配置项和后端部分的源码改造,下面我们进行前端源码改造,并进行双向数据同步的测试和验证:
4. 前端代码修改
① 前端Html页面调整
sidebar.html
找到 webapp/resources/app/scripts/directives/sidebar/sidebar.html 文件,找到以下代码:
<li ui-sref-active="active" ng-if="!entry.isGateway">
<a ui-sref="dashboard.flowV1({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则</a>
</li>
修改为:
<!-- 修改 dashboard.flowV1 为 dashboard.flow-->
<li ui-sref-active="active" ng-if="!entry.isGateway">
<a ui-sref="dashboard.flow({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则</a>
</li>
flow_v2.html
找到webapp/resources/app/views/flow_v2.html文件,找到以下代码:
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})">
回到单机页面
</a>
将其注释掉或删掉。
② 前端Js接口调整
flow_service_v1.js
找到webapp/resources/app/scripts/services/flow_service_v1.js文件,找到以下代码:
this.newRule = function (rule) {
var param = {
resource: rule.resource,
limitApp: rule.limitApp,
grade: rule.grade,
count: rule.count,
strategy: rule.strategy,
refResource: rule.refResource,
controlBehavior: rule.controlBehavior,
warmUpPeriodSec: rule.warmUpPeriodSec,
maxQueueingTimeMs: rule.maxQueueingTimeMs,
app: rule.app,
ip: rule.ip,
port: rule.port
};
return $http({
// url: '/v1/flow/rule',
url: '/v2/flow/rule',
data: rule,
method: 'POST'
});
};
注意:在IDEA中打开JS源文件会提示var创建的变量需要初始化的错误警告,不用管,这是不同IDE的语法检查不同,对代码正确性无影响。
主要是将 url 里的 v1 改为 v2。
identity.js
找到 webapp/resources/app/scripts/controllers/identity.js 文件,找到以下代码:
function saveFlowRule() {
if (!FlowService.checkRuleValid(flowRuleDialogScope.currentRule)) {
return;
}
FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) {
if (data.code === 0) {
flowRuleDialog.close();
// let url = '/dashboard/flow/' + $scope.app;
let url = '/dashboard/v2/flow/' + $scope.app;
$location.path(url);
} else {
alert('失败:' + data.msg);
}
}).error((data, header, config, status) => {
alert('未知错误');
});
}
主要是将跳转到 v1 版本的流控界面改为跳转到 v2 版本的流控界面。
到此,全局依赖和配置、后端代码和前端代码都修改完成了,全部代码的修改都完成了,下面只需要进行编译打包然后进行验证即可。
参考链接:使用Nacos持久化规则,改造sentinel-dashboard
我们下面在编译之前,对全局修改的代码做一个简单的总结:
修改的文件总览
全局依赖和配置类
| 路径 | 说明 |
|---|---|
| sentinel-dashboard/pom.xml | 依赖 |
| sentinel-dashboard/src/main/resources/application.properties | 配置文件 |
后端文件列表
配置类
| 路径 | 说明 |
|---|---|
| com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosPropertiesConfig | 配置类 |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfig |
新增规则交互层部分
| 路径 | 说明 |
|---|---|
| com.alibaba.csp.sentinel.dashboard.rule.nacos.authority.AuthorityRuleNacosProvider | 规则拉取类 |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.authority.AuthorityRuleNacosPublisher | 规则推送类 |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade.DegradeRuleNacosProvider | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade.DegradeRuleNacosPublisher | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.flow.FlowRuleNacosProvider | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.flow.FlowRuleNacosPublisher | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.api.GatewayApiGroupNacosProvider | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.api.GatewayApiGroupNacosPublisher | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.flow.GatewayFlowRuleNacosProvider | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.flow.GatewayFlowRuleNacosPublisher | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.param.ParamRuleNacosProvider | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.param.ParamRuleNacosPublisher | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.system.SystemRuleNacosProvider | |
| com.alibaba.csp.sentinel.dashboard.rule.nacos.system.SystemRuleNacosPublisher |
控制层
| 路径 | 说明 |
|---|---|
| com.alibaba.csp.sentinel.dashboard.controller.gateway.GatewayApiController | 控制层代码 |
| com.alibaba.csp.sentinel.dashboard.controller.gateway.GatewayFlowRuleController | |
| com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2 | |
| com.alibaba.csp.sentinel.dashboard.controller.AuthorityRuleController | |
| com.alibaba.csp.sentinel.dashboard.controller.DegradeController | |
| com.alibaba.csp.sentinel.dashboard.controller.ParamFlowRuleController | |
| com.alibaba.csp.sentinel.dashboard.controller.SystemController |
前端文件列表
| 路径 | 说明 |
|---|---|
| webapp/resources/app/scripts/directives/sidebar/sidebar.html | HTML页面 |
| webapp/resources/app/views/flow_v2.html | |
| webapp/resources/app/scripts/services/flow_service_v1.js | JavaScript脚本 |
| webapp/resources/app/scripts/controllers/identity.js |
基于Push模型的Sentinel-Nacos双向持久化规则,至此改造基本完毕。
下面我们来编译和打包改造完成的sentinel后端和前端源码:
编译和打包sentinel控制台
编译打包前端代码
前端项目编译打包
进入项目 webapp/resources 目录,运行下面的代码安装前端模块所需的node.js依赖:
npm install
然后使用 npm run build命令,进行前端项目打包:
npm run build
注意:这里大概率会遇到gulp版本和node版本不兼容的问题,因为gulp本地全局的2.3.0版本不能适配node 11.15.0以上的版本。
报错信息如下所示:
E:\IdeaProjects\MyProjects\sentinel\sentinel-dashboard\src\main\webapp\resources>npm run build
> sentinel-dashboard@1.0.0 build
> gulp build
fs.js:35
} = primordials;
^
ReferenceError: primordials is not defined
at fs.js:35:5
at req_ (E:\IdeaProjects\MyProjects\sentinel\sentinel-dashboard\src\main\webapp\resources\node_modules\natives\index.js:143:24)
at Object.req [as require] (E:\IdeaProjects\MyProjects\sentinel\sentinel-dashboard\src\main\webapp\resources\node_modules\natives\index.js:55:10)
at Object.<anonymous> (E:\IdeaProjects\MyProjects\sentinel\sentinel-dashboard\src\main\webapp\resources\node_modules\vinyl-fs\node_modules\graceful-fs\fs.js:1:37)
at Module._compile (internal/modules/cjs/loader.js:1158:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
at Module.load (internal/modules/cjs/loader.js:1002:32)
at Function.Module._load (internal/modules/cjs/loader.js:901:14)
at Module.require (internal/modules/cjs/loader.js:1044:19)
at require (internal/modules/cjs/helpers.js:77:18)
通过查找资料了解到gulp不能兼容高版本的node.js,因此上面报错是node和gulp版本不兼容的问题,查询两者的版本信息如下所示:
$ node -v
v16.13.2
$ gulp -v
CLI version: 2.3.0
Local version: Unknown
解决:通过降级或升级node版本的方式(这里是降级node版本的方式)解决。
有两种方式降级或升级node版本:
第一种:直接覆盖降级或升级
npm install -g node@11.15.0
缺点:会覆盖原版本的node.js安装包,会导致依赖覆盖前的node.js项目同样出现版本错误问题
第二种:使用node版本管理工具nvm安装多版本node(推荐)
npm install -g nvm
C:\Users\deepinsea>gulp -v
CLI version: 2.3.0
Local version: Unknown
C:\Users\deepinsea>node -v
v12.16.1
C:\Users\deepinsea>nvm version
1.1.9
C:\Users\deepinsea>nvm install 11.15.0
Downloading node.js version 11.15.0 (64-bit)...
Complete
Downloading npm version 6.7.0... Download interrupted.Rolling back...
Download interrupted.Rolling back...
Error while downloading https://github.com/npm/cli/archive/v6.7.0.zip - http2: response body closed
Complete
Installing npm v6.7.0...
C:\Users\deepinsea>nvm install 11.15.0
Downloading node.js version 11.15.0 (64-bit)...
Complete
Downloading npm version 6.7.0... Complete
Installing npm v6.7.0...
Installation complete. If you want to use this version, type
nvm use 11.15.0
这种方式是通过nvm工具管理node版本,在不兼容的node版本项目上切换到合适的node版本即可;还可以随时切换回去,不会出现node版本丢失问题。
重新使用 npm run builld 命令编译打包项目,可以发现编译成功了:
E:\IdeaProjects\MyProjects\sentinel\sentinel-dashboard\src\main\webapp\resources>npm run build
npm WARN npm npm does not support Node.js v11.15.0
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm You can find the latest version at https://nodejs.org/
> sentinel-dashboard@1.0.0 build
> gulp build
[20:59:02] Using gulpfile E:\IdeaProjects\MyProjects\sentinel\sentinel-dashboard\src\main\webapp\resources\gulpfile.js
[20:59:02] Starting 'clean'...g npm:load:cleanupLog Completed in 2ms
[20:59:02] Finished 'clean' after 101 ms:cleanupLog Completed in 2ms
[20:59:02] Starting 'jshint'...
[20:59:03] Finished 'jshint' after 294 mscleanupLog Completed in 2ms
[20:59:03] Starting 'lib'...
[20:59:03] Finished 'lib' after 408 msad:cleanupLog Completed in 2ms
[20:59:03] Starting 'js'...
[20:59:03] Finished 'js' after 9.32 ms
[20:59:03] Starting 'css'...
[20:59:03] Finished 'css' after 268 msad:cleanupLog Completed in 2ms
[20:59:03] Starting 'build'...
[20:59:03] Finished 'build' after 64 μs
app\scripts\services\flow_service_v1.js: line 18, col 13, 'param' is defined but never used.
app\scripts\services\flow_service_v1.js: line 96, col 29, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v1.js: line 96, col 51, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v1.js: line 97, col 70, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v1.js: line 106, col 36, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v1.js: line 110, col 36, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v1.js: line 114, col 119, Line is too long.
app\scripts\services\flow_service_v1.js: line 75, col 14, 'notNumberAtLeastZero' is defined but never used.
app\scripts\services\flow_service_v1.js: line 85, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 89, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 93, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 98, col 17, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 103, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 107, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 111, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v1.js: line 115, col 13, 'alert' is not defined.
16 errors
app\scripts\services\flow_service_v2.js: line 61, col 29, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v2.js: line 61, col 51, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v2.js: line 62, col 70, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v2.js: line 71, col 36, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v2.js: line 75, col 36, Expected '===' and instead saw '=='.
app\scripts\services\flow_service_v2.js: line 79, col 119, Line is too long.
app\scripts\services\flow_service_v2.js: line 40, col 14, 'notNumberAtLeastZero' is defined but never used.
app\scripts\services\flow_service_v2.js: line 50, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 54, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 58, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 63, col 17, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 68, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 72, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 76, col 13, 'alert' is not defined.
app\scripts\services\flow_service_v2.js: line 80, col 13, 'alert' is not defined.
15 errors
app\scripts\services\degrade_service.js: line 64, col 29, Expected '===' and instead saw '=='.
app\scripts\services\degrade_service.js: line 68, col 35, Expected '===' and instead saw '=='.
app\scripts\services\degrade_service.js: line 72, col 33, Expected '===' and instead saw '=='.
app\scripts\services\degrade_service.js: line 81, col 24, Expected '===' and instead saw '=='.
app\scripts\services\degrade_service.js: line 85, col 24, Expected '===' and instead saw '=='.
app\scripts\services\degrade_service.js: line 86, col 41, Expected '===' and instead saw '=='.
app\scripts\services\degrade_service.js: line 53, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 57, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 61, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 65, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 69, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 73, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 77, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 82, col 11, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 87, col 15, 'alert' is not defined.
app\scripts\services\degrade_service.js: line 91, col 15, 'alert' is not defined.
16 errors
app\scripts\services\systemservice.js: line 23, col 22, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 25, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 27, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 29, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 31, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 46, col 22, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 48, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 50, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 52, col 29, Expected '===' and instead saw '=='.
app\scripts\services\systemservice.js: line 54, col 29, Expected '===' and instead saw '=='.
10 errors
app\scripts\services\param_flow_service.js: line 68, col 109, Line is too long.
app\scripts\services\param_flow_service.js: line 80, col 24, Expected '!==' and instead saw '!='.
app\scripts\services\param_flow_service.js: line 88, col 109, Line is too long.
app\scripts\services\param_flow_service.js: line 77, col 11, 'alert' is not defined.
app\scripts\services\param_flow_service.js: line 81, col 11, 'alert' is not defined.
app\scripts\services\param_flow_service.js: line 85, col 11, 'alert' is not defined.
app\scripts\services\param_flow_service.js: line 89, col 11, 'alert' is not defined.
app\scripts\services\param_flow_service.js: line 96, col 19, 'alert' is not defined.
8 errors
app\scripts\services\authority_service.js: line 43, col 13, 'alert' is not defined.
app\scripts\services\authority_service.js: line 47, col 13, 'alert' is not defined.
app\scripts\services\authority_service.js: line 51, col 13, 'alert' is not defined.
3 errors
app\scripts\services\gateway\api_service.js: line 47, col 7, 'alert' is not defined.
app\scripts\services\gateway\api_service.js: line 53, col 7, 'alert' is not defined.
app\scripts\services\gateway\api_service.js: line 61, col 9, 'alert' is not defined.
app\scripts\services\gateway\api_service.js: line 67, col 7, 'alert' is not defined.
4 errors
虽然有一些警告,但是只是不同编译器的一些语法检查罢了,不影响打包。
问题解决参考:
解决 ReferenceError: primordials is not defined
编译打包后端代码
后端项目打包
进入项目 sentienl-dashboard 目录,运行
mvn clean package
如果嫌打包速度慢,我们可以用两种命令来跳过测试:
mvn clean install -DskipTests
或
mvn clean install -Dmaven.test.skip=true
如果报错,则进入上级目录 sentinel ,执行mvn clean package -Dmaven.test.skip=true 后重新打包。
打包成功后,会在 target 目录下生成 sentinel-dashboard.jar 文件。
也可以直接点击Maven命令栏的工具栏的蓝色闪电⚡图标跳过测试,来进行打包,这样更快捷。
最后,我们得到了在 target 目录下得到了一个名为sentinel-dashboard的jar包:
到此,sentinel-dashboard项目的编译打包工作已经完成了,下面我们启动打包好的jar包,然后连接sentinel客户端端口来进行功能验证:
启动Sentinel控制台
本地前后端项目运行的方式启动sentinel控制台
上面既然已经完成了前后端项目的改造,并且也解决了一些编译和打包的问题,那么我们可以直接通过运行改造好的前后端项目来启动sentinel-dashboard项目:
启动后端项目
我们可以直接在主启动类中点击"▶️"图标启动后端项目,注意Tomcat默认运行的端口为8080,需要更换端口的话在配置文件中配置即可:
运行成功,下面运行前端项目:
启动前端项目
在上面已经安装好了 node_module 依赖,并且编译成功了,这说明启动肯定没有问题(因为编译成功的条件就是没有程序错误)。我们进入到 webapp\resource 目录下,找到 package.json 文件,点击start命令左边的"▶️"图标启动前端项目:
可以看到,前端项目以及成功启动了(控制台哪些error不用管,只是编译器语法检查规则不同,实际上没有错误的),并且自动跳转到了浏览器网页中:
看到错误页面不用慌,并不是启动错误,而是这个默认跳转的路由不存在。我们去掉/index.html后缀即可跳转到sentinel登录界面:
输入账号/密码,即可进入控制台首页:
但是没有服务信息,因为我们打开sentinel-dashboard服务本身的监控信息显示配置选项,也没用客户端进行连接。下面,我们修改sentinel客户端连接的端口为8080,然后启动sentinel客户端:
可以看到,service-sentinel客户端服务成功连接到sentinel控制台,本地IDE运行的方式成功!下面测试Jar包部署运行的方式:
Jar包的方式启动sentinel控制台
使用如下命令启动改造后的控制台:
这里新打包的sentinel-dashboard控制台服务启动端口设置为8850,是为了与前面单向同步Sentine配置l规则的原sentinel-dashboard控制台区分开。
当然,既然更换了端口进行区分,这也就意味着service-sentinel客户端服务需要更换端口为8850来进行适配;如果保持新打包的sentinel-dashboard控制台服务为8849端口,这就可能会产生端口冲突问题,需要停止原来的sentinel控制台服务才能启动这个新的项目。
这其实是一种拥有更多区分性与做更多工作之间代价的开销权衡。
# 完整命令(包含sentinel-dashboard服务本身的流量监控)
java -Dserver.port=8850 -Dcsp.sentinel.dashboard.server=localhost:8850 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar
# 精简命令
java -jar sentinel-dashboard-1.8.3.jar --server.port=8850
上述命令中我们指定几个 JVM 参数,其中 -Dserver.port=8850 是springboot的参数, 用于指定springboot服务端启动端口为 8850,其余几个是 Sentinel 客户端的参数。
我们使用上面的完整命令,来启动sentinel控制台:
Microsoft Windows [版本 10.0.22000.739]
(c) Microsoft Corporation。保留所有权利。
E:\IdeaProjects\MyProjects\sentinel-dashboard-reform\sentinel\v2>java -Dserver.port=8850 -Dcsp.sentinel.dashboard.server=localhost:8850 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar
INFO: Sentinel log output type is: file
INFO: Sentinel log charset is: utf-8
INFO: Sentinel log base directory is: C:\Users\deepinsea\logs\csp\
INFO: Sentinel log name use pid is: false
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )___ | '_ | '_| | '_ / _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.5.RELEASE)
2022-07-21 02:01:15.735 INFO 13176 --- [ main] c.a.c.s.dashboard.DashboardApplication : Starting DashboardApplication on aries with PID 13176 (E:\IdeaProjects\MyProjects\sentinel-dashboard-reform\sentinel\v2\sentinel-dashboard-1.8.3.jar started by deepinsea in E:\IdeaProjects\MyProjects\sentinel-dashboard-reform\sentinel\v2)
2022-07-21 02:01:15.756 INFO 13176 --- [ main] c.a.c.s.dashboard.DashboardApplication : No active profile set, falling back to default profiles: default
2022-07-21 02:01:15.787 INFO 13176 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@574caa3f: startup date [Thu Jul 21 02:01:15 CST 2022]; root of context hierarchy
2022-07-21 02:01:17.179 INFO 13176 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8850 (http)
2022-07-21 02:01:17.199 INFO 13176 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-07-21 02:01:17.199 INFO 13176 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.34
浏览器输入 http://localhost:8850 ,就会跳转到sentinel控制台登录界面,输入sentinel/sentinel 即可登录到首页:
控制台启动成功,下面我们需要配置sentinel客户端连接到控制台来验证改造后的sentinel控制台双向同步规则功能:
测试验证
版本选取
我们的Nacos版本为1.4.1,但是不影响(因为不是跨大版本)。
| 组件 | 版本 |
|---|---|
| nacos | 1.4.2 |
| sentinel | 1.8.2 |
首先我们需要在sentinel客户端的yml文件中,配置Nacos和Sentinel的相关配置;然后在Nacos和Sentinel控制台两端修改流控规则,以测试双向同步功能,并且测试添加和同步过来的流控规则是否生效。
添加本地配置
首先需要将之前配置的 bootstrap.yml 文件重命名为 bootstrap.yml.bak ,即可保留原文件,也可以解除原文件配置生效。
然后在 service-sentinel 服务中,创建新的的bootstrap.yml文件,添加适配双向规则同步的相关配置:
# Nacos-Sentinel双向规则同步配置
# (具体参数参照bootstrap.yml.bak文件,去掉.bak后缀即可恢复为yml文件)
server:
port: 9080
spring:
application:
name: service-sentinel
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
namespace: public
config:
server-addr: localhost:8848
file-extension: yaml
# 配置中心创建文件默认的分组
group: DEFAULT_GROUP
gateway:
enabled: true
discovery:
routes:
- id: service-provider-nacos
uri: lb://service-provider-nacos
predicates:
- Path=/service-provider-nacos/provider-nacos/**
filters:
- StripPrefix=1
- id: service-sentinel
uri: lb://service-sentinel
predicates:
- Path=/service-sentinel/sentinel/**
filters:
- StripPrefix=1
sentinel:
eager: true
filter:
enabled: false
transport:
dashboard: localhost:8850
port: 8721
datasource:
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow
degrade:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
system:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
rule-type: system
authority:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-authority-rules
groupId: SENTINEL_GROUP
rule-type: authority
param-flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-param-flow-rules
groupId: SENTINEL_GROUP
rule-type: param-flow
# 网关api分组
gw-api-group:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-gateway-api-groups
groupId: SENTINEL_GROUP
data-type: json
rule-type: gw-api-group
# 网关限流规则
gw-flow:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-gateway-flow-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: gw-flow
注意:配置文件中的groupId对应着nacos配置中心生效的配置文件分组,dataId的名称和nacos配置中心相同配置才会生效,rule-type与创建的sentinel规则类型相同才会生效(sentinel 1.8.3新限流规则都为gw-flow,为限流规则v2,普通流控规则类型flow为v1)。
启动项目,查看sentinel控制台:
可以看sentinel-dashboard服务本身和service-sentinel客户端服务都成功监控了,sentinel客户端连接成功。
Sentinel控制台不显示原规则配置的问题
注意:因为我们sentinel源码中配置的生效的组ID为SENTINEL_GROUP,原来项目中创建的规则不会同步到sentinel控制台,因此我们也就在新改造的sentinel控制台看不到原来配置的规则,但实际上是生效的。并且在项目启动的时候,控制台会出现以下警告信息:
2022-07-23 20:31:09.066 WARN 25256 --- [update-thread-1] c.a.c.s.d.converter.SentinelConverter : converter can not convert rules because source is empty
这是因为新创建的配置中groupId不是SENTINEL_GROUP,但是这个不影响原配置的生效。
我们测试一下接口,可以看到原规则是生效的:
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: FlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: FlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: FlowException"}
但是将groupId改为SENTINEL_GROUP后,原来的规则配置就不会生效了(以新创建的规则配置为准)。
解决方案
如果一定要原来的DEFAULT_GROUP规则显示的话,我们则需要修改源码中配置的groupId为DEFAULT_GROUP,并且修改sentinel客户端配置中的groupId为DEFAULT_GROUP(这种方式虽然可以使原来的规则生效,但是不推荐;还是建议Sentinel有关的规则配置的组ID都设置为SENTINEL_GROUP,这样具有更好的区分度)。
在前端方面,我们可以添加v1版本的所有<li> 标签来进行原来规则的显示,这样原来的规则也会显示了。
这样我们创建的规则就会默认为DEFAULT_GROUP,并且可以从sentinel控制台同步到原来nacos控制台创建的sentinel规则配置中,如下所示:
并且同步过来的配置也可以生效。
下面我们添加规则,进行配置双向同步测试和规则生效测试:
测试数据双向同步
我们以添加基于api分组的限流规则为例,测试数据双向同步
首先我们需要在API管理中,添加一个基于API分组的API名称,刷新即可看到配置成功添加了:
然后在流控规则中,添加一个基于API分组的限流规则:
然后我们到nacos控制台,查看添加的API分组配置和网关流控规则配置是否成功同步:
可以看到,原来是没有这两个配置文件的,通过sentinel控制台创建之后自动生成了配置文件。这里可以证明:sentinel到nacos的API分组和流控规则配置单向数据同步成功!
然后我们在nacos控制台,删除刚刚创建的基于API分组的限流规则,通过nacos和sentinel控制台两端进行查看验证:
可以看到,nacos控制台删除限流规则配置后,sentinel控制台中的规则也消失了。这里可以证明:nacos到sentinel的流控规则的单向数据同步成功,并且流控规则的nacos-sentinel数据双向同步成功!
并且sentinel-dashboard启动日志中也打印了获取不到 dateway flow rules 的信息:
2022-07-23 20:53:15.232 INFO 29396 --- [nio-8850-exec-2] s.d.r.n.g.f.GatewayFlowRuleNacosProvider : get gateway flow rules from nacos, rules: null
从上面sentinel添加规则到nacos配置中心以及从nacos配置中心删除sentinel规则配置,都测试成功的结果,我们可以管中窥豹的判断:因为规则拉取与推送的实现类的代码原理相同,因此只要有一种规则的拉取和推送测试成功,那么其他类型的规则的拉取和推送也是成功的。因此,可以证明:改造后的sentinel控制台的整体双向数据同步是成功的!
这里只是测试了规则配置的双向同步,但是还没有测试规则是否生效,下面进行测试:
测试规则生效
下面使用下面的curl命令为例,来进行测试:
curl http://localhost:9080/service-sentinel/sentinel/fusing
分别测试基于Route ID和基于API分组的流控规则和熔断规则(还有系统规则就不测试了,但原理是一样的,前面的规则配置生效的话那么系统规则同样生效),进行规则生效测试。
注意:因为原来配置的规则还是会生效,因此我们需要将原来的配置删除或清空配置为"[]",防止原规则干扰新规则的生效性测试。最好是在下面添加规则前先提前测试访问一下接口,快速访问接口不会出现 Blocked Exception 异常才说明原规则没有生效了。
流控规则生效性测试
基于Route ID的流控规则
我们在sentinel控制台创建一个基于Route ID的流控规则,API名称填配置的service-sentinel静态路由名:
创建完成后,可以看到控制台界面出现了创建的流控规则:
并且nacos控制台的配置列表也同步创建了限流规则配置:
下面我们使用curl命令来测试,基于Route ID的限流规则是否生效(需要排除有无其他作用于此接口的规则,防止干扰):
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
可以看到,基于Route ID的限流规则成功生效!
基于API分组的流控规则
我们首先需要删除上面添加的基于Route ID的全局限流规则(防止干扰),然后添加上面删除的基于API分组的限流规则:
点击"刷新"按钮或刷新页面,来刷新界面规则显示:
可以看到,基于API分组的限流规则成功创建,下面我们使用curl命令来进行测试:
curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
可以看到,基于API分组的限流规则生效成功!
降级熔断规则生效性测试
基于Route ID的流控规则
我们先删除上面的限流规则(熔断规则可以基于异常数进行熔断,与限流规则不冲突,但这里为了单一性测试就排除流控规则了),然后添加熔断规则:
可以看到,我们成功创建了基于Route ID的熔断规则配置:
下面我们使用curl命令来进行规则生效测试:
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
通过 Blocked by Sentinel: DegradeException 的阻塞异常提示信息可知,基于Route ID的熔断规则生效成功!
基于API分组的流控规则
删除上面配置的基于Route ID的熔断规则,然后创建基于API分组的熔断规则:
因为我们对源码中请求链路的前端代码进行过改造了,因此我们可以直接在请求链路上添加(降级)熔断规则:
这种方式不需要记住自定义API分组名称,能避免熔断的API名称错误的问题,但是最小请求数需要手动填写(直接在熔断规则创建会默认设置为5)。点击"新增",然后点击"刷新",可以看到"熔断规则"中出现了新增的基于API分组的熔断规则:
下面我们使用curl命令,来测试基于API分组的熔断规则:
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
hi, this is service-sentinel-fusing test!
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
C:\Users\deepinsea>curl http://localhost:9080/service-sentinel/sentinel/fusing
{"code":429,"message":"Blocked by Sentinel: DegradeException"}
测试成功,基于API分组的熔断规则生效成功!
管中窥豹,那么系统规则也是同样的原理,应该也能够生效,也就是说改造后的sentinel控制台的规则都是可以生效的。
整体而言,改造后的sentinel双向数据同步和规则生效都是成功的,验证完成!
欢迎点赞,谢谢各位大佬了ヾ(◍°∇°◍)ノ゙