互聯網產品高速迭代,一般伴隨着高頻次的版本發佈。部署新版上線須要重啓服務,直接 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 版本