eureka心跳和服务剔除机制是什么

3 个回答

  • 夜太
    明知不可为而为之就是我最大的诚意
    ### 1.服务剔除 注册到eureka的服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,而服务注册中心并未收到“服务下线”的请求。服务注册中心在启动时会创建一个定时任务,默认每隔一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操作被称为失效剔除。 ### 2.服务保护 我们关停一个服务,很可能会在Eureka面板看到一条警告: 这是触发了Eureka的自我保护机制。当服务未按时进行心跳续约时,Eureka会统计服务实例最近15分钟心跳续约的比例是否低于了85%。 在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。 Eureka在这段时间内不会剔除任何服务实例,直到网络恢复正常。生产环境下这很有效,保证了大多数服务依然可用,不过也有可能获取到失败的服务实例,因此服务调用者必须做好服 务的失败容错。
    发布于 2022-03-10 14:20 •IP属地 西藏
    举报
    评论
    收藏1

  • 蚂蚱
    在漆黑的夜里,你需要一道光照亮夜行的路,我燃烧了我自己,但也造就了你我不能相拥。
    当Eureka-server发现有的实例没有续约超过一定时间,则将该服务从注册列表剔除,该项工作由一个定时任务完成的。 在AbstractInstanceRegistry的postInit方法中,定义EvictionTask定时任务,构建定时器启动该任务,执行任务中剔除方法 evict()。 当该条件成立时,认为服务过期。在Eureka中过期时间默认定义为3个心跳的时间,一个心跳是30秒,因此过期时间是90秒。当该条件成立时,认为服务过期。在Eureka中过期时间默认定义为3个心跳的时间,一个心跳是30秒,因此过期时间是90秒 当以上两个条件之一成立时,判断该实例过期,将该过期实例放入上面创建的列表中。注意这里仅仅是将实例放入List中,并没有实际剔除。 在实际剔除任务前,需要提一下eureka的自我保护机制,当15分钟内,心跳失败的服务大于一定比例时,会触发自我保护机制。 这个值在Eureka中被定义为85%,一旦触发自我保护机制,Eureka会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据。
    发布于 2022-03-05 15:57 •IP属地 安徽
    举报
    评论
    收藏

  • 梅拾璎
    希望有人告诉你开心比对错更重要。
    ### 1、源码分析 在eureka源码中,有个evict(剔除,驱逐,源码位置:com.netflix.eureka.registry.AbstractInstanceRegistry,代码清单5.1)的方法: ``` public void evict(long additionalLeaseMs) { logger.debug("Running the evict task"); if (!isLeaseExpirationEnabled()) { logger.debug("DS: lease expiration is currently disabled."); return; } // We collect first all expired items, to evict them in random order. For large eviction sets, // if we do not that, we might wipe out whole apps before self preservation kicks in. By randomizing it, // the impact should be evenly distributed across all applications. List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>(); for (Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) { Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue(); if (leaseMap != null) { for (Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) { Lease<InstanceInfo> lease = leaseEntry.getValue(); if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) { expiredLeases.add(lease); } } } } // To compensate for GC pauses or drifting local time, we need to use current registry size as a base for // triggering self-preservation. Without that we would wipe out full registry. int registrySize = (int) getLocalRegistrySize(); int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold()); int evictionLimit = registrySize - registrySizeThreshold; int toEvict = Math.min(expiredLeases.size(), evictionLimit); if (toEvict > 0) { logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit); Random random = new Random(System.currentTimeMillis()); for (int i = 0; i < toEvict; i++) { // Pick a random item (Knuth shuffle algorithm) int next = i + random.nextInt(expiredLeases.size() - i); Collections.swap(expiredLeases, i, next); Lease<InstanceInfo> lease = expiredLeases.get(i); String appName = lease.getHolder().getAppName(); String id = lease.getHolder().getId(); EXPIRED.increment(); logger.warn("DS: Registry: expired lease for {}/{}", appName, id); internalCancel(appName, id, false); } } } ``` 在上述代码第4行,做了isLeaseExpirationEnabled(字面意思:是否启用租约到期,即是否开启了服务过期超时机制,开启之后就会将过期的服务进行剔除)的if判断,源码(com.netflix.eureka.registry .PeerAwareInstanceRegistryImpl实现类中,代码清单5.2)如下: ``` @Override public boolean isLeaseExpirationEnabled() { if (!isSelfPreservationModeEnabled()) { // The self preservation mode is disabled, hence allowing the instances to expire. return true; } return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold; } ``` 同样在上述方法开始的第3行也做了isSelfPreservationModeEnabled方法的判断,该方法是判断是否开启了自我保护机制(有关自我保护机制有关说明在第6节),接下来看到第4行的注释翻译如下: 自保存模式被禁用,因此允许实例过期 也就是说如果关闭了自我保护机制,那么直接就允许实例过期,也就是说可以将过期的服务实例剔除。那如果开启了自我保护机制,会做如下判断(代码清单5.3): ``` numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold ``` getNumOfRenewsInLastMin即最后一分钟接收到的心跳总数,numberOfRenewsPerMinThreshold 表示收到一分钟内收到服务心跳数临界值(后简称临界值),也就是说当临界值大于0,且最后一分钟接收到的心跳总数大于临界值时,允许实例过期,他的计算方式源码如下(代码清单5.4): ``` protected void updateRenewsPerMinThreshold() { this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews * (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds()) * serverConfig.getRenewalPercentThreshold()); } ``` 其中: 1. this.expectedNumberOfClientsSendingRenews:接收到的客户端数量 2. serverConfig.getExpectedClientRenewalIntervalSeconds():客户端发送心跳时间的间隔,默认是30秒 3. serverConfig.getRenewalPercentThreshold():一个百分比率阈值,默认是0.85,可以通过配置修改 从上述代码的计算方法可以看出: > 一分钟内收到服务心跳数临界值 = 客户端数量 * (60/心跳时间间隔) * 比率 带入默认值: > 一分钟内收到服务心跳数临界值 = 客户端数量 * (60/30) * 0.85 = 客户端数量 * 1.7 所以假如有总共有10个客户端,那么表示一分钟至少需要收到17次心跳。 所以代码清单的解析就是,如果开启只我保护机制,那么一分钟内收到的心跳数大于一分钟内收到服务心跳数临界值时,则启用租约到期机制,即服务剔除机制。 那么最终回到代码清单的第4行的if判断,即如果没有启用服务剔除机制(即开启了自我保护机制或者一分钟收到的心跳数小于临界值),那么直接return结束,不做任何操作。否则代码继续运行,从代码的第9行注释到最后,可以看出先跳出已过期的服务实例,然后通过随机数的方式将这些已过期的实例进行剔除。 ### 2、总结 #### 心跳机制: 客户端启动后,就会启动一个定时任务,定时向服务端发送心跳数据,告知服务端自己还活着,默认的心跳时间间隔是30秒。 #### 服务剔除机制: 如果开启了自我保护机制,那么所有的服务,包括长时间没有收到心跳的服务(即已过期的服务)都不会被剔除; 如果未开启自我保护机制,那么将判断最后一分钟收到的心跳数与一分钟收到心跳数临界值(计算方法参考5.1节)比较,如果前者大于后者,且后者大于0的话,则启用服务剔除机制; 一旦服务剔除机制开启,则Eureka服务端并不会直接剔除所有已过期的服务,而是通过随机数的方式进行剔除,避免自我保护开启之前将所有的服务(包括正常的服务)给剔除。
    发布于 2022-03-03 10:50 •IP属地 重庆
    举报
    评论
    收藏