Eureka 启动保护机制:
如果在 15 分钟内超过 85% 的节点都没有正常的心跳,那 么Eureka 就认为客户端与注册中心出现了网络故障。
自我保护机制的触发条件:
条件:当每分钟心跳次数( renewsLastMin ) 小于 numberOfRenewsPerMinThreshold 时,并且开启自动保护模式开关( eureka.server.enable-self-preservation = true ) 时,触发自我保护机制,不再自动过期续约。
其中:
numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比( eureka.server.renewalPercentThreshold, 默认0.85 )
expectedNumberOfRenewsPerMin = 当前注册的应用实例数 x 2 。为什么乘以 2: 默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2 。
解释:服务实例数10个,期望每分钟续约数10 2=20,期望阈值20 0.85=17,自我保护少于17时 触发。】
Eureka 启动保护机制会出现以下情况:
引入依赖 spring-cloud-starter-netflix-eureka-server
, 在启动类 Application
上,添加 @EnableEurekaServer
注解。
如果是单机服务,可以在 application.yml
中使用以下配置:
eureka: environment: dev # 设置环境,可选 server: enable-self-preservation: false # 中小规模下,自我保护模式坑比好处多,所以关闭它 renewal-threshold-update-interval-ms: 120000 # 心跳阈值计算周期,如果开启自我保护模式,可以改一下这个配置 eviction-interval-timer-in-ms: 5000 # 主动失效检测间隔,配置成5秒 use-read-only-response-cache: false # 禁用readOnlyCacheMap wait-time-in-ms-when-sync-empty: 0 #在Eureka服务器获取不到集群里对等服务器上的实例时,需要等待的时间,单机模式设置为0 client: healthcheck: true service-url: defaultZone: http://${webfuse-security.user.name}:${webfuse-security.user.password}@localhost:2000/eureka/ registry-fetch-interval-seconds: 5 # 定时刷新本地缓存时间 register-with-eureka: false #表示是否将自己注册到Eureka Server,默认为true。由于当前这个应用就是Eureka Server,故而设为false。 fetch-registry: false #表示是否从Eureka Server获取注册信息,默认为true。因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,故而设为false。 instance: hostname: ${hostname:localhost} instance-id: ${spring.application.name}@${spring.cloud.client.ip-address}:${server.port} # 自定义实例ID prefer-ip-address: true lease-expiration-duration-in-seconds: 10 # 没有心跳的淘汰时间,10秒 lease-renewal-interval-in-seconds: 5 # 心跳间隔,5秒
启动服务,可在 http://localhost:2000
查看项目页面。
EurekaClient 可以在客户端获取eureka服务器上的注册者信息。
引入依赖 spring-cloud-starter-netflix-eureka-client
, 在启动类 Application
上,添加 @EnableDiscoveryClient
注解。
在 application.yml
中使用以下配置:
eureka: environment: dev client: healthcheck: enabled: true service-url: defaultZone: http://user:[email protected]:8010/eureka/ registry-fetch-interval-seconds: 5 # 定时刷新本地缓存时间 instance: hostname: ${hostname:localhost} instance-id: ${spring.application.name}@${spring.cloud.client.ip-address}:${server.port} # 自定义实例ID prefer-ip-address: true lease-expiration-duration-in-seconds: 10 # 没有心跳的淘汰时间,10秒 lease-renewal-interval-in-seconds: 5 # 心跳间隔,5秒
启动项目即可。可在 http://localhost:2000
中看到注册的状态。
Eureka Server 之间是可以互相注册的。
举个例子,我们有 3 个 Eureka 注册中心,端口分别为 2001 、 2002 和 2003 。那么端口为 2001 的最基本的配置如下:
eureka: client: service-url: defaultZone: http://localhost:2002/eureka/,http://localhost:2003/eureka/
端口 2002 和 2003 服务可以根据以上规则配置。
服务器有多个网卡,eh0,eh1,eh2,只有eh0可以让外部其他服务访问进来,而Eureka client将eh1和eh2注册到Eureka server上,这样其他服务就无法访问该微服务了。有两种方式:
指定IP注册
eureka: instance: prefer-ip-address: true ip-address: 实际能访问到的IP
使用 spring.cloud.inetutils 配置网卡选择
由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问。看eureka界面中的status。
比如心跳一直正常,服务一直UP,但是此服务DB连不上了,无法正常提供服务。
此时,我们需要将 微服务的健康状态也同步到server。只需要启动eureka的健康检查就行。这样微服务就会将自己的健康状态同步到eureka。配置如下即可。
在client端加入Actuator,并配置 eureka.client.healthcheck.enabled=true
,将自己真正的健康状态传播到server。
通过代码来改动服务的状态:
@Component @Data public class HealthStatusHandlerimplements HealthIndicator{ private Boolean status = true; @Override public Health health(){ if (status) { return new Health.Builder().up().build(); } return new Health.Builder().down().build(); } }
应用场景:比如说短信业务,欠费了等情况,可以暂时下线服务。
如果使用了 eureka.instance.prefer-ip-address: true
,然后 eureka.client.service-url.defaultZone
配置的IP与实例IP不一致,会出现available-replicas为空的问题。
解决方法:在 eureka.instance.ip-address
中强制设置IP,然后在 eureka.client.service-url.defaultZone
配置对应的IP。
本人所在的公司由于体量小, 生产环境直接使用 Eureka 的默认配置进行高可用性运行 ,目前也没有出现太大的问题。
以下是一些实践参考文章(注意:文章中的版本号不是最新的,可能在配置上会有调整):