互联网产品高速迭代,一般伴随着高频次的版本发布。部署新版上线须要重启服务,直接 kill 服务进程可能会形成服务短暂不可用,从而影响到正在使用的用户。json
Spring Cloud 项目中通常会用到 Ribbon 做为负载均衡,那么是否是只要保证每一个服务部署多台服务器,发布时采用 Rolling Update 分批次部署,保证一部分服务器正常提供服务的同时发布另外一部分服务器,Ribbon 就能自动切换,保证服务的不间断?然而并非。segmentfault
全部服务的状态保存在注册中心,即 Eureka Server。一个服务要想获取其余服务的实例列表和状态,须要经过 Eureka Client 定时从 Eureka Server 中获取并缓存下来,默认时间间隔是30秒。Eureka Client 和 Eureka Server 是经过 HTTP 协议通讯,请求由 Eureka Client 发起,而不是基于长链接或者 Eureka Server 主动推送,因此没法当即知道其余服务状态变动。缓存
即便同一个服务部署多台机器,每台机器依次发布,当其中一个服务实例重启时,服务调用方是没法第一时间知道的,因此仍是会调用到这台暂时没法提供服务的实例上。这样会形成短暂的访问失败,这段时间也会对正在使用产品的用户形成必定的影响。bash
基于以上的缘由,在部署应用时应该按照如下步骤进行(为了简单起见,假设一个应用部署两个实例):服务器
完成后,再重复以上步骤部署另外一个实例。app
有两种方案能够修改实例的状态,选择其一便可:负载均衡
/service-registry
我更偏向使用方法二,对应的命令:curl
curl -H "Content-Type:application/json" -X POST http://{host:port}/actuator/service-registry?status=DOWN
若是 actuator endpoint 加了 Spring Security Basic 认证,则还须要加上用户名和密码:url
curl -H "Content-Type:application/json" -X POST -u {username}:{password} http://{host:port}/actuator/service-registry?status=DOWN
具体要等多久,其余调用者的请求才会再也不访问到这台状态为 DOWN 的实例?这里涉及到三个配置项:spa
eureka.client.registryFetchIntervalSeconds
Eureka 客户端每隔多久去 Eureka 服务器拉取最新的注册信息,默认值 30(秒)。ribbon.ServerListRefreshInterval
Ribbon 的缓存刷新间隔时间,默认 30000(毫秒)。Eureka 客户端拉取到最新注册信息后,Ribbon、Feign 等组件不会当即生效,是由于 Ribbon 还有一层缓存。eureka.server.responseCacheUpdateIntervalMs
Eureka Server 返回最新的注册信息的接口缓存刷新时间间隔,默认 30000(毫秒)。有时候会看到 Eureka 页面和 /eureka/apps
接口的服务状态不一致,就是由于 /eureka/apps
接口默认会有 30 秒缓存。在默认状况下,当一个服务状态改成 DOWN,最长可能须要 30+30+30 秒,全部的缓存才会刷新,其余调用者才不会调用到这个状态为 DOWN 的实例。这就意味着修改服务实例状态为 DOWN 后须要等待 90 秒,才能进行下一步操做。
为了让部署时间缩短,能够将以上三个配置项都修改成5秒:
Eureka Server:
eureka: server: responseCacheUpdateIntervalMs: 5000
Eureka Client(即各个服务):
ribbon: ServerListRefreshInterval: 5000 eureka: client: registryFetchIntervalSeconds: 5
完成以上配置,部署时将实例状态设为 DOWN 后,只须要等待 15 秒便可中止进程:
sleep 15s
这一步主要须要注意
kill -9 pid
强制杀掉进程,而应该使用 kill pid
或者 kill -15 pid
关闭进程。使用 kill pid
或者 kill -15 pid
关闭进程以前,Eureka Client 会给 Eureka Server 请求删除本身,后续服务再次启动后会从新注册为 UP 状态。若是使用 kill -9 pid
强制杀掉进程,Eureka Client 没有办法注销本身,Eureka Server 就不知道该实例已下线,直到长时间收不到心跳才会删除该实例。若是在 Eureka Server 删除实例以前实例启动了,那么它的状态仍是会保持 DOWN 状态。若是确实须要用到 kill -9 pid
强制杀掉进程,那么服务重启后须要再经过第一步的方式将实例状态设为 UP。/health
接口,例如每隔 1 秒请求一次,直到接口能够正常访问,便可认为服务启动成功。本文基于 Spring Boot 2.1.x 及 Spring Cloud Greenwich 版本