Eureka常见问题解答

什么情况下会开启自我保护机制?

前提说明

Eureka Server 内部维护了两个变量 :

expectedNumberOfRenewsPerMin :每分钟最大的续约数量,由于客户端是每30秒续约一次,一分钟就是续约2次, count代表的是客户端数量
​
所以这个变量的计算公式 : 客户端数量*2 
​
numberOfRenewsPerMinThreshold : 每分钟最小续约数量, 使用expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold()。

每次客户端来续约时,都会更新一个变量,即每分钟的续约次数 renewsLastMin , 该变量维护着所有客户端每分钟的续约次数。

何时开启

Eureka Server 每60秒会自动清理一下过期的客户端,在清理之前会判断一下 是否需要自我保护,每次都会判断。

@Override
public boolean isLeaseExpirationEnabled() {
    // 是否开启自我保护机制,这是个配置,默认为true
    if (!isSelfPreservationModeEnabled()) {
        return true;
    }
    // 计算是否需要自我保护
    return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
}

何时解除

1.客户端的心跳恢复正常

2.重启服务

具体机制可以细看深入理解Eureka 自我保护机制(五)

 

网络波动,集群同步的问题

Eureka Server 允许同一时刻被任意Eureka Client做写入操作, 当发生客户端向Eureka Server 1发起注册时,明明在Eureka Server注册成功了,但是返回结果的时候,发生网络错误,误让Eureka Client 认为server 1不可用,正好这个时候Eureka Client的状态发生变更(会去修改laseDirtyTimestamp),进而像server 2发起注册, 这个时候问题就来了。

server1 和 server2 上面的实例状态不一致。

但是由于Eureka Server服务有如下机制,可以确保集群状态下数据的最终一致性;

1.当向server 2 注册之后, server 2 会同时向server 1 同步client端的注册信息,server 1由于之前被client注册过,同时也向server 2同步注册信息 , 这就造成了,两个Eureka Server互相同步请求的问题, 这个时候就是 通过 lastDirtyTimestamp这个变量来判定以谁的为准, 谁的lastDirtyTimestamp 大,则以谁的为准。

2.单单通过lastDirtyTimestamp 这个机制,并没有办法保证集群之间的数据一致性,当网络出现异常的之后,集群同步请求一直不成功,同时任务的过期时间已经到了(集群同步是通过发布任务,让多线程批量去处理的,同时任务有过期时间),这个时候会造成集群之间的数据不一致的情况,这个时候,就是通过heatbeat机制, 当心跳发生如下三种情况的是,客户端会重新发起注册:

  1. 当客户端的lastDirtyTimestamp> 大于服务端的instance的lastDirtyTimestamp时候,会认为服务端的信息是无效的,因此无法续约,需要重新发起注册请求。

  2. 服务端的注册信息不存在

  3. 服务端的instance的status = UNKONW, 为什么会出现UNKONW这个状态呢,因为在deleteStatusOverride

的时候存在传入UNKONW的可能性。

通过以上机制,保证了在网络异常的情况下,Eureka Server能够在网络恢复后,达到最终一致性。

 

 

Eureka Server端实例过期,会同步到其他server服务器吗?

实例过期不会同步到集群中其他服务器,每个Eureka Server 内部都有自己的过期定时任务,每个server

自己负责清理自己的,互不相干,会触发同步操作的是如下几个操作,

register 注册

renew 心跳续约

cancle 客户端主动下线

stateUpdate 添加覆盖状态

deleteStateovrride 删除覆盖状态

 

Eureka Client刚启动是否会立即注册?

网上有些误导人的博客,说Eureka Client启动之后会等待40秒之后才会向Eureka Server端注册。

这种说法是错误的, client端启动之后会立马像服务端发起注册,详情请看:2. Eureka 服务注册(二)

 

 

Eureka Server集群宕机后,客户端是否可用?

情景一

Eureka Client 启动的时候,会主动去全量获取一次注册信息,如果这个时候Eureka Server集群

已经宕机,那么Eureka Client端是不可用的。

情景二

如果Eureka Client 启动时全量获取注册信息成功,在之后的运行过程当中,Eureka Server集群宕机了

那么这个时候,Eureka Client是不受影响的,Eureka Client会缓存注册信息在本地,如果后续增量获取

注册信息失败,也不会影响本地现有的注册信息。 唯一影响的是,由于Eureka Client所拥有的数据

得不到更新,这个时候,新增客户端,或者有客户端的信息发生变化,那么Eureka Client是感知不到的。

关于Eureka Client获取注册信息,详情请看:7. Eureka 获取注册信息(七)

 

关键的时间间隔说明

Eureka Client:

更新本地注册信息 默认:30秒

发送心跳 默认:30秒

检查应用信息,如果发生变化,则重新发起注册 默认:30秒

 

Eureka Server:

只读缓存过期时间 默认:30秒

读写缓存过期时间 默认:180秒

清理过期的任务 默认:60秒

租约过期时间 默认:90秒

启动时同步节点数据,为空等待时间 默认:30秒

清空每分钟续约次数 默认:60秒

 

Eureka Client 90秒没有心跳一定会过期吗?

答案是,不一定会过期

情景一

自我保护模式的开启

情景二

Eureka Server中租约过期时间默认是90秒,服务端维护了一个lastUpdaeTimestap这个变量,

用来表示最后修改时间,至于为什么90秒不一定会过期,看下代码即可:

但是由于在续约的时候,更新lastUpdateTimestap是这样的:

public static final int DEFAULT_DURATION_IN_SECS = 90;
// duration = (DEFAULT_DURATION_IN_SECS * 1000);
public void renew() {
    lastUpdateTimestamp = System.currentTimeMillis() + duration;
 
}

由上可以看出,这个地方,更新最后修改时间,是用当前时间加了90秒上去的,那么接下来看下

Eureka Server是如何判断过期的呢。

public boolean isExpired(long additionalLeaseMs) {
    return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs));
}

evictionTimestamp : 为下线时间,在下线操作的时候会更新这个值

其实,主要是看后面一段,撇开additionalLeaseMs这个时间偏差不谈,

当前时间,一定要大于最后修改时间+90秒, 由于最后修改时间,在续约的时候已经加了90秒了

这里再加个90秒,就是180秒,要大于最后修改时间180秒才会被判定为过期。

System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs)

sharedCode源码交流群,欢迎喜欢阅读源码的朋友加群,添加下面的微信, 备注”加群“ 。 

 

 

展开阅读全文

没有更多推荐了,返回首页