spring cloud alibaba 应用无法注册到sentinel dashboard

一。技术背景

由于升级jdk17的需要 我们将项目中的 spring cloud spring cloud alibaba 以及springboot进行了升级 各版本如下
spring cloud 2021.0.5
spring cloud alibaba 2021.0.5.0
spring boot 2.6.13

二。问题表现

当启动项目服务后,服务无法注册到 sentinel-dashboard

三。错误排查

  • 首先检查sentinel-dashboard 启动状态 启动成功并且可以正常访问且不存在网络问题
  • 环境配置检查
<!-- 依赖检查 无误 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

配置检查

#配置也正常
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.transport.port=8719
  • 第三步源码追踪

接下来开始漫长源码分析步骤

然后点击 spring.cloud.sentinel.transport.dashboard 这条配置 跳转 com.alibaba.cloud.sentinel.SentinelProperties.Transport#setDashboard

然后点击 getDashboard() 方法查看在哪里调用 最后来到了 com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration#init

在如下代码中

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelAutoConfiguration {@PostConstructprivate void init() {///省略部分逻辑	if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))&& StringUtils.isNotBlank(properties.getTransport().getPort())) {System.setProperty(TransportConfig.SERVER_PORT,properties.getTransport().getPort());}if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))&& StringUtils.isNotBlank(properties.getTransport().getDashboard())) {System.setProperty(TransportConfig.CONSOLE_SERVER,properties.getTransport().getDashboard());}}
}

断点时 发现配置成功被设置到 系统的属性配置中
接下来再来看 心跳发送具体类 HeartbeatSenderInitFunc
com.alibaba.csp.sentinel.transport.init.HeartbeatSenderInitFunc#init

@Override
public void init() {HeartbeatSender sender = HeartbeatSenderProvider.getHeartbeatSender();if (sender == null) {RecordLog.warn("[HeartbeatSenderInitFunc] WARN: No HeartbeatSender loaded");return;}initSchedulerIfNeeded();long interval = retrieveInterval(sender);setIntervalIfNotExists(interval);//定时调度发送心跳scheduleHeartbeatTask(sender, interval);
}

具体得调度逻辑 每5秒发送一次心跳

private void scheduleHeartbeatTask(/*@NonNull*/ final HeartbeatSender sender, /*@Valid*/ long interval) {pool.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {sender.sendHeartbeat();} catch (Throwable e) {RecordLog.warn("[HeartbeatSender] Send heartbeat error", e);}}}, 5000, interval, TimeUnit.MILLISECONDS);RecordLog.info("[HeartbeatSenderInit] HeartbeatSender started: "+ sender.getClass().getCanonicalName());
}

我们再来看下具体的实现
sender.sendHeartbeat();
实现类只有一个 SimpleHttpHeartbeatSender

com.alibaba.csp.sentinel.transport.heartbeat.SimpleHttpHeartbeatSender#sendHeartbeat

@Override                                                                                                     
public boolean sendHeartbeat() throws Exception {                                                             if (TransportConfig.getRuntimePort() <= 0) {                                                              RecordLog.info("[SimpleHttpHeartbeatSender] Command server port not initialized, won't send heartbeat"return false;                                                                                         }                                                                                                         Endpoint addrInfo = getAvailableAddress();                                                                if (addrInfo == null) {                                                                                   return false;                                                                                         }                                                                                                         SimpleHttpRequest request = new SimpleHttpRequest(addrInfo, TransportConfig.getHeartbeatApiPath());       request.setParams(heartBeat.generateCurrentMessage());                                                    try {                                                                                                     SimpleHttpResponse response = httpClient.post(request);                                               if (response.getStatusCode() == OK_STATUS) {                                                          return true;                                                                                      } else if (clientErrorCode(response.getStatusCode()) || serverErrorCode(response.getStatusCode())) {  RecordLog.warn("[SimpleHttpHeartbeatSender] Failed to send heartbeat to " + addrInfo              + ", http status code: " + response.getStatusCode());                                         }                                                                                                     } catch (Exception e) {                                                                                   RecordLog.warn("[SimpleHttpHeartbeatSender] Failed to send heartbeat to " + addrInfo, e);             }                                                                                                         return false;                                                                                             
}                                                                                                             

以上就是发送心跳的逻辑
核心逻辑

  • 获取有效的链接
  • 创建连接发送心跳请求
  • 响应以及异常处理

但是在断点过程中 有效的链接列表居然是空的 这就是导致代码无法继续向下
在这里插入图片描述
然后我们继续围绕这个点进行排查

获取有效的地址列表方法如下

private Endpoint getAvailableAddress() {if (addressList == null || addressList.isEmpty()) {return null;}if (currentAddressIdx < 0) {currentAddressIdx = 0;}int index = currentAddressIdx % addressList.size();return addressList.get(index);
}

发现使用的成员变量 addressList 我们再来找下这个值的赋值操作

赋值操作只有一个地方 在SimpleHttpHeartbeatSender的构造方法中

public SimpleHttpHeartbeatSender() {// Retrieve the list of default addresses.List<Endpoint> newAddrs = TransportConfig.getConsoleServerList();if (newAddrs.isEmpty()) {RecordLog.warn("[SimpleHttpHeartbeatSender] Dashboard server address not configured or not available");} else {RecordLog.info("[SimpleHttpHeartbeatSender] Default console address list retrieved: {}", newAddrs);}this.addressList = newAddrs;
}

com.alibaba.csp.sentinel.transport.config.TransportConfig#getConsoleServerList

public static List<Endpoint> getConsoleServerList() {String config = SentinelConfig.getConfig(CONSOLE_SERVER);List<Endpoint> list = new ArrayList<Endpoint>();if (StringUtil.isBlank(config)) {return list;}//。。。。。省略部分return list;
}

com.alibaba.csp.sentinel.config.SentinelConfig#getConfig(java.lang.String)

public static String getConfig(String key) {AssertUtil.notNull(key, "key cannot be null");return props.get(key);
}

我们再来看下 props的初始化

在SentinelConfig的静态构造中

static {try {initialize();//加载配置loadProps();resolveAppName();resolveAppType();RecordLog.info("[SentinelConfig] Application type resolved: {}", appType);} catch (Throwable ex) {RecordLog.warn("[SentinelConfig] Failed to initialize", ex);ex.printStackTrace();}
}

com.alibaba.csp.sentinel.config.SentinelConfig#loadProps

private static void loadProps() {///从配置加载中获取配置Properties properties = SentinelConfigLoader.getProperties();for (Object key : properties.keySet()) {setConfig((String) key, (String) properties.get(key));}
}

从SentinelConfigLoader 获取到配置

public static Properties getProperties() {return properties;
}

而这个properties的初始化是在SentinelConfigLoader 静态构造方法中

static {try {load();} catch (Throwable t) {RecordLog.warn("[SentinelConfigLoader] Failed to initialize configuration items", t);}
}
private static void load() {// Order: system property -> system env -> default file (classpath:sentinel.properties) -> legacy pathString fileName = System.getProperty(SENTINEL_CONFIG_PROPERTY_KEY);if (StringUtil.isBlank(fileName)) {fileName = System.getenv(SENTINEL_CONFIG_ENV_KEY);if (StringUtil.isBlank(fileName)) {fileName = DEFAULT_SENTINEL_CONFIG_FILE;}}Properties p = ConfigUtil.loadProperties(fileName);if (p != null && !p.isEmpty()) {RecordLog.info("[SentinelConfigLoader] Loading Sentinel config from {}", fileName);properties.putAll(p);}for (Map.Entry<Object, Object> entry : new CopyOnWriteArraySet<>(System.getProperties().entrySet())) {String configKey = entry.getKey().toString();String newConfigValue = entry.getValue().toString();String oldConfigValue = properties.getProperty(configKey);properties.put(configKey, newConfigValue);if (oldConfigValue != null) {RecordLog.info("[SentinelConfigLoader] JVM parameter overrides {}: {} -> {}",configKey, oldConfigValue, newConfigValue);}}
}

看到这里就大概明白了,因为这是静态代码话 肯定优先初始化,而我们的地址在项目启动bean加载中才会设置到System的Properties里

所以获取的 地址一直是空的。 也无法注册到sentinel-dashboard上

四。解决办法

  • idea 启动类 增加参数 指定dashboard server地址 以及应用名称
-Dcsp.sentinel.dashboard.server=localhost:8080 -Dcsp.sentinel.app.name=gateway-service
  • 启动类设置系统变量
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayServiceApplication {public static void main(String[] args) {System.setProperty("csp.sentinel.dashboard.server","localhost:8080");System.setProperty("csp.sentinel.app.name","gateway-service");SpringApplication.run(GatewayServiceApplication.class, args);}}

五。后续分析旧的版本的依赖对应的实现方式

旧的依赖版本为
springboot 2.3.12.RELEASE
spring cloud Hoxton.SR12
spring cloud alibaba 2.2.9.RELEASE

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UDP简介

UDP 1. UDP格式2. UDP特点3. 差错检验 1. UDP格式 16位UDP长度&#xff0c;表示整个数据报&#xff08;UDP首部UDP数据&#xff09;的最大长度&#xff1b; 如果校验和出错&#xff0c;就会直接丢弃; 2. UDP特点 无连接: 知道对端的IP和端口号就直接进行传输&#xff0c;不需…

C语言 指针变量的大小与指针类型

一、指针变量的大小 例如:int main() {int num 10;int* p &num;char ch w;char* pc &ch;printf("%d\n",sizeof(p));printf("%d\n",sizeof(pc));return 0; }答案分别是 4 和 4 指针变量中存储的是地址&#xff0c;而非前缀类型下的元素&…

Docker安装Grafana以及Grafana应用

Doker基础 安装 1、 卸载旧的版本 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 2、需要的安装包 sudo yum install -y yum-utils 3、设置镜像的仓库 yum-config-m…

2000-2022年全国各地级市绿色金融指数数据

2000-2022年全国各地级市绿色金融指数数据 1、时间&#xff1a;2000-2022年 2、来源&#xff1a;来源&#xff1a;统计局、科技部、中国人民银行等权威机构网站及各种权威统计年鉴&#xff0c;包括全国及各省市统计年鉴、环境状况公报及一些专业统计年鉴&#xff0c;如 《中国…

opencv基础53-图像轮廓06-判断像素点与轮廓的关系(轮廓内,轮廓上,轮廓外)cv2.pointPolygonTest()

点到轮廓的距离 在 OpenCV 中&#xff0c;函数 cv2.pointPolygonTest()被用来计算点到多边形&#xff08;轮廓&#xff09;的最短距离&#xff08;也 就是垂线距离&#xff09;&#xff0c;这个计算过程又称点和多边形的关系测试。该函数的语法格式为&#xff1a; retval cv2…

模板方法模式(Template Method)

模板方法模式是一种行为设计模式&#xff0c;在超类中定义了一个算法的框架&#xff0c;而将一些步骤的实现延迟到子类中&#xff0c;使得子类可重定义该算法的特定步骤。 Template Method is a behavior design pattern. It defines an algorithm framework in the superclas…

企业运单管理教程

随着电子面单的普及&#xff0c;以及商务寄件稳步增加&#xff0c;快递公司为了留住商企客户&#xff0c;推出了月结协议模式寄件。企业可以根据寄件量大小&#xff0c;和快递公司签订月结协议&#xff0c;运费每月结算一次&#xff0c;还能根据自身的寄件量&#xff0c;向快递…

[C语言]深入浅出,带你构建C语言宏观框架

导言&#xff1a; 本文章会带你基本了解C语言&#xff0c;对他有一个感性的认识&#xff0c;对其有一个框架&#xff0c;后期在对其进行更加细致的补充。 文章目录 C语言第一个函数变量局部变量 与 全局变量常量字符串 与 转义字符 头文件分支 与 循环注释数组关键字操作符宏指…

VS + Qt Include宏指向的路径错误或者project特性的值无效

如果你电脑上有多个Qt版本&#xff0c;不同项目又依赖不同的Qt版本&#xff0c;就会偶尔出现Qt Include宏指向的Qt路径并不是当前依赖的Qt路径。有时候还会出现project特性的值无效&#xff0c;路径中含有非法字符错误&#xff0c;如下图所示 这个问题的解决办法就是删除工程目…

Docker容器监控(Cadvisor +Prometheus+Grafana)

环境部署&#xff0c;接着上一篇文章Docker容器部署&#xff08;Cadvisor InfluxDBGrafana&#xff09;开始 目录 1、先清理一下容器 2、部署Cadvisor 3、访问Cadvisor页面 4、部署Prometheus 5、准备配置 6、运行prometheus容器 7、访问prometheus页面 8、部署Grafan…

软件测试面试题——如何测试App性能?

为什么要做App性能测试&#xff1f; 如果APP总是出现卡顿或网络延迟的情况&#xff0c;降低了用户的好感&#xff0c;用户可能会抛弃该App&#xff0c;换同类型的其他应用。如果APP的性能较好&#xff0c;用户体验高&#xff0c;使用起来丝滑顺畅&#xff0c;那该应用的用户粘…

Spring IoC 详解

目录 一、引言二、Spring Bean三、将一个类声明为 Bean 所涉及的注解四、Component 和 Bean 的区别五、注入 Bean 的注解六、Autowired 和 Resource 的区别七、Bean7.1 作用域7.2 线程安全7.3 生命周期 一、引言 IoC&#xff08;Inversion of Control:控制反转&#xff09; 是…

【01】基础知识:typescript安装及使用,开发工具vscode配置

一、typescript 了解 typeScript 是由微软开发的一款开源的编程语言。 typeScript 是 javascript 的超级&#xff0c;遵循最新的 es6、es5规范。 typeScript 扩展了 javaScript 的语法。 typeScript 更像后端 java、C# 这样的面向对象语言&#xff0c;可以让 js 开发大型企…

CANdelaStudio 使用介绍

CANdela Studio使用_哔哩哔哩_bilibili 一.CANdelaStudio使用tips 1.开始菜单打开软件&#xff0c;避免软件字体是德文的 2.打开软件之后&#xff0c;用“Open”打开.cdd或者.cddt文件&#xff0c;不要双击文件打开&#xff0c;这样容易报错 3.查看软件版本信息 4.只有Admin版…

探索规律:Python地图数据可视化艺术

文章目录 一 基础地图使用二 国内疫情可视化图表2.1 实现步骤2.2 完整代码2.3 运行结果 一 基础地图使用 使用 Pyecharts 构建地图可视化也是很简单的。Pyecharts 支持多种地图类型&#xff0c;包括普通地图、热力图、散点地图等。以下是一个构建简单地图的示例&#xff0c;以…

灰度均衡变换之c++实现(qt + 不调包)

1.基本原理 灰度均衡是以累计分布函数变换为基础的直方图修正法&#xff0c;它可以产生一副灰度级分布概率均匀的图像。也就是说&#xff0c;经过灰度均衡后的图像在没一级灰度上像素点的数量相差不大。公式见下图&#xff0c;为灰度值为x的像素点的个数&#xff0c;n为总像素点…

回归预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门…

十一、结合数字孪生与时间技术进行多维分析设计与实施

大数据可视化中心以主题为分析对象,选择业务分类下的某个主题,可以在数据面板中展示其二维图表,在地图中标记其空间分布,并叠加其相应的二维或三维图层。 1、界面设计 其主界面设计详上图,各部分功能介绍如下: 1.1、主题与图层面板,从上到下,从左到右分别是: ①折…

高压放大器如何正常使用的呢

高压放大器是一种用于将低电压信号转换成高电压信号的电子设备。它广泛应用于通信、雷达、医疗设备等领域。正确使用高压放大器对于保证设备的正常运行和延长使用寿命至关重要。下面安泰将介绍高压放大器的使用方法和注意事项&#xff0c;帮助您更好地了解如何正确使用高压放大…

Python基础小项目

今天给大家写一期特别基础的Python小项目&#xff0c;欢迎大家支持&#xff0c;并给出自己的完善修改 &#xff08;因为我写的都是很基础的&#xff0c;运行速率不是很好的 目录 1. 地铁票价题目程序源码运行截图 2. 购物车题目程序源码运行截图 3. 名片管理器题目程序源码运行…