1、微服務平臺簡介java
要搭建一套能穩定支持海量調用的微服務系統,須要先看看系統由哪些模塊組成。如上圖所示,從下往上看,不一樣的用戶 VPC 表明多租戶,中間是服務註冊發現的模塊,頂部是應用管理模塊和數據化運營模塊,應用管理模塊用來進行 CICD,包括了分發、部署以及配置管理等應用生命週期相關的功能。
數據化運營這個模塊主要用於幫助業務進行分析,包括但不限於調用鏈、日誌、metrics 等。
從系統架構上來講,藍框裏的屬於數據面,也就是常說的 data plane,是影響業務請求的核心鏈路;灰色區域內更多的偏向控制流,也就是 control plane ,幫助咱們更簡單的使用好微服務。
數據面和控制面屬於兩種不一樣的架構,面臨的挑戰也各不相同。數據面的挑戰主要難點在於大流量、穩定性和高可用等,而控制面的更多則是業務複雜度。本文將圍繞着整個數據面分享如何讓微服務系統變得更穩定。
2. 海量調用的起始——微服務
2014 年雲興起以後,提出了雲時代下的微服務概念:單一應用程序構成的小程序,本身擁有本身的邏輯與輕量化處理能力,服務以全自動方式部署,與其餘的服務之間進行通訊,服務可使用不一樣編程語言和數據庫實現。
這個概念和早期 Dubbo 這種基於 Netty 框架構成的系統本質上沒區別,只不過雲興起以後增長了一些自動部署和 docker 的能力,也作了更多的集成。
經過上圖能夠看到,咱們每一個微服務都內聚了本身的業務邏輯,容許訪問不一樣的數據庫,以及經過 rest API 進行互相通訊。從模型來看有點像是蜂巢,也很像一張網。這裏就會引伸出一個小問題,這麼多的微服務,他們之間是如何進行調用的?
http client 自己咱們知道是經過 IP 和 port 來進行互相調用,早期單體應用還可以簡單的進行配置。可是在微服務時代,特別是用了 K8s 和 docker,每次啓動的 IP 也可能會變,這裏該怎麼辦呢?其實能夠經過服務註冊發現模塊進行機器實例的互相發現和調用。
mysql
咱們來看圖解釋一下什麼是服務註冊發現。
圖上能看到有兩個微服務,ServiceA 和 ServiceB。在這裏咱們定義 ServiceA 爲服務調用方,ServiceB 爲服務提供者。
前面也說到了,在單體應用時代,咱們都須要經過配置來指定須要訪問的 IP,可是雲時代下的微服務,IP 自己會變,因此須要有一個地方來記錄這些 IP,那就是服務註冊和發現的能力。
ServiceB 的每一個實例在啓動時,會將自身的 IP 和 port 寫入到服務發現模塊的某個路徑,而後 ServiceA 會從這個路徑來拉取到想要訪問的 ServiceB 的服務提供者的列表。這裏就會拉取到三個實例節點,從中選擇一個節點進行訪問。
目前市面上已經有不少成熟的註冊發現組件,像是 zookeeper,nacos,Consul 等。Consul 自己做爲一個開箱即用,而且支持 http 請求,同時擁有豐富的文檔和簡單的 API 的系統被不少的中小型公司青睞和使用。
固然,Consul 和 Spring 的對接也很成熟,不少中小型公司,特別是比較新的公司不少都會選擇 Consul 來做爲服務註冊發現。因此咱們選擇基於 Consul 做爲底層基礎組件,在上面一點點的進行擴展,來搭建一套穩定的服務註冊發現模塊。
redis
2、突破原生開源架構sql
Consul 有開源版本和企業版本,對於開源版原本說,基本功能都齊全,但企業級能力卻不提供。缺乏這些企業級的能力,對想用 Consul 來實現支持海量調用的微服務系統會有不足。
原生的Consul的服務發現 API 參數只有一個服務名,想要多租戶或者帶上 namespace,只能拼接在服務名上。可是這裏須要強行依賴 SDK,對於 Consul 這樣一個暴露 http 的通用服務,不能限定用戶的語言,也不可能每一個語言去實現一套 SDK,咱們須要用其餘方式來實現。
docker
實現多租戶的能力,須要在原有的 Consul-server 集羣以前,加一層 Consul-access 層。對外暴露的 API 和原生的 Consul 徹底同樣,但背後針對一些 API 能夠進行了一些改造。
先簡單看看經過加入 access 層,怎麼來實現多租戶的能力:
服務註冊發現通常來講分爲三步
數據庫
爲了簡化問題,咱們在這裏不考慮異常狀況和順序狀況。
針對這三步,咱們分別進行一些改造,用戶側使用原生的 Consul-SDK 進行服務註冊,當 access 接收到註冊請求後,會將該請求翻譯成一個 KV 請求,而後存儲到 Consul-server 上。
第一步,實現多租戶的能力,服務發現第一步是服務提供者進行實例註冊,接到註冊請求時會將該請求翻譯成key是/租戶/service/serviceA/instance-id/data,value 是用戶註冊上來的節點信息的請求,每個 instance-id 對應的目錄就表明着一個服務提供者。
並無採起原生的服務註冊的 Consul 提供的服務註冊,而是爲了作治理能力分開成了 KV 進行存儲。
第二步,心跳請求也會被 Consul-access 攔截,翻譯成 KV 請求,存在 Consul 集羣上。
第三步,是服務發現請求,該請求被 Consul-access 攔截後,首先會從前面所說的路徑下拉取當前所有的實例列表,而後將對應實例的最後心跳上報時間取出,第二步存 KV 的地方將服務註冊的實例信息和心跳數據進行合併。
合併是將最近 30 s 內沒有心跳數據的節點狀態置爲 critical,30 s 內有心跳的節點狀態置爲 passing,而後返回給客戶端,這樣對於客戶端來講,和直接請求 Consul-server 行爲保持一致。
但這種實現方式有個問題:用戶若是使用原生的 API 進行服務註冊的話,自己其實並不包含租戶的信息,那 access 如何知道寫入的路徑呢?
3. 透明地生成租戶信息
這種實現有一個問題,用戶使用的原生 API 進行註冊,原本不帶有租戶信息,Access 第一步就沒法實現了,這塊如何處理?
原生 Consul 的有一個參數叫 token,是個 String 字段,爲了即兼容原生的 Consul請求,又可以獲取咱們想要的信息,咱們在這裏作了一些文章。
首先須要實現 「token」 模塊,該模塊提供 token 授予和驗證,同時也提供根據 token 返回相應信息的能力。
用戶首先申請 token 密鑰,填寫信息,如租戶名等等,而後 token-server 模塊會根據這些信息生成一個 token 密鑰並返回給客戶端。用戶在使用原生 API 的時候,須要把該 token 帶上。Consul-access 收到 token 後,會從 token-server 來換取對應的信息,這樣對於用戶而言作到了徹底透明。
Token-server 模塊的存在,使得 access 層除了可以實現一些企業級的功能,好比多租戶,也可使得整個 Consul 集羣能夠更加穩定,好比防止用戶惡意的進行調用,來對 Consul-server 形成 ddos ***。
也能夠針對不一樣的業務模塊或者用戶能夠進行不一樣的治理手段,好比咱們能夠根據用戶的 token 等級來設定 Consul 的配額,或者能夠在測試環境限制訪問頻率,或者說限制某些用戶的某些操做權限。
引入了 token 模塊和 access 層,還能夠作很是多有意思的事情,這裏是給你們發散思考的地方,若是大家來作的話,還會加入哪些能力呢?
咱們已經發現加入了 access 層從功能層面上可以讓整個 Consul 集羣可以更加穩定,有些有經驗的工程師可能會想到,會不會由於多了一層,而致使性能變差呢?
下面咱們來看看,在加入 access 層後,咱們作了哪些性能優化。
編程
3、讓服務發現更穩定小程序
解決方案很簡單,Consul-access 是無狀態能夠水平擴容的,可是 Consul-server 集羣有瓶頸,那麼咱們能夠以 Consul-server 集羣爲粒度進行水平擴容。
咱們仍是藉助以前說的 token 模塊,根據 token 返回的信息來進行斷定,而後決定當前的用戶請求應當轉發到哪一個 server 集羣,而後經過這種思路,讓整個服務發現系統作到徹底水平擴容。
這種架構目前也被普遍採用,好比 shardingredis,水平分庫中間件等。
緩存
這裏再講一個小優化,在運行過程當中,發現 Consul 的 CPU 佔用仍是比較高的,這裏用 pprof 進行調用採樣分析後,發現大量的 CPU 消耗都來自於一個請求。
經過排查,發現是 Spring-SDK 中會每 2s 定時發一個 watch 請求,在這裏咱們作個轉換,將 watchtimeout 2s 的請求在 access 側轉換成了 55s 轉發給 Consul-server。須要注意的是,這裏的轉換和原來沒有區別,也是會在 55s 有變化的時候返回,可是大大下降了 CPU。上面兩張 CPU 負載圖是在運行了 3 天后的結果。
比起分享具體的某一次優化是怎麼作的,更但願能給你們一些啓發,某些看起來可能很難的事情,好比這裏的 CPU 下降 60% 負載,但你去嘗試優化了,可能發現仍是比較容易的,可是成本收益很高,相比起某些架構上或者代碼上的細節,一些點的修改可能會極大的影響穩定性。
性能優化
講了如何從功能緯度和性能緯度讓整個服務發現系統更穩定,下面是如何讓服務發現變得高可用。 Consul 是一個 CP 系統,根據 CAP 定理,CP 系統是無法作到高可用的,因此咱們只能儘量的在別的環節來增強,彌補一下 CP 系統的可用性。這裏我會從客戶端、SDK 和 access 層來分享如何儘可能讓整個系統更高可用。
爲何是在 SDK 和 access 層作加強呢,實際上是由於 Consul-server 對咱們來講是黑盒,咱們不對他進行改造,由於不一樣於 access 層,修改 Consul 源碼超出了大部分中小型公司的範圍,在此咱們不作定製化。
一樣的,咱們仍是先分析沒有 access 層的狀況:
要搞清楚的一點是,服務註冊發現三步驟中、註冊、心跳和發現,出問題下分別會對系統形成什麼樣子的影響?
首先是註冊,若是一個實例註冊不上去,那麼再有其餘實例存在的狀況下,對總體微服務是沒有任何影響的。
而後是心跳,若是由於某個緣由,好比網絡閃斷,或者丟包,丟失了心跳,那麼會致使該節點從服務註冊列表中下線。若是實例數少的狀況下,部分實例下線會致使流量不均勻甚至整個系統垮掉。
最後發現,若是由於異常,好比 Consul 重啓後丟失了數據,或者好比網絡緣由,服務提供者的實例沒有註冊上去,會致使拉取到的實例列表爲 0,這裏會直接形成服務不可用。
根據上面的分析,咱們能夠發現,首先要增強的是服務發現:
Spring 原生的服務發現是每 30s 左右去拉取新的實例列表,這裏其實還有個 bug,這個參數沒法經過配置來指定。
因此第一步,咱們將定時拉取改成了 watch 機制。好處在於,某些實例若是已經反註冊下線後,能夠馬上通知客戶端更新列表,不然在最多 30s 的時間內,可能請求仍是會打到已經下線的機器上。
同時,增長了本地緩存,每次拉回來的服務列表,會存儲在本地,這樣若是機器 crash 或者由於某些緣由,Consul 集羣不可用時,不至於致使整個微服務系統所有不可用。
最後增長零實例保護,指的是,若是從 Consul 拉取的列表爲空時,不替換內存中的數據,也不刷新緩存。由於若是 Consul 集羣不可用,或者冷啓動,或者其餘不可預知的場景時,拉取回空列表會形成巨大的影響。
第二步咱們要增強心跳上報的流程,心跳上報是 put 請求,因此這裏須要設置 readtimeout,默認是 1min。
這裏要注意的是,1min 多是兩個心跳週期,若是客戶端和 Consul 之間的網絡抖動或者丟包,會直接形成 1 分鐘內不可用,因此這裏首先要設置 readtimeout,通常推薦 5s 左右。
同時須要配套增長重試機制,不然一次失敗就會致使一個生命週期掉線,這裏推薦 3 次,配合上剛剛超時的 5s,一共 15s,小於一個週期的 30s。
說完 SDK 後,咱們再來看看 access 層,在計算機系統裏,每增長一箇中間層,解決一些問題的同時,也會帶來一些問題,特別是可用性這裏,引入中間層,必須作的更多,才能保證和沒有這一層同樣的可用性。
和 SDK 不同,access 對於客戶端來講就是服務端,因此要儘量的保證每一個請求的成功,因此咱們能夠作一些通用性質的可用性加強建設:
第一,和 SDK 的同樣,減小 timeout 和重試,可是因爲 raft 的實現機制,咱們只須要重試最多 1/2+1 次就行。
第二,當出現某個極端場景,好比整個 Consul-server 集羣不可用,咱們須要增長一個兜底集羣。在某個集羣整個不可用時,將流量轉發到兜底集羣,並作下記錄,等服務發現等 get 類型請求時,須要知道從哪一個集羣拉取合併數據。
第三,咱們還須要增長主動發現問題的能力,這裏咱們增長集羣探測的 agent,定時發送請求給每臺 access 和每一個 Consul-server 集羣,出了問題及時告警。
除了以上針對每一個請求的通用能力建設外,咱們還能夠針對服務發現,作一些更多的加強。
首先若是真的出現內部錯誤,須要用 500 來代替空列表返回。這樣無論是原生的 SDK 仍是剛剛通過咱們增強的 SDK,都不會替換內存裏的列表,至少能夠保證微服務系統繼續運行。
而後,咱們須要加入零實例保護的機制,這裏和 SDK 有些區別,指的是若是發現全部實例都不可用,則以最近一個不可用的實例節點的最後心跳時間做爲基線,往前一個心跳週期做爲時間範圍,將這個時間段的實例狀態置爲 passing 返回給客戶端。
這裏有點拗口,咱們舉個實際的例子,好比當前服務 B 有 10 個實例,其中 2 個在幾個小時前就已經掉線了,還有 8 個在正常運行,此時,Consul 集羣徹底不可用十分鐘,因此心跳信息沒法上報,當 Consul 集羣恢復時,access 會發現最近的心跳是 Consul 集羣不可用那個時間點,也就是 10min 前,可是因爲已經超過了一個心跳週期 30s,因此這裏全部的實例都不可用,返回給客戶端的話,會形成很是劇烈的影響。
可是若是增長了零實例保護,則會在返回實例列表時,發現最後一次上報心跳的節點在十分鐘前,同時往前推 30s 發現一共有 8 個節點是在這個時間段丟失心跳,因此會將這 8 個實例返回給客戶端。
固然,這裏須要有個界限,通常選擇 Consul-server 集羣可以修復的時間,好比 1~3 小時,再長的話可能髒數據機率會比較大。
服務註冊發現的話題先說到這,再來回顧咱們經過增長 access 層和 token 模塊,來實現了企業級能力,加強了功能性的穩定性。同時經過聚合鏈接以及多 Consul-server 集羣模式,大大加強了整個 Consul 的性能穩定性,最後,經過一些高可用的加強,咱們增強了整個服務發現系統的可用性。
在咱們擁有一個穩定的服務發現系統以後,咱們進入下一個話題,如何讓服務之間的調用變得更加穩定。
咱們先來看看一個基於 Springcloud 開發的微服務之間的調用流程:
當用戶發起 API 調用時,首先會來到 feign 模塊。在 Springcloud 中,feign 起到了一個承上啓下的做用,他封裝了 http 的調用,讓用戶能夠像使用接口同樣的方式發起 rest 調用,同時也是在這裏配置了須要訪問的微服務名稱。
feign 帶着須要訪問的服務名和拼接好的 http 請求來到了 ribbon 模塊,
ribbon 簡單來講就是一個負載均衡模塊,若是給定的是 IP,則會直接像該IP發起調用,若是是服務名的話,會從服務註冊發現模塊中獲取服務名對應的服務提供者列表,而後從中選擇一臺進行調用。
看起來整個調用過程很是簡單,可是實際生產上,特別是流量較大的狀況下,若是直接這麼使用開源組件,而且使用默認配置的話,一旦某個環節出了一點問題,可能會直接致使一條線所有都崩潰。這也是不少研發遇到的問題。
那麼若是在我不想改動業務代碼的狀況下,咱們在這裏又能夠作哪些措施來讓系統變得更穩定?
總體的調用圖和上一幅沒有太大變化,這裏咱們增長了幾個環節,下面來講一下。
首先,在 feign 和 ribbon 之間,增長了 hystrix 和 fallback。也是分別對應了熔斷和容錯這兩個能力。
熔斷這裏要說的一點是,熔斷自己不是萬能藥,通常來講,熔斷只針對弱依賴,或者直白的說就是不那麼重要的下游服務開啓。
熔斷這個能力是爲了防止雪崩,所謂雪崩就是下游某個服務不可用時,調用該服務的服務調用方也會受到影響從而使得自身資源被吃光,也逐漸變得不可用。慢慢的整個微服務系統都開始變得癱瘓。
額外補充說明,在微服務體系或者說分佈式系統裏,服務半死不活遠比服務整個宕掉難處理的多。
設想一下,假設某個下游服務徹底掛了,進程也不存在,此時若是調用者調用該服務,獲得的是 connection refuesd 異常,異常會很是快返回,因此就時間上來講和你調用成功沒有太大區別,若是該服務是一個弱依賴服務,那影響更是微乎其微。
但若是下游服務不返回,上游調用者會一直阻塞在那裏,隨着請求的增多,會把線程池,鏈接池等資源都吃滿,影響其餘接口甚至致使整個都不可用。
那在這種場景下,咱們須要一種辦法,讓咱們達到和下游服務掛掉同樣的快速失敗,那就是熔斷的做用。經過熔斷模塊,咱們能夠防止整個微服務被某一個半死不活的微服務拖死。同時也提醒你們,要重視快速識別出半死不活的那些機器。
說回容錯,容錯的使用的場景不是很是的頻繁,更可能是針對一些不那麼重要的接口返回一些默認的數據,或者配和熔斷等其餘治理能力進行搭配使用。
當 ribbon 選定了實例以後,要正式發起調用的以前,能夠添加一個重試和超時,加上重試和超時,若是真的可以配置好這幾個參數,能將系統穩定性提高一大截的。
關於超時,不少人、甚至不少有必定經驗的開發者都喜歡用默認的超時時間。通常來講,默認的超時時間都是分鐘以上,有的框架甚至默認是 0,也就是沒有超時。
這種行爲在生產上十分危險,可能有一臺服務提供者假死在那裏,因爲超時時間設置爲 10 分鐘,同時因爲 loadbalance 的緣由,使得線程慢慢積壓起來,從而致使了自身系統的崩潰。
給出建議——絕對不要使用默認的超時,而且必須合理配置 timeout。超時通常來講主要是 connect timeout 和 read timeout,connect timeout 是指創建鏈接的超時時間,這個比較簡單,通常同機房 5s 差很少了。
Read timeout 也就是 socketTimeout 須要用戶根據本身下游接口的複雜度來配置,好比響應通常在毫秒級別的,我推薦設置 3s 到 5s 就好了,對一些秒級的 5s 也行,對於比較重要的大查詢,耗時十幾 s 到幾十 s 的我建議設置爲 1min,同時開啓熔斷,以及最好可以使用異步線程去將這種大請求和業務請求分離。
若是你們以爲這種須要根據每一個請求來自行設定 read timeout 的方式太過於麻煩,其實還有一種更方便的方式,就是自適應超時。在網關若是傳入的時候能夠設置一個最大的超時時間,每一個微服務都會將該時間傳遞下去,這樣能夠動態的設置當前請求的超時時間。
說完超時咱們再來看一下重試,ribbon 其實自帶了一些配置參數,經常使用的是 MaxAutoRetries,MaxAutoRetriesNextServer,OkToRetryOnAllOperations,這幾個參數具體的含義和計算公式官網都有,這裏不詳細介紹了。
想提醒你們的是,對於一些冪等的請求,配合上較短的 timeout,合理的設置 1 次到 2 次重試,會讓你總體的微服務系統更加穩定。
上面的全部加強其實不須要用戶修改業務邏輯,基本上都是配置和依賴,可是正確的配置和使用這些開源組件,可讓你的整個系統變得更加穩定。下面看一些進階場景。
4、穩定調用的學問
介紹了熔斷,hystrix 是服務級別或者接口級別,但生產過程當中,都是個別實例出現問題,特別是某一個實例假死或者不返回。
針對這種場景,hyxtrix 的熔斷配置不是很靈活,由於它是經過總體的錯誤率來進行熔斷的,通常一個實例異常是沒有辦法處罰熔斷。
若是不改代碼,咱們有沒有辦法處理這種場景?咱們其實能夠經過減小 timeout 搭配上重試 1 次繞過該錯誤,若是是一個冪等的服務的話,一個實例壞掉,其實對整個系統不會有太大影響。
但若是是一個非冪等的,或者 put 請求,這裏該怎麼辦?有沒有辦法不讓失敗率升高到 33% ?
TSF 用 resilience4j 從新本身實現了一整套的熔斷,並加入了實例級別熔斷的粒度,用來解決上述場景。
先說一下選型,爲何要用 resilience4j 來做爲底座替換 hystrix?緣由很簡單,首先 resilience4j 是官方推薦的替代 hystrix 的框架,也更輕巧靈活。
它將容錯、熔斷、艙壁等治理能力獨立,讓用戶能夠自行組合,通過壓測,發現單個 resilience4j 熔斷器實例的 qps 能夠高達百萬,對應用不會形成額外的負擔,因此這裏選擇基於 resilience4j 來進行二次開發。
熔斷的原理是在發送請求前,根據當前想要訪問的微服務或者接口,獲取到對應的熔斷器狀態。若是是進入 open 狀態,則直接拒絕調用,而在調用請求後,會將成功,失敗的結果更新至對應的熔斷器,若是失敗比例超過了閾值,則打開熔斷器,若是用戶想擴展一些 metrics,好比慢調用等,只要記錄時間,而後傳給 resilience4j 熔斷器便可, resilience4j 默認支持慢調用熔斷。
再看一下實例級別的熔斷,實例級別熔斷和上面兩個維度在實現上有些不一樣,它更多的是剔除有問題的節點。
具體的時機是在 ribbon從Consul 獲取可用的服務列表後,會增長一步:斷定當前訪問的微服務有哪些節點是打開狀態,而後須要將打開狀態的節點從可用列表中剔除,而後再進行 loadbalance,這樣就能夠作到及時的將不可用節點剔除,大大下降失敗率。
咱們已經介紹瞭如何讓服務發現和運行時調用變得更穩定,那麼接下去,看看怎麼讓服務可以平滑的下線和上線。
可能有人會以爲奇怪,上下線能對系統穩定性形成什麼影響?那咱們就先來看一下簡單的下線和上線會遇到什麼問題:
首先是下線,一個考慮的比較周到的微服務框架在下線前會發送反註冊請求給 Consul,而後再下線。看起來彷佛沒什麼問題,可是從反註冊發送到下線其實間隔很短。
這裏若是用戶用的是剛剛咱們增強過的 SDK,也就是將 30s 定時輪訓改成 watch 的機制後,影響大概在秒級。
具體影響的時間爲從註冊推送到 Consul,以及 Consul 到變動後返回給 watch 的客戶端,而後客戶端執行替換和緩存文件寫入的時間,基本上在幾百 ms 到 1s 左右。假設咱們 qps 爲 1000,服務實例列表爲 10 臺,那麼大概會有 100 個請求失敗。
若是用戶用的是原生的 SpringSDK 的話,那麼這裏影響就比較大了,30 秒內會不停的有流量打過去,錯誤率會快速升高。
問題已經清楚,怎麼解決?因爲目前 k8S 是主流的容器編排的系統,因此介紹下如何利用 K8S 的一些特性,來作到優雅下線。
先明確這是由於反註冊和 shutdown 間隔時間過短而致使的異常,若是咱們能作到,先反註冊,而後過 40s 再下線,那即便使用的是原生的 SDK,也不會有錯誤,由於最大 30s 後會更新到新的實例列表。
知道方法後,來看看在不改代碼的狀況下怎麼作到優雅下線:
首先能夠利用 k8s 自帶的 pre-stophook 能力,這個 hook 是在須要 stop 容器以前進行的一個操做。當 pre-stop hook 執行完畢後才正式執行銷燬容器。在 pre-stophook 裏面進行反註冊,成功後 sleep 35 秒,而後再執行 shutdown。
這裏有個細節,雖然 pre-stophook 裏面進行了反註冊,可是應用仍是會繼續發心跳,因此須要在 Consul-access 層屏蔽掉髮送了反註冊請求實例節點的心跳數據。
咱們再接着來看看優雅發佈,正常發佈會狀況是,k8s 有兩個狀態,分別是 liveness 和 readiness。
默認狀況下,容器啓動了就算是 live了,啓動完成後就變成了 ready 了。但大多數的 Spring 應用其實啓動仍是耗時間的,有的啓動甚至須要好幾分鐘,若是 k8s 發佈參數設置的很差,可能所有滾動更新後,全部的程序都還沒初始化完畢,這樣直接就致使整個服務全都不可用了。
咱們如何避免以上狀況?簡單的辦法是評估本身應用啓動的時間,在 k8s 滾動發佈的間隔參數配置的長一點,大於你預估的啓動時間就行。那有沒有更簡單更自動的辦法呢?
經過 k8s 的 readinessprobe,而後在 readinessprobe 中咱們向 Consul 發送請求,查詢該實例是否已經註冊到 Consul 上,若是已經在 Consul 上了,則認爲 ready。
由於通常來講,註冊到 Consul 都已是啓動的最後一步了,經過這種方式,咱們就能夠不作任何干預的進行優雅發佈。
從整個優雅發佈和優雅下線能夠看到,只是利用了原生 k8s 的 probe 能力,在正確的時間點,與 Consul 一塊兒配合,就能沒有任何異常的讓系統穩定的更新,但願你們在本身的生產上也能用到這一點。
今天分享到此結束,感謝你們的觀看!
5、Q&A