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 的默认配置进行高可用性运行 ,目前也没有出现太大的问题。
以下是一些实践参考文章(注意:文章中的版本号不是最新的,可能在配置上会有调整):