Sentinel Dashboard集成Nacos

1.前言

当项目上Sentinel Dashboard做流量监控的时候,我们可以通过Sentinel控制台修改限流配置,但当我们使用Nacos作为配置中心动态配置流控规则的时候,问题就来了。

首先我们要明白,Sentinel Dashboard的配置是从机器的内存中加载的,如果使用Nacos、Apollo、Zookeeper等作为我们动态加载限流规则的配置中心的时候,我们的配置信息流向是这样的:

就是说客户端从配置中心获取配置,Sentinel Dashboard又从客户端机器的内存中获取配置。

在这种情况下,Sentinel Dashboard可以修改配置,Nacos也可以修改配置,这就会存在数据一致性问题,我们可以从两方面考虑

1)Nacos修改了配置,Sentinel Dashboard会同步更新吗?答案是肯定的,因为Nacos配置变更会通知客户端,客户端配置变更后也会通知Sentinel Dashboard

2)如果在Sentinel Dashboard修改了配置会通知Nacos吗?答案是不会。但是可以通过修改源码实现。

Sentinel控制台在做流控规则的时候,都会调用Sentinel-Dashboard源码中的 一个名叫:FlowControllerV1的接口类,因为流控规则的所有操作,调用的 接口都是如图所示:

这个路径对应的就是FlowControllerV1这个类,但是同时还存在一个 FlowControllerV2的接口类,这个类主要提供的是流控规则的CURD,这两者有啥区别呢? 

区别在于:V2可以实现指定数据源的规则拉取和发布,这也就意味着Sentinel-Dashboard可以从Nacos等配置中心进行相互通信,从而实现数据一致性,Sentinel开发者已经做好封装,我们改一下源码配置一下就好了(后面会有教程)。这样我们的配置关系就变成了了这样:

2.实战:Sentinel Dashboard集成Nacos

第一步:下载Sentinel源码,本案例用的是Sentinel-v1.8.6

Sentinel官网下载地址:

https://github.com/alibaba/Sentinel/releases

下载好之后,解压,import project,可以看到sentinel-dashboard就是我们要改动的spring-boot项目

 

 第二步:将pom.xml中的sentinel-datasource-nacos的scope去掉

 第三步:进入resources/app/scripts/directives/sidebar/sidebar.html,全局搜一下“dashboard.flowV1”,替换成"dashboard.flow",也就是将V1去除:去除之后就 会调用FlowControllerV2中的CURD的接口

 其实Sentinel的开发者已经做好相关的适配,如下图,可以支持集成Apollo、Nacos、Zeekeeper,我们现在是以Nacos为例,进入src/test/java/com.alibaba.csp.sentinel.dashboard.rule.nacos目录,将整个nacos目录及其相关文件复制到src/main/java/com.alibaba.csp.sentinel.dashboard.rule.nacos

注:代码的红叉是因为我复制过去了,相同包名相同class导致的,不必在意,实在强迫症的话,可以把test里面的这几个删掉就好了,不删也不影响运行

 复制过来之后,如下图:

其中NacosConfigUtil就一些常量,我自定义了些常量并改名为NacosConfigConstant了,不在意细节

1.NacosConfigConstant.java

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

public class NacosConfigConstant { 
	public static final String DATA_ID_POSTFIX="-flow-rules";
	public static final String GROUP_ID="SENTINEL_GROUP";  
}

 2.配置nacos相关配置

 2.1: application.properties添加nacos配置:

#config my nacos
sentinel.nacos.serverAddr=192.168.1.105:8848
sentinel.nacos.namespace=
sentinel.nacos.groupId=SENTINEL_GROUP

2.2: 新建Nacos配置类NacosPropertiesConfiguration.java

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "sentinel.nacos")
public class NacosPropertiesConfiguration {
	
	private String serverAddr;
	private String dataId;
	private String groupId;
	private String namespace;

	public String getServerAddr() {
		return serverAddr;
	}

	public void setServerAddr(String serverAddr) {
		this.serverAddr = serverAddr;
	}

	public String getDataId() {
		return dataId;
	}

	public void setDataId(String dataId) {
		this.dataId = dataId;
	}

	public String getGroupId() {
		return groupId;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public String getNamespace() {
		return namespace;
	}

	public void setNamespace(String namespace) {
		this.namespace = namespace;
	}

}

3.FlowRuleNacosProvider.java,稍微改动了一下,如下:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.utils.StringUtils;

@Service("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
	
	@Autowired
	private NacosPropertiesConfiguration nacosPropertiesConfiguration;
	@Autowired
	private ConfigService configService;
	@Autowired
	private Converter<String, List<FlowRuleEntity>> converter;

	/**
	 * @Description: 通过ConfigService.getConfig方法从NacosConfigServer中读取指定配置信息,通过converter转化为FlowRule规则
	 * @Author: LiJianhong
	 * @Param: [appName]
	 * @Return: java.util.List<com.alibaba.csp.sentinel.dashboard.datasource.entity.
	 *          rule.FlowRuleEntity>
	 */
	@Override
	public List<FlowRuleEntity> getRules(String appName) throws Exception {
		String dataId = appName + NacosConfigConstant.DATA_ID_POSTFIX; //user-service-flow-rules
		String groupId = nacosPropertiesConfiguration.getGroupId();
		String rules = configService.getConfig(dataId, groupId, 3000);
		if (StringUtils.isEmpty(rules)) {
			return new ArrayList<>();
		}
		return converter.convert(rules);
	}
}

4.FlowRuleNacosPublisher.java,也是稍微改动了一下:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;

@Service("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
	
	@Autowired
	private NacosPropertiesConfiguration nacosPropertiesConfiguration;
	@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, "appName connot be empty");
		if (rules == null) {
			return;
		}
		String dataId = new StringBuilder(app).append(NacosConfigConstant.DATA_ID_POSTFIX).toString();
		configService.publishConfig(dataId, nacosPropertiesConfiguration.getGroupId(), converter.convert(rules));
	}
	
}

 5. 修改com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2,将注入的bean改成我们改过之后的bean

6.最后mvn clean package打包运行jar即可。

接下来是测试环节:

运行改动后的sentinel-dashboard 

首先,我在Nacos配置中心配置了dataId=user-service-flow-rules限流规则,如下:

[
    {
        "app": "user-service",
        "clusterConfig": {
            "acquireRefuseStrategy": 0,
            "clientOfflineTime": 2000,
            "fallbackToLocalWhenFail": true,
            "flowId": 1001,
            "resourceTimeout": 2000,
            "resourceTimeoutStrategy": 0,
            "sampleCount": 10,
            "strategy": 0,
            "thresholdType": 1,
            "windowIntervalMs": 1000
        },
        "clusterMode": true,
        "controlBehavior": 0,
        "count": 30.0,
        "gmtModified": 1690385332131,
        "grade": 1,
        "id": 1001,
        "limitApp": "default",
        "resource": "com.lee.demo.dubbo.demo.user.ISentinelService",
        "strategy": 0
    },
    {
        "app": "user-service",
        "clusterConfig": {
            "acquireRefuseStrategy": 0,
            "clientOfflineTime": 2000,
            "fallbackToLocalWhenFail": true,
            "flowId": 1002,
            "resourceTimeout": 2000,
            "resourceTimeoutStrategy": 0,
            "sampleCount": 10,
            "strategy": 0,
            "thresholdType": 0,
            "windowIntervalMs": 1000
        },
        "clusterMode": true,
        "controlBehavior": 0,
        "count": 10.0,
        "gmtModified": 1690373927810,
        "grade": 1,
        "id": 1002,
        "limitApp": "default",
        "resource": "com.lee.demo.dubbo.demo.user.IHelloService",
        "strategy": 0
    }
]

com.lee.demo.dubbo.demo.user.ISentinelService的count配置的是30

com.lee.demo.dubbo.demo.user.IHelloService的count配置的是10

然后看下Sentinel-Dashboard的限流规则是与Nacos一致的:

1)在Nacos修改配置查看Sentinel-Dashboard是否更新配置:

可以看到Sentinel-Dashboard的配置是更新了

 2)在Sentinel-Dashboard更新配置,检查是否同步到Nacos,这一步才是验证我们这么辛苦改代码的关键

 可以看到,Nacos成功同步了Sentinel-Dashboard的配置修改

注:我发现改了之后,在Sentinel-Dashboard对配置的CRUD之后,页面没有刷新,要我们手动刷新一下才会看到最新数据~~o(>_<)o ~~,这个我没有过多去排查前端的异常,毕竟我只是后端开发嘛。

至此,Sentinel-Dashboard集成Nacos案例演示完毕。

最后分享一下集成Nacos过程中遇到的问题:

1)Sentinel-Dashboard控制台可以新增限流规则同步Nacos,但是“修改”配置的时候弹出警告“失败”,没提示啥原因,经过debug才发现,是因为新增和修改都需要进行限流规则的参数校验,校验的必要参数如下:

private <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {
        if (entity == null) {
            return Result.ofFail(-1, "invalid body");
        }
        if (StringUtil.isBlank(entity.getApp())) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getLimitApp())) {
            return Result.ofFail(-1, "limitApp can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getResource())) {
            return Result.ofFail(-1, "resource can't be null or empty");
        }
        if (entity.getGrade() == null) {
            return Result.ofFail(-1, "grade can't be null");
        }
        if (entity.getGrade() != 0 && entity.getGrade() != 1) {
            return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
        }
        if (entity.getCount() == null || entity.getCount() < 0) {
            return Result.ofFail(-1, "count should be at lease zero");
        }
        if (entity.getStrategy() == null) {
            return Result.ofFail(-1, "strategy can't be null");
        }
        if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
            return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
        }
        if (entity.getControlBehavior() == null) {
            return Result.ofFail(-1, "controlBehavior can't be null");
        }
        int controlBehavior = entity.getControlBehavior();
        if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {
            return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
        }
        if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {
            return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
        }
        if (entity.isClusterMode() && entity.getClusterConfig() == null) {
            return Result.ofFail(-1, "cluster config should be valid");
        }
        return null;
    }

因此我把Nacos配置中心的限流规则根据这个必要参数都配置了一下之后,再从Sentinel Dashboard修改配置成功了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/49083.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【kubernetes系列】flannel之vxlan模式原理

概述 在Kubernetes中要保证容器之间网络互通&#xff0c;网络至关重要。而Kubernetes本身并没有自己实现容器网络&#xff0c;而是而是借助CNI标准&#xff0c;通过插件化的方式自由接入进来。在容器网络接入进来需要满足如下基本原则&#xff1a; Pod无论运行在任何节点都可…

运算放大器--------加减运算电路

反向求和运算电路 电路 公式 同向加法运算电路 电路 公式 加减运算电路 分别求正向输入的输出和反相输入的输出&#xff0c;然后求和就可以得到到最终的输出。 切记&#xff0c;虚短虚断不是真正的断路和短路。

this关键字和同步异步宏认为微任务理解

目录 js面试常见问题&#xff1a;1.this指向 2.闭包定义和作用 3.原型链 4.异步协程 this关键字 this主要有以下几个使用场合。 1&#xff09;全局环境 &#xff08;2&#xff09;构造函数 &#xff08;3&#xff09;对象的方法 避免多层this 避免数组处理方法中的 this 避免回…

C++(14):重载运算与类型转换

当运算符被用于类类型的对象时&#xff0c;允许我们为其指定新的含义&#xff1b;同时&#xff0c;也能自定义类类型之间的转换规则。和内置类型的转换一样&#xff0c;类类型转换隐式地将一种类型的对象转换成另一种我们所需类型的对象。 当运算符作用于类类型的运算对象时&a…

lc154.寻找旋转排序数组中的最小值

最小元素的位置以旋转次数为索引的位置&#xff0c;但是没有告诉旋转次数&#xff0c;换一种思路 当遇到arr[index] > arr[index1]时&#xff0c;index1为最小元素的位置。首位位置独立比较。但是这种方法还是遍历数组 观察两组数的中间值与首尾的值&#xff0c;又由于数组…

【C++】图

目录 图的存储结构邻接矩阵&#xff08;Adjacency Matrix&#xff09;无向(网)图邻接矩阵代码实现&#xff1a; 邻接表(Adjacency Lists) 图的遍历邻接矩阵深度和广度遍历DFS_BFS邻接表深度和广度遍历DFS_BFS 最小生成树普里姆&#xff08;Prim&#xff09;算法克鲁斯卡尔&…

Spring 6【单例设计模式、bean标签的scope属性、Spring 循环注入问题】(八)-全面详解(学习总结---从入门到深化)

目录 十五、单例设计模式 十六、bean标签的scope属性 十七、Spring 循环注入问题 十五、单例设计模式 设计模式&#xff1a;根据面向对象五大设计思想衍生出的23种常见代码写法&#xff0c;每种写法可以专门解决一类问题。 单例设计模式&#xff1a;保证某个类在整个应用程…

PLC的高端版本通常具有以下特点:

高速处理能力&#xff1a;高端PLC通常具有更快的处理速度和更高的运行频率&#xff0c;可以处理更复杂的控制逻辑和更多的输入/输出信号。 大容量存储&#xff1a;高端PLC通常具有更大的存储容量&#xff0c;可以保存更多的程序和数据&#xff0c;以满足更复杂的应用需求。 多种…

uniapp 选择城市定位 根据城市首字母分类排序

获取城市首字母排序&#xff0c;按字母顺序排序 <template><view class"address-wrap" id"address"><!-- 搜索输入框-end --><template v-if"!isSearch"><!-- 城市列表-start --><view class"address-sc…

基于SSM实现个人随笔分享平台:创作心灵,分享自我

项目简介 本文将对项目的功能及部分细节的实现进行介绍。个人随笔分享平台基于 SpringBoot SpringMVC MyBatis 实现。实现了用户的注册与登录、随笔主页、文章查询、个人随笔展示、个人随笔查询、写随笔、草稿箱、随笔修改、随笔删除、访问量及阅读量统计等功能。该项目登录模…

【C语言day08】

int n5; int a[n][n2] 数组定义下角标不能为变量 注&#xff1a;C99标准中支持了使用变量本题考查的是二维数组的元素访问&#xff0c;A选项是 正确的&#xff0c;X[i]就是第i行的数组名&#xff0c;数组名表示首元素的地址&#xff0c;X[i]表示第i行的第一个元素的地址&#…

Qgis二次开发-QgsMapLayer(加载矢量、栅格图层)

1.简介 QgsMapLayer是所有地图层类型的基类&#xff0c;这是所有地图层类型(矢量&#xff0c;栅格)的基类&#xff0c;首先定义一个QgsMapCanvas地图画布&#xff0c;然后画布上添加图层&#xff0c;使用以下方法设置图层集合。 //设置当前图层集合 void setLayers (const QL…

【c语言进阶】字符函数和字符串函数知识总结

字符函数和字符串函数 前期背景求字符串长度函数strlen函数strlen函数三种模拟实现 长度不受限制的字符串函数strcpy函数strcpy函数模拟实现strcat函数strcat函数模拟实现strcmp函数strcmp函数模拟实现 长度受限制的字符串函数strncpy函数strncpy函数模拟实现strncat函数strnca…

【Qt】QML-02:QQuickView用法

1、先看demo QtCreator自动生成的工程是使用QQmlApplicationEngine来加载qml文件&#xff0c;下面的demo将使用QQuickView来加载qml文件 #include <QGuiApplication> #include <QtQuick/QQuickView>int main(int argc, char *argv[]) {QGuiApplication app(argc,…

electron dialog.showMessageBox使用案例

electron 版本&#xff1a;25.3.1 index.html <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>Hello World!</title><meta http-equiv"Content-Security-Policy" content"script-src self unsa…

MySQL绿色安装和配置

1、 从地址http://dev.mysql.com/downloads/mysql/中选择windows的版本下载。 2、 mysql各个版本的简介 &#xff08;1&#xff09; MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;但不提供官方技术支持。 &#xff08;2&#xff09; MySQL Enterprise Ed…

失去SSL证书,会对网站安全造成什么影响?

作为网络世界中的“身份证”&#xff0c;SSL证书可以在网络世界中证明你是一个真实可信的企业或个人网站&#xff0c;而不是一个钓鱼网站。且在网站的服务器上部署SSL证书后&#xff0c;可以使网站与访问者之间通过SSL协议建立安全的加密连接&#xff0c;确保在Web服务器和浏览…

【Unity细节】关于拉进镜头场景后场景资源消失的问题的解决

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于拉进镜头场景资源消失的问题的解决⭐ 文章目录 ⭐关于拉进镜头场景资源消失…

No100.精选前端面试题,享受每天的挑战和学习(事件循环)

文章目录 1. 请解释一下JavaScript中的事件循环&#xff08;Event Loop&#xff09;是什么&#xff0c;并描述其工作原理。2. 请解释一下JavaScript中的宏任务&#xff08;macro-task&#xff09;和微任务&#xff08;micro-task&#xff09;的区别3. 在事件循环中&#xff0c;…

移动IP的原理

目的 使得移动主机在各网络之间漫游时&#xff0c;仍然能保持其原来的IP地址不变 工作步骤 代理发现与注册 主机A&#xff1a;主机A移动到外地网络后&#xff0c;通过“代理发现协议”&#xff0c;与外地代理建立联系&#xff0c;并从外地代理获得一个转交地址&#xff0c;…