性能文章>我也是醉了,Eureka 延迟注册还有这个坑!>

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

3周前
223403

前言

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秒

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

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

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

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

第一个问题

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

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

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

这里需要特别说明一下 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,所以应该是他没错了。
8.png

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

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

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

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

验证

为了验证我的猜想,我把这两个配置同时配置成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 个地方都调用了注册方法。
13.png

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

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

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

15.png
16.png

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

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

17.png

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

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

总结

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

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

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

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

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

分类:标签:
请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

多机房灾备实践
2017年主导了公司新机房(100多台服务器规模)建设以及机房切换,前期工作主要是招标选供应商,服务器,网络设备等,定下来后就开始进行采购,2017年过年之前设备到位。年后开始规划实施。下面我就分享下
Kafka的生产者优秀架构设计
前言 Kafka 是一个高吞吐量的分布式的发布订阅消息系统,在全世界都很流行,在大数据项目里面使用尤其频繁。笔者看过多个大数据开源产品的源码,感觉 Kafka 的源码是其中质量比较上乘的一个,这得益于
微服务架构何去何从?
前言微服务架构模式经过5年多的发展,在各行各业如火如荼地应用和实践。如何在企业中优雅地设计微服务架构?是企业面对的一个重要问题。本文将讲述微服务架构1.0设计与实践以及面临问题和破局,最后讲述微服务架
PerfMa童庭坚:全链路压测体系建设方案的思考与实践
日前杭州笨马CTO童庭坚接受了软件质量效能社区的邀请,与行业同仁分享了关于全链路压测体系建设方案的思考与实践。以下为本场直播的核心内容: 系统性能测试的几个痛点在金融、零售快消、物流、新能源等传统行业
记一次存储故障的排查过程
高可用真是一丝细节都不得马虎。平时跑的好好的系统,在相应硬件出现故障时就会引发出潜在的Bug。偏偏这些故障在应用层的表现稀奇古怪,很难让人联想到是硬件出了问题,特别是偶发性出现的问题更难排查。今天,笔
微服务5:服务注册与发现(实践篇)
★微服务系列微服务1:微服务及其演进史微服务2:微服务全景架构 微服务3:微服务拆分策略微服务4:服务注册与发现微服务5:服务注册与发现(实践篇)1 服务注册中心前面我们对业内几种比较常见的注册中心做了介绍:Eureka、Zookeeper、Consul、Etcd。并且在
Eureka服务下线太慢,电话被告警打爆了
导语某年某月的某一天,就像一张破碎的脸。。。错了,重来。某天,忽然发现大量的告警,经过多番调查研究考察(此处省略3000字),发现是由于 Eureka 服务下线太慢,而仍然有大量的请求打进来导致的报错。于是,又经过了大量详细周密的考察和研究,终于找到了问题并且解决了(此处省略5000字)。全文完。
我也是醉了,Eureka 延迟注册还有这个坑!
前言Eureka 有个延迟注册的功能,也就是在服务启动成功之后不立刻注册到 Eureka Server,而是延迟一段时间再去注册,这样做的主要目的是因为虽然服务启动成功了,可能还有一些框架或者业务的代码没有初始化完成,可能会导致调用的报错,所以需要延迟注册。但是发现,然并卵啊,好像这个延迟注册
3
0