Eureka自我保护机制
本文来说下Eureka自我保护机制
文章目录
- 为什么要有自我保护机制
- 重要变量
- 变量更新
- Eureka-Server初始化
- cancle主动下线
- 客户端注册
- 定时器
- 自我保护机制
- 开启
- 解除
- 本文小结
为什么要有自我保护机制
众所周知,Eureka在CAP理论当中是属于AP , 也就说当产生网络分区时,Eureka保证系统的可用性,但不保证系统里面数据的一致性, 举个例子。
当发生网络分区的时候,Eureka-Server和client端的通信被终止,server端收不到大部分的client的续约,这个时候,如果直接将没有收到心跳的client端自动剔除,那么会将可用的client端剔除,这不符合AP理论,所以Eureka宁可保留也许已经宕机了的client端 , 也不愿意将可以用的client端一起剔除。 从这一点上,也就保证了Eureka程序的健壮性,符合AP理论。
重要变量
this.expectedNumberOfRenewsPerMin = count * 2;
this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
expectedNumberOfRenewsPerMin :每分钟最大的续约数量,由于客户端是每30秒续约一次,一分钟就是续约2次, count代表的是客户端数量。
所以这个变量的计算公式 : 客户端数量*2
numberOfRenewsPerMinThreshold : 每分钟最小续约数量, 使用expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold()。
serverConfig.getRenewalPercentThreshold()的默认值为0.85 , 也就是说每分钟的续约数量要大于85% 。
Eureka的自我保护机制,都是围绕这两个变量来实现的, 如果每分钟的续约数量小于numberOfRenewsPerMinThreshold , 就会开启自动保护机制。
在此期间,不会再主动剔除任何一个客户端。
变量更新
Eureka-Server初始化,cancle主动下线, 客户端注册 ,定时器, 这四个场景会更新这两个变量。
Eureka-Server初始化
protected void initEurekaServerContext() throws Exception {// ....省略N多代码// 服务刚刚启动的时候,去其他服务节点同步客户端的数量。int registryCount = this.registry.syncUp();// 这个方法里面计算expectedNumberOfRenewsPerMin的值this.registry.openForTraffic(this.applicationInfoManager, registryCount);// Register all monitoring statistics.EurekaMonitors.registerAllStats();}this.registry.openForTraffic(this.applicationInfoManager, registryCount);@Overridepublic void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {// 此处初始化值,客户端数量*2 this.expectedNumberOfRenewsPerMin = count * 2;// serverConfig.getRenewalPercentThreshold() 默认为0.85this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());// ...省略N多代码// 开启定时清理过期客户端的定时器super.postInit();
}
cancle主动下线
@Overridepublic boolean cancel(final String appName, final String id,final boolean isReplication) {if (super.cancel(appName, id, isReplication)) {replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);synchronized (lock) {if (this.expectedNumberOfRenewsPerMin > 0) {// 重点在这里,,,,,主动下线的时候,需要去更新每分钟最大续约数,// 一个客户端的每30秒续约一次,一分钟就是续约两次,所以需要减2.this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin - 2;this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());}}return true;}return false;
}
客户端注册
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {try {read.lock();// ....省略 N多代码if (existingLease != null && (existingLease.getHolder() != null)) {// ....省略 N多代码} else {synchronized (lock) {if (this.expectedNumberOfRenewsPerMin > 0) {// 重点在这里, 注册一个客户端,一个客户端每分钟需要两次续约,所以这里加2 this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin + 2;this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());}}logger.debug("No previous lease information found; it is new registration");}// ....省略 N多代码} finally {read.unlock();}
}
定时器
在Eureka-Server启动的时候,会进行初始化,执行路径如下:
DefaultEurekaServerContext 》@PostConstruct修饰的initialize()方法》init()
@Overridepublic void init(PeerEurekaNodes peerEurekaNodes) throws Exception {// .... 省略N多代码// 启动定时器scheduleRenewalThresholdUpdateTask();// .... 省略N多代码}private void scheduleRenewalThresholdUpdateTask() {timer.schedule(new TimerTask() {@Overridepublic void run() {updateRenewalThreshold();}}, serverConfig.getRenewalThresholdUpdateIntervalMs(),serverConfig.getRenewalThresholdUpdateIntervalMs());}private void updateRenewalThreshold() {try {Applications apps = eurekaClient.getApplications();// 计算有效的应用实例数量int count = 0;for (Application app : apps.getRegisteredApplications()) {for (InstanceInfo instance : app.getInstances()) {if (this.isRegisterable(instance)) {++count;}}}synchronized (lock) {// 重新计算值if ((count * 2) > (serverConfig.getRenewalPercentThreshold() * numberOfRenewsPerMinThreshold)|| (!this.isSelfPreservationModeEnabled())) {this.expectedNumberOfRenewsPerMin = count * 2;this.numberOfRenewsPerMinThreshold = (int) ((count * 2) * serverConfig.getRenewalPercentThreshold());}}logger.info("Current renewal threshold is : {}", numberOfRenewsPerMinThreshold);} catch (Throwable e) {logger.error("Cannot update renewal threshold", e);}
}
renewalThresholdUpdateIntervalMs : 默认为15分钟serverConfig.getRenewalPercentThreshold() * numberOfRenewsPerMinThreshold 这个地方有个这个比较,当前最小续约数0.85 , 然后呢,count2 要大于他,这个意思,主要是为了防止开启自我保护机制之后,被定时器重新计算了expectedNumberOfRenewsPerMin 和numberOfRenewsPerMinThreshold 的值。
自我保护机制
一句话总结:某时刻某一个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存!
- 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了–因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制来解决这个问题–当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
- 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着。
- 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定。
- 在SpringCloud中,可以使用eureka.server.enable-self-preservation=false禁用自我保护模式【不推荐关闭自我保护机制】
开启
定期清理任务的线程最终执行的是这个方法,这里就直接开始讲
public void evict(long additionalLeaseMs) {logger.debug("Running the evict task");// 是否需要开启自我保护机制,如果需要,那么直接RETURE, 不需要继续往下执行了if (!isLeaseExpirationEnabled()) {logger.debug("DS: lease expiration is currently disabled.");return;}// ..... 省略N多代码,。这下面主要是做服务自动下线的操作的}@Override
public boolean isLeaseExpirationEnabled() {// 是否开启自我保护机制,这是个配置,默认为trueif (!isSelfPreservationModeEnabled()) {return true;}// 计算是否需要自我保护return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
}
从上面可以导,判断是否开启自我保护机制,主要在于计算每分钟最小续约数的值, getNumOfRenewInLastMin()这个获取的是每分钟的续约数量(每个客户端来续约的时候,都是会更新这个值得,每分钟重置一次,有线程去跑的), 如果每分钟的续约数量>最小续约数,则不需要开启自我保护机制, 如果是小于,那么就是需要开启, 所以当返回false的时候,就需要开启自我保护机制了。
PS: 其实说白了,自我保护机制,就是在定时任务执行之前,判断每分钟的续约数量,然后决定是否继续执行下去。因此Eureka Server的过期时间(默认60s) ,客户端的续约时间(默认30s) , 这个配置最好不要更改,如果更改的话就会打破自我保护机制的规则。
解除
解除
- 当服务的网络分区解除之后,客户端能够和服务进行交互时,在续约的时候,更新每分钟的续约数,当每分钟的续约数大于85%时,则自动解除。
- 重启服务
本文小结
本文详细介绍了Eureka自我保护机制。
Eureka自我保护机制相关推荐
- eureka自我保护时间_Spring Cloud Eureka 自我保护机制
自我保护出现 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行. 默认情况下,如果Eureka Serve ...
- Spring Cloud Eureka 自我保护机制
Spring Cloud Eureka 自我保护机制 Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这 ...
- eureka自我保护时间_SpringCloud Eureka自我保护机制
自我保护背景 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行. 默认情况下,如果Eureka Serve ...
- SpringCloud Eureka自我保护机制
转载自 SpringCloud Eureka自我保护机制 自我保护背景 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他 ...
- SpringCloud Eureka自我保护机制介绍及配置
概述:谈到Eureka的自我保护机制时,我们需要知道其中一些客户端和服务端的概念.比如客户端的心跳发送时间间隔.服务续约时间:服务端的服务剔除时间间隔.阈值更新时间间隔. 客户端心跳发送时间间隔(eu ...
- eureka:自我保护机制_对自我怀疑的开发人员:您足够好吗?
eureka:自我保护机制 by Sihui Huang 黄思慧 对自我怀疑的开发人员:您足够好吗? (To self-doubting developers: are you good enough ...
- Spring Cloud Eureka 自我保护机制(EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY)
在本地启动一个Euraka-Server服务(服务注册中心)和一个Euraka-Client服务(服务注册者-应用服务)两个服务.过了一会儿后,在Euraka-Server界面显示:EMERGENCY ...
- 天荒地老修仙功-第六部第二篇:Spring Cloud Eureka自我保护机制
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,但是在保护期内如果 ...
- 深入理解Eureka 自我保护机制(五)
对自我保护的理解: 自我保护的作用是保证服务的稳定性,也就是怕过多的服务心跳失败,是Eureka服务端的问题,而不是客户端的问题,所以为了避免将正常的服务剔除,所以加了保护机制,当然保护机制的话也有可 ...
最新文章
- 二叉树的前序,中序,后序的递归、迭代实现
- 循环map_python函数 map函数—比for还好用的循环
- 转帖:3D音频之双耳效应
- 关于printf()与自增自减运算符结和问题
- 二叉树题目----2 检查两颗树是否相同 和 对称二叉树的判定
- 调试利器:浏览器 Logger
- android studio 安装问题,解决Android Studio的安装问题
- c语言变量定义数组,C语言中数组的定义和使用
- SNMP简单网络管理协议
- android手机禁止休眠_浮窗----手机是否可以一心多用?这个只是开始而已。
- 面试机器学习、数据挖掘、大数据岗位时遇到的各种问题
- python获取磁盘剩余空间的方法
- 如何使用secureCRT连接vmware中的虚拟主机?
- 天梯 L1 Practic1 题解合集
- L2-029 特立独行的幸福 (递归) 有代码详细解析
- 大家都在努力,你凭什么不努力?
- window系统下添加路由的方法
- 如何写系统需求分析书
- 神经网络隐含层节点数
- Scratch案例—在Scratch上制作植物大战僵尸游戏