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 {
	@PostConstruct
	private 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() {
        @Override
        public 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 path
    String 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

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

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

相关文章

开发规范(一):Mysql篇

1. 流程 数据库表结构的修改需要相关人员和Leader一起评审&#xff0c;保证符合涉及规范。 不允许使用root账号&#xff0c;所有开发和测试应当分配指定账号&#xff0c;并授予最小数据库权限 2. 数据库与表规范 表命名规范 常规表表名以 t_开头&#xff0c;t 代表 table 的意思…

安卓逆向 - 某麦网 x-mini-wua x-sgext x-sign x-umt x-utdid

本文仅供学习交流&#xff0c;只提供关键思路不会给出完整代码&#xff0c;严禁用于非法用途&#xff0c;若有侵权请联系我删除&#xff01; 目标app: 5aSn6bqm572ROC41LjQ 目标接口&#xff1a;aHR0cHM6Ly9hY3MubS50YW9iYW8uY29tL2d3L210b3AuZGFtYWkud2lyZWxlc3MuZGlzY292ZX…

vue element 多图片组合预览

定义组件&#xff1a;preview-image <template><div><div class"imgbox"><divclass"preview-img":class"boxClass"v-if"Imageslist 3 ||Imageslist 5 ||Imageslist 7 ||Imageslist 8 ||Imageslist > 9"&…

IK分词器升级,MySQL热更新助一臂之力

ik分词器采用MySQL热更新 ​ 官方所给的IK分词器只支持远程文本文件热更新&#xff0c;不支持采用MySQL热更新&#xff0c;没关系&#xff0c;这难不倒伟大的博主&#xff0c;给哈哈哈。今天就来和大家讲一下如何采用MySQL做热更新IK分词器的词库。 一、建立数据库表 CREATE…

Vue-4.编译器VsCode

准备 Vue-1.零基础学习Vue Vue-2.nodejs的介绍和安装 Vue-3.vue简介 为什么用VsCode VsCode 是Vue官网首推的编译器它是完全免费的 下载安装VsCode 下载地址 安装的时候不停地下一步直到完成即可 安装插件 安装汉化插件 要将 Visual Studio Code&#xff08;VSCode&am…

回归预测 | MATLAB实现基于LSSVM-Adaboost最小二乘支持向量机结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于LSSVM-Adaboost最小二乘支持向量机结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于LSSVM-Adaboost最小二乘支持向量机结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab实现L…

elasticsearch-head 插件

1、elastic 插件说明 **Head** 是第三方提供的一款很优秀的插件&#xff0c;集监控、查询、配置一体的web功能系统&#xff0c;可以在系统中进行创建、删除索引 、文档。以及查询、配置索引等功能&#xff0c;深受广大开发者的喜爱 **Kopf** 是另一个第三方提供的一款很优秀…

云原生k8s---资源限制、探针

目录 一&#xff1a;资源限制 1、资源限制原因 2、Pod 和 容器 的资源请求和限制 3、CPU 资源单位 4、内存 资源单位 5、事例 &#xff08;1&#xff09;事例一 &#xff08;2&#xff09;事例二 二&#xff1a;重启策略 1、重启策略模式 2、事例 三&#xff1a;探针…

微信小程序实现左滑删除

一、效果 二、代码 实现思路使用的是官方提供的 movable-area&#xff1a;注意点&#xff0c;需要设置其高度&#xff0c;否则会出现列表内容重叠的现象。由于movable-view需要向右移动&#xff0c;左滑的时候给删除控件展示的空间&#xff0c;故 movable-area 需要左移 left:…

视觉学习(七)---Flask 框架下接口调用及python requests 实现json字符串传输

在项目实施过程中需要与其他系统进行接口联调&#xff0c;将图像检测的结果传递给其他系统接口&#xff0c;进行逻辑调用。这中间的过程可以通过requests库进行实现。 1.安装requests库 pip install requests2.postman 接口测试 我们先通过postman 了解下接口调用&#xff0…

linux系统服务学习(二)linux下yum源配置实战

文章目录 Linux下yum源配置实战一、Linux下软件包的管理1、软件安装方式2、源码安装的配置过程3、详解源码安装的配置过程&#xff08;定制&#xff09;4、详解编译过程5、安装过程6、axel多线程下载软件源码安装7、使用软链接解决command not found8、使用环境变量解决command…

springcloud3 hystrix实现服务降级,熔断,限流以及案例配置

一 hystrix的作用 1.1 降级&#xff0c;熔断&#xff0c;限流 1.服务降级&#xff1a; A方案出现问题&#xff0c;切换到兜底方案B&#xff1b; 2.服务熔断&#xff1a;触发规则&#xff0c;出现断电限闸&#xff0c;服务降级 3.服务限流&#xff1a;限制请求数量。 二 案例…

【机器学习5】数据处理(二)Pandas:表格处理

Pandas:表格处理 &#x1f31f;&#x1f31f;Pandas三种数据类型✨✨Series数据结构✨✨ DataFrame数据结构&#x1f319;&#x1f319;DataFrame数据的选取&#x1f315;&#x1f315;DataFrame的构建&#x1f315;&#x1f315;选取多行&#x1f315;&#x1f315;选取某一列…

【广州华锐视点】VR燃气轮机故障判断模拟演练系统

VR燃气轮机故障判断模拟演练系统由广州华锐视点开发&#xff0c;是一款基于虚拟现实技术的教育工具&#xff0c;旨在为学生提供一个安全、高效、互动的学习环境&#xff0c;帮助他们更好地掌握燃气轮机的故障诊断技能。 这款VR实训软件能够模拟真实的燃气轮机故障诊断场景&…

JVM---理解jvm之对象已死怎么判断?

目录 引用计数算法 什么是引用 可达性分析算法&#xff08;用的最多的&#xff09; 引用计数算法 定义&#xff1a;在对象中添加一个引用计数器&#xff0c;每当有一个地方引用它时&#xff0c;计数器值就加一&#xff1b;当引用失效时&#xff0c;计数器值就减一&#xff1…

利用python实现批量登录网络设备进行日常巡检

利用python实现批量登录网络设备 实现ensp与物理机互通ensp 配置配置网络设备远程登录 用python实现批量登录常见问题 通过阅读本文可以学习自动化运维相关知识&#xff0c;本文章代码可以直接使用&#xff0c;通过批量登录功能后&#xff0c;可以按照自己意愿进行功能更改与完…

CentOS7最小化安装使用KVM虚拟化

说明&#xff1a;本文初衷在于记录一次实战经验&#xff0c;以便后续参考&#xff0c;不具有任何权威作用&#xff0c;如若对你有帮助深感荣幸&#xff01; 一、环境安装 CentOS Linux release 7.9.2009 (Core)【不带GUI】Xshell 6Xmanager 6 # 执行 export DISPLAY客户端机器…

MongoDB数据库

目录 一、概述 二、安装 三、目录结构 四、MongoDB数据库操作 五、MongoDB数据库备份 一、概述 mongodb是一个nosql数据库&#xff0c;它有高性能、无模式、文档型的特点。是nosql数据库中功能最丰富&#xff0c;最像关系数据库的。数据库格式为BSON 相关概念 实例&…

计算机网络-物理层(二)- 传输方式

计算机网络-物理层&#xff08;二&#xff09;- 传输方式 串型传输与并行传输 串行传输:是指数据是一个比特一个比特依次发送的&#xff0c;因此在发送端和接收端之间&#xff0c;只需要一条数据传输线路即可 并行传输:是指一次发送n个比特而不是一个比特&#xff0c;因此发送…

电脑ip地址怎么改 ip地址怎么改到别的城市

一、ip地址怎么改到别的城市 1.ip地址怎么改到别的城市&#xff0c;1、重启WIFI路由设备 一般手机或电脑在家或公司上网时都是接入到路由器的WIFI网络,再由路由器分配上网IP地址,如果要更换上网IP那么重启路由器设备后,路由器会向网络运营商进行宽带的重新拨号,此时手机或电脑设…