Spring Cloud Eureka 客户端服务快速上下线

问题描述

在开发环境联调接口过程中,出现bug 或 新增属性方法 或其他需要重启服务才能让新代码生效的情况,是再正常不过的事了,如果是单体应用还好,重启就能直接用了,但如果是Spring Cloud微服务应用就不一样了,因为我们调用接口都是会经过网关,然后网关再通过负载均衡将请求转发后可用的服务实例,这一切很大程度上依赖于Service Discovery(服务发现,即Spring Cloud Eureka,当然还有其他服务发现框架,这里主要讨论Eureka),当服务重启后,你会发现有一小段时间重新启动的服务变成不可用。

问题原因

比较了解Eureka的人都知道,Eureka Server 有2个缓存,一个是可读写缓存(readWriteCacheMap),另一个是只读缓存(readCacheMap),这2个缓存存放的都是所有Eureka Client服务的服务实例列表,不过这2个Cache有不同的用途。可以简单地这样理解:

  • readWriteCacheMap: 存放的是实时的、最新的、可用的服务实例列表;服务上下线,都会实时更新该缓存;
  • readCacheMap: 存放的是readWriteCacheMap某一时刻的拷贝,并定期(默认是30s)从readWriteCacheMap最新的实例列表更新;

然而,Eureka ClientEureka Server请求获取服务实例列表时,Server端返回的是readCacheMap这个缓存里边的内容,所以就会出现请求的服务没有可用的服务实例。

服务重启后变成不可用,过段时间又变成可用的流程,具体可参考如下时序图:


Spring Cloud Eureka 客户端服务快速上下线_第1张图片
eureka 服务上下线

解决方案

既然知道问题所在,只要解决思路就清晰了,无非就是缩短readWriteCacheMap缓存更新到readCacheMap中的时间,再一个是缩短Eureka Client服务从Eureka Server获取新的服务实例列表的时间;当然,还需要其他配置的配合,比如主动让不可用服务时效掉,因为Spring Cloud的负载均衡默认实现是Ribbon,所以还需要缩短其刷新负载列表的时间。具体配置如下:

Eureka Server

eureka:
  server:
    # 默认30s. eureka server刷新readCacheMap的时间,注意,client读取的是readCacheMap,
    # 这个时间决定了多久会把readWriteCacheMap的缓存更新到readCacheMap上
    response-cache-update-interval-ms: 3000
    # 默认60s. 启用主动失效,并且每次主动失效检测间隔为5s.
    eviction-interval-timer-in-ms: 5000
  instance:
    # 默认90s. 服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除.
    # 注意,EurekaServer一定要设置eureka.server.eviction-interval-timer-in-ms否则这个配置无效,这个配置一般为服务刷新时间配置的三倍
    lease-expiration-duration-in-seconds: 15
    # 默认30s. 服务刷新时间配置,每隔这个时间会主动心跳一次
    lease-renewal-interval-in-seconds: 5

Eureka Client

eureka:
  client:
    # eureka client刷新本地缓存时间
    registryFetchIntervalSeconds: 5
ribbon:
  # eureka客户端ribbon刷新时间
  ServerListRefreshInterval: 5000

友情提醒

这套配置,比较适合在开发阶段使用,因为我们希望重启的服务能尽快可用。但是线上环境就需要根据具体情况更改配置,当然如果线上环境的服务实例数比较少,也是可以考虑使用上述配置。

推荐阅读

Spring Cloud 进阶玩法

你可能感兴趣的:(Spring Cloud Eureka 客户端服务快速上下线)