我也是醉了,Eureka 延迟注册还有这个坑!

Eureka 有个延迟注册的功能,也就是在服务启动成功之后不立刻注册到 Eureka Server,而是延迟一段时间再去注册,这样做的主要目的是因为虽然服务启动成功了,可能还有一些框架或者业务的代码没有初始化完成,可能会导致调用的报错,所以需要延迟注册。

但是发现,然并卵啊,好像这个延迟注册并没有生效,也是开始了排查之路。

延迟注册

首先,延迟注册的功能主要依赖这两个参数, eureka.client.initial-instance-info-replication-interval-seconds代表第一次初始化延迟注册的时间间隔, eureka.client.instance-info-replication-interval-seconds则代表后续同步注册的时间间隔。

eureka.client.initial-instance-info-replication-interval-seconds=40 //默认40秒
eureka.client.instance-info-replication-interval-seconds=30 //默认30秒

我们从源码先来看是怎么做到延迟注册的,先看 DiscoveryClientinitScheduledTasks ,这里创建了同步注册到 Eureka Server 的定时任务。

我也是醉了,Eureka 延迟注册还有这个坑!

之后调用 start 方法创建定时任务,并且延迟 40 秒执行,也就是我们达到的延迟注册的效果。

我也是醉了,Eureka 延迟注册还有这个坑!

我也是醉了,Eureka 延迟注册还有这个坑!

默认的第一次注册,也就是延迟注册的时间是 40 秒,之后每 30 秒会同步注册信息。

我也是醉了,Eureka 延迟注册还有这个坑!

但是,即便我们配置了这俩属性,发现好像没什么卵用,接下来我们要排查下到底是为啥捏?

第一个问题

我发现在 InstanceInfoReplica 中存在这样一段终止当前线程池任务,并且直接调用 run 方法的存在,猜测失效就是他直接调用导致延迟任务没有生效,因为这个方法的直接调用导致延迟注册压根就没效果嘛。

我也是醉了,Eureka 延迟注册还有这个坑!

看起来他存在两个调用,第一个是 registerHealthCheck,当存在这个健康检查什么玩意儿的时候就会去调用 onDemandUpdate

我也是醉了,Eureka 延迟注册还有这个坑!

经过排查我们发现,只要配置了 eureka.client.healthcheck.enabled=true,就会创建 HealthCheckHandler的实例出来,默认情况下他是 false的,所以应该是对我们没有影响的。

我也是醉了,Eureka 延迟注册还有这个坑!

这里需要特别说明一下 eureka.client.healthcheck.enabled的作用,默认 Eureka 根据心跳来决定应用的状态,如果是这个属性配置成 true的话,则是会根据 Spring Boot Actuator 来决定,而不是心跳了。

比如我们可以实现 HealthIndicator接口,自己写一个 Controller来动态改变服务的状态

@RestController
public class ControllerTest {
    @Autowired
    private HealthChecker healthChecker;

    @RequestMapping("/change")
    public String test(Boolean flag) {
        healthChecker.setUp(new AtomicBoolean(flag));
        return "success";
    }

}

实现 HealthChecker,这样会发现启动、下线服务 Eureka Server 的状态不会变成 Down,只有通过调用接口手动改变应用状态 Server 的状态才会发生改变,大家可以自行测试。

@Component
public class HealthChecker extends EurekaHealthIndicator implements HealthIndicator {
    private AtomicBoolean up = new AtomicBoolean(true);

    public HealthChecker(EurekaClient eurekaClient, EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) {
        super(eurekaClient, instanceConfig, clientConfig);
    }

    @Override
    public Health health() {
        if(up.get()){
            return Health.up().build();
        }else{
            return Health.down().build();
        }
    }

第二个问题

第一个问题我们找到了,发现他不是导致我们问题的根因,于是继续排查。

发现第二个调用,在 DiscoveryClient注册了状态事件变更的监听,如果状态发生变更,也会去调用 onDemandUpdate ,影响延迟注册的效果。

这里存在一个配置项 onDemandUpdateStatusChange,默认是 true,所以应该是他没错了。

我也是醉了,Eureka 延迟注册还有这个坑!

进入 StatusChangeListener,找到了一个调用。

我也是醉了,Eureka 延迟注册还有这个坑!

就是通过 setInstanceStatus方法触发的事件通知。

我也是醉了,Eureka 延迟注册还有这个坑!

这里存在 6 个调用,一一排查,通过源码找啊找,最终定位到服务启动自动装配的地方,在这里去修改服务状态为 UP,然后触发事件通知,启动 start 方法调用 register方法。

我也是醉了,Eureka 延迟注册还有这个坑!

继续调用,修改应用为上线 UP状态。

我也是醉了,Eureka 延迟注册还有这个坑!

由此我们知道,只要服务启动成功,就会触发事件通知,所以这个基本上是启动成功立刻就会去注册到 Eureka Server,这就会导致延迟注册的失效,从启动日志也能直观的看到这个效果。

我也是醉了,Eureka 延迟注册还有这个坑!

验证

为了验证我的猜想,我把这两个配置同时配置成 false,并且把延迟注册的时间调整到非常大。

eureka.client.healthcheck.enabled=false
eureka.client.onDemandUpdateStatusChange=false
eureka.client.initial-instance-info-replication-interval-seconds=9999999 //默认40秒
eureka.client.instance-info-replication-interval-seconds=999999 //默认30秒

但是,但是!!!

发现过了几十秒之后,还是注册到 Server 了,真的是醉了。。。

那就继续看吧。

再看下注册方法,可能不止一个地方存在调用,我们发现果然如此,有 3 个地方都调用了注册方法。

我也是醉了,Eureka 延迟注册还有这个坑!

第一个调用在 DiscoveryClient注入的时候,这个看了下, clientConfig.shouldEnforceRegistrationAtInit()默认是 false,方法不会进来,不管他了。

我也是醉了,Eureka 延迟注册还有这个坑!

那么继续看第二个调用,第二个调用你看 renew方法,这一看我们就知道了,这不就是心跳吗?!

发送心跳如果返回 NOT_FOUND,就会去注册了啊。

我也是醉了,Eureka 延迟注册还有这个坑!

我也是醉了,Eureka 延迟注册还有这个坑!

感觉已经接近真相了,去找下 Server 心跳的源码,根据调用的路径找到源码位于 InstanceResource中。

可以看到第一次注册的时候从注册表拿到的实例信息是空的,所以直接返回了 false,就会返回 NOT FOUND 了。

我也是醉了,Eureka 延迟注册还有这个坑!

registry.renew方法,最终会调用到 AbstractInstanceRegistry中,初始化的时候注册表 registry肯定没有当前实例的信息,所以拿到是空的,返回了false,最终就返回了 NOT_FOUND

我也是醉了,Eureka 延迟注册还有这个坑!

因此,虽然我们把这两个参数都设置成了 false,但是由于心跳默认 30 秒一次,所以最终我们发现配置的超级大的延迟注册的时间并没有完全生效。

总结

OK,到此,延迟注册不生效的原因找到了,我们做一个总结。

默认情况下,配置了延迟注册的时间并不会生效,因为事件监听默认是 true,服务启动之后就会立刻注册到 Eureka Server。

如果需要延迟注册生效,必须 eureka.client.healthcheck.enabledeureka.client.onDemandUpdateStatusChange 都为 false

即便我们把所有途径都封死了,但是发送心跳的线程仍然会去注册,所以这个延迟注册的时间最多也不会超过 30 秒,即便配置的延迟时间超过 30 秒。

OK,到此为止,结束,我是艾小仙,欢迎拍砖。

Original: https://www.cnblogs.com/ilovejaney/p/16518063.html
Author: 艾小仙
Title: 我也是醉了,Eureka 延迟注册还有这个坑!

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/608808/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • mybatis plus通过java代码进行权限等全局控制

    在mapper.xml中调用java静态方法,并且传递一些参数 在静态方法中进行sql拼接,可以用于用户权限管理、数据权限管理等等 一、静态方法 拼接sql,可以调用缓存中的用户权…

    Java 2023年6月16日
    074
  • 并查集size rank的优化

    目录 并查集 size 的优化 Java 实例代码 并查集 rank 的优化 Java 实例代码 并查集 size 的优化 按照上一篇文章的思路,我们把如下图所示的并查集,进行 u…

    Java 2023年6月5日
    092
  • 并发编程之:线程

    大家好,我是小黑,一个在互联网苟且偷生的农民工。前段时间公司面试招人,发现好多小伙伴虽然已经有两三年的工作经验,但是对于一些Java基础的知识掌握的都不是很扎实,所以小黑决定开始跟…

    Java 2023年6月7日
    088
  • Spring知识点总结4 SpringMVC

    说说自己对于 Spring MVC 了解? MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代…

    Java 2023年6月6日
    0108
  • java核心技术巩固笔记

    前言 基础知识 高级特性 posted @2022-03-17 10:49 侯小厨 阅读(28 ) 评论() 编辑 Original: https://www.cnblogs.co…

    Java 2023年5月29日
    085
  • Nginx配置https 之 找不到 ./configure

    Nginx配置https 之 找不到 ./configure 需求 要配置个https 问题 找不到文件在哪里 教程很简单,发现就是找不到 ./configure 这个文件这个文件…

    Java 2023年5月30日
    096
  • ngrok-server 服务端搭建

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年5月30日
    080
  • spring中使用mockito

    1 mockito介绍和入门 官方:https://github.com/mockito/mockito 入门: 5分钟了解Mockito http://liuzhijun.ite…

    Java 2023年5月30日
    078
  • TCP 和 UDP 协议简介

    一、TCP TCP(Transmission Control Protocol),传输控制协议,对”传输、发送、通信”进行”控制”的…

    Java 2023年6月7日
    085
  • MySQL知识点1

    本文基于尚硅谷MySQL以及个人部分总结 基本的SELECT语句 SELECT * FROM employees; SELECT employee_id ,last_name ,s…

    Java 2023年6月6日
    081
  • c 的陷阱

    c语言算是非常古老了,像瑞士军刀灵活却也很容易伤到自己,即使是多年的老杆子,以致于市面上都有一本经典的C的书叫《C陷阱与缺陷》的书。 这个文章总结下c中常见的陷阱,可能在日常工作或…

    Java 2023年5月29日
    092
  • Linux(一)——安装

    Linux(一)——安装 一、VMware Workstation Pro (一款虚拟机软件) 1.下载 打开网址https://www.vmware.com/cn.html跟着红…

    Java 2023年6月16日
    070
  • Linux 系统安全加固经验总结

    本文为博主原创,转载请注明出处: 1. 禁止root密码登录 修改 /etc/ssh/sshd_config 中 允许root 用户登录 PermitRootLogin 的值改为 …

    Java 2023年6月8日
    073
  • python使用泛型

    所谓的泛型, 就是将数据类型作为参数进行传递, 即在我们用的时候确定数据类型, 这是一种在面向对象语言中经常使用的特性 一般类使用 以SQLAlchemy举例 比如: 我们统一写个…

    Java 2023年6月7日
    0109
  • 利用redis+AOP简单处理MQ幂等问题

    思路: 1、利用redis内部的串行执行特性,使用getandset()处理分布式+并发问题; 2、注解提供入参选择,通过数据抽取后计算MD5值,实现业务性值的幂等; 代码区: 1…

    Java 2023年6月6日
    0114
  • CentOS7-ElasticSearch的使用

    1.下载 ElasticSearch官方下载地址​www.elastic.co/cn/downloads/past-releases#elasticsearch 最好选择版本7.x…

    Java 2023年6月7日
    082
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球