当前位置:网站首页>我也是醉了,Eureka 延迟注册还有这个坑!
我也是醉了,Eureka 延迟注册还有这个坑!
2022-07-25 21:26:00 【艾小仙】
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 的定时任务。

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


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

但是,即便我们配置了这俩属性,发现好像没什么卵用,接下来我们要排查下到底是为啥捏?
第一个问题
我发现在 InstanceInfoReplica 中存在这样一段终止当前线程池任务,并且直接调用 run 方法的存在,猜测失效就是他直接调用导致延迟任务没有生效,因为这个方法的直接调用导致延迟注册压根就没效果嘛。

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

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

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

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

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

这里存在 6 个调用,一一排查,通过源码找啊找,最终定位到服务启动自动装配的地方,在这里去修改服务状态为 UP,然后触发事件通知,启动 start 方法调用register方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RqZJ2Fwe-1658740435819)(https://tva1.sinaimg.cn/large/e6c9d24egy1h4j6mnog9zj223u0u0ail.jpg)]
继续调用,修改应用为上线UP状态。

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

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

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

那么继续看第二个调用,第二个调用你看renew方法,这一看我们就知道了,这不就是心跳吗?!
发送心跳如果返回NOT_FOUND,就会去注册了啊。


感觉已经接近真相了,去找下 Server 心跳的源码,根据调用的路径找到源码位于InstanceResource中。
可以看到第一次注册的时候从注册表拿到的实例信息是空的,所以直接返回了 false,就会返回 NOT FOUND 了。

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

因此,虽然我们把这两个参数都设置成了false,但是由于心跳默认 30 秒一次,所以最终我们发现配置的超级大的延迟注册的时间并没有完全生效。
总结
OK,到此,延迟注册不生效的原因找到了,我们做一个总结。
默认情况下,配置了延迟注册的时间并不会生效,因为事件监听默认是true,服务启动之后就会立刻注册到 Eureka Server。
如果需要延迟注册生效,必须 eureka.client.healthcheck.enabled 、eureka.client.onDemandUpdateStatusChange 都为false。
即便我们把所有途径都封死了,但是发送心跳的线程仍然会去注册,所以这个延迟注册的时间最多也不会超过 30 秒,即便配置的延迟时间超过 30 秒。
OK,到此为止,结束,我是艾小仙,欢迎拍砖。
边栏推荐
- 腾讯云数据库的可信可控之路
- 函数栈帧的创建和销毁
- 测试用例和缺陷报告模板
- Explain the principle of MySQL master-slave replication in detail
- NPM module removal_ [solved] after NPM uninstalls the module, the module is not removed from package.json [easy to understand]
- Canvas 填充渐变
- 大厂面试官:千万级数据量的表,如何进行快速查询?
- Matlab---eeglab check EEG signal
- Based on pexels image material API, sort out the material resource library
- H5 realize the animation effect of a scratch card
猜你喜欢

As a test, how to understand thread synchronization and asynchrony

【FiddlerTX插件】使用Fiddler抓包腾讯课堂视频下载(抓不到包解决方案)

Product principles of non-financial decentralized application

Focus on data | Haitai Fangyuan directly hits the construction idea of data security governance in the securities industry

Airtest解决“自动装包”过程中需要输入密码的问题(同适用于随机弹框处理)

2022 latest examination questions and answers of eight members (standard staff) of Shanghai Architecture

Programmer's Guide to health quenching 5: introduction to sports Basics

函数栈帧的创建和销毁

SSH private key realizes login to remote target server

Too many passwords, don't know how to record? Why don't you write a password box applet yourself
随机推荐
Focus on data | Haitai Fangyuan directly hits the construction idea of data security governance in the securities industry
How to copy all files in one folder to another folder
零基础学习CANoe Panel(17)—— Panel CAPL Function
MPI学习笔记(二):矩阵相乘的两种实现方法
Leetcode skimming -- guess the size of numbers II 375 medium
Per capita Swiss number series, Swiss number 4 generation JS reverse analysis
Intel base instruction -- bnd
五、品达通用权限系统__pd-tools-xxs(防跨站脚本攻击)
【网络教程】IPtables官方教程--学习笔记2
Apple estimates that iPhone will give up the Chinese market, and the Chinese industrial chain needs to consider living a hard life
Golang language quickly get started to comprehensive practical notes (go language, beego framework, high concurrency chat room, crawler)
On Web Performance Optimization (1)
seven point two three
An interview question about recover in golang
Add startup software items when the win system starts up
一道golang中关于recover的面试题
CNN structural design skills: taking into account speed accuracy and engineering implementation
全志芯片bsp命名规则
Debugged PEB (beingdebugged, ntglobalflag)
Fusing and degrading Sentinel