javascript
my.ini修改后服务无法启动_Spring Cloud Eureka 服务实现不停机(Zero-downtime)部署
問(wèn)題
互聯(lián)網(wǎng)產(chǎn)品高速迭代,通常伴隨著高頻次的版本發(fā)布。部署新版上線需要重啟服務(wù),直接 kill 服務(wù)進(jìn)程可能會(huì)造成服務(wù)短暫不可用,從而影響到正在使用的用戶(hù)。
Spring Cloud 項(xiàng)目中一般會(huì)用到 Ribbon 作為負(fù)載均衡,那么是不是只要保證每個(gè)服務(wù)部署多臺(tái)服務(wù)器,發(fā)布時(shí)采用 Rolling Update 分批次部署,保證一部分服務(wù)器正常提供服務(wù)的同時(shí)發(fā)布另一部分服務(wù)器,Ribbon 就能自動(dòng)切換,保證服務(wù)的不間斷?然而并不是。
產(chǎn)生原因
所有服務(wù)的狀態(tài)保存在注冊(cè)中心,即 Eureka Server。一個(gè)服務(wù)要想獲取其他服務(wù)的實(shí)例列表和狀態(tài),需要通過(guò) Eureka Client 定時(shí)從 Eureka Server 中獲取并緩存下來(lái),默認(rèn)時(shí)間間隔是30秒。Eureka Client 和 Eureka Server 是通過(guò) HTTP 協(xié)議通信,請(qǐng)求由 Eureka Client 發(fā)起,而不是基于長(zhǎng)連接或者 Eureka Server 主動(dòng)推送,所以無(wú)法立即知道其他服務(wù)狀態(tài)變更。
即使同一個(gè)服務(wù)部署多臺(tái)機(jī)器,每臺(tái)機(jī)器依次發(fā)布,當(dāng)其中一個(gè)服務(wù)實(shí)例重啟時(shí),服務(wù)調(diào)用方是無(wú)法第一時(shí)間知道的,所以還是會(huì)調(diào)用到這臺(tái)暫時(shí)無(wú)法提供服務(wù)的實(shí)例上。這樣會(huì)造成短暫的訪問(wèn)失敗,這段時(shí)間也會(huì)對(duì)正在使用產(chǎn)品的用戶(hù)造成一定的影響。
解決方案
基于以上的原因,在部署應(yīng)用時(shí)應(yīng)該按照以下步驟進(jìn)行(為了簡(jiǎn)單起見(jiàn),假設(shè)一個(gè)應(yīng)用部署兩個(gè)實(shí)例):
完成后,再重復(fù)以上步驟部署另一個(gè)實(shí)例。
第一步:修改服務(wù)實(shí)例狀態(tài)為 DOWN
有兩種方案可以修改實(shí)例的狀態(tài),選擇其一即可:
我更偏向使用方法二,對(duì)應(yīng)的命令:
curl -H "Content-Type:application/json" -X POST http://{host:port}/actuator/service-registry?status=DOWN如果 actuator endpoint 加了 Spring Security Basic 認(rèn)證,則還需要加上用戶(hù)名和密碼:
curl -H "Content-Type:application/json" -X POST -u {username}:{password} http://{host:port}/actuator/service-registry?status=DOWN第二步:等待其他服務(wù)緩存刷新
具體要等多久,其他調(diào)用者的請(qǐng)求才會(huì)不再訪問(wèn)到這臺(tái)狀態(tài)為 DOWN 的實(shí)例?這里涉及到三個(gè)配置項(xiàng):
- eureka.client.registryFetchIntervalSeconds Eureka 客戶(hù)端每隔多久去 Eureka 服務(wù)器拉取最新的注冊(cè)信息,默認(rèn)值 30(秒)。
- ribbon.ServerListRefreshInterval Ribbon 的緩存刷新間隔時(shí)間,默認(rèn) 30000(毫秒)。Eureka 客戶(hù)端拉取到最新注冊(cè)信息后,Ribbon、Feign 等組件不會(huì)立即生效,是因?yàn)?Ribbon 還有一層緩存。
- eureka.server.responseCacheUpdateIntervalMs Eureka Server 返回最新的注冊(cè)信息的接口緩存刷新時(shí)間間隔,默認(rèn) 30000(毫秒)。有時(shí)候會(huì)看到 Eureka 頁(yè)面和 /eureka/apps 接口的服務(wù)狀態(tài)不一致,就是因?yàn)?/eureka/apps 接口默認(rèn)會(huì)有 30 秒緩存。
在默認(rèn)情況下,當(dāng)一個(gè)服務(wù)狀態(tài)改為 DOWN,最長(zhǎng)可能需要 30+30+30 秒,所有的緩存才會(huì)刷新,其他調(diào)用者才不會(huì)調(diào)用到這個(gè)狀態(tài)為 DOWN 的實(shí)例。這就意味著修改服務(wù)實(shí)例狀態(tài)為 DOWN 后需要等待 90 秒,才能進(jìn)行下一步操作。
為了讓部署時(shí)間縮短,可以將以上三個(gè)配置項(xiàng)都修改為5秒:
Eureka Server:
eureka:server:responseCacheUpdateIntervalMs: 5000Eureka Client(即各個(gè)服務(wù)):
ribbon:ServerListRefreshInterval: 5000 eureka:client:registryFetchIntervalSeconds: 5完成以上配置,部署時(shí)將實(shí)例狀態(tài)設(shè)為 DOWN 后,只需要等待 15 秒即可停止進(jìn)程:
sleep 15s第三步:實(shí)例部署
這一步主要需要注意
- 盡量不要使用 kill -9 pid 強(qiáng)制殺掉進(jìn)程,而應(yīng)該使用 kill pid 或者 kill -15 pid 關(guān)閉進(jìn)程。使用 kill pid 或者 kill -15 pid 關(guān)閉進(jìn)程之前,Eureka Client 會(huì)給 Eureka Server 請(qǐng)求刪除自己,后續(xù)服務(wù)再次啟動(dòng)后會(huì)重新注冊(cè)為 UP 狀態(tài)。如果使用 kill -9 pid 強(qiáng)制殺掉進(jìn)程,Eureka Client 沒(méi)有辦法注銷(xiāo)自己,Eureka Server 就不知道該實(shí)例已下線,直到長(zhǎng)時(shí)間收不到心跳才會(huì)刪除該實(shí)例。如果在 Eureka Server 刪除實(shí)例之前實(shí)例啟動(dòng)了,那么它的狀態(tài)還是會(huì)保持 DOWN 狀態(tài)。如果確實(shí)需要用到 kill -9 pid 強(qiáng)制殺掉進(jìn)程,那么服務(wù)重啟后需要再通過(guò)第一步的方式將實(shí)例狀態(tài)設(shè)為 UP。
- 服務(wù)啟動(dòng)后,需要等待并確認(rèn)啟動(dòng)成功后,才可以開(kāi)始部署下一臺(tái)服務(wù)器。這里我們可以定時(shí)去請(qǐng)求 Spring Boot 提供的 actuator endpoint /health 接口,例如每隔 1 秒請(qǐng)求一次,直到接口可以正常訪問(wèn),即可認(rèn)為服務(wù)啟動(dòng)成功。
本文基于 Spring Boot 2.1.x 及 Spring Cloud Greenwich 版本
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的my.ini修改后服务无法启动_Spring Cloud Eureka 服务实现不停机(Zero-downtime)部署的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 平淡的网名,简单随意淡然网名495个
- 下一篇: 一字的网名,一字的高冷网名515个