Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn)
前言
在生產(chǎn)環(huán)境中,如何保證在服務(wù)升級(jí)的時(shí)候,不影響用戶的體驗(yàn),這個(gè)是一個(gè)非常重要的問題。如果在我們升級(jí)服務(wù)的時(shí)候,會(huì)造成一段時(shí)間內(nèi)的服務(wù)不可用,這就是不夠優(yōu)雅的。那什么是優(yōu)雅的呢?主要就是指在服務(wù)升級(jí)的時(shí)候,不中斷整個(gè)服務(wù),讓用戶無感知,進(jìn)而不會(huì)影響用戶的體驗(yàn),這就是優(yōu)雅的。
實(shí)際上,優(yōu)雅下線是目標(biāo),而不是手段,它是一個(gè)相對的概念,例如kill PID
和kill -9 PID
都是暴力殺死服務(wù),相對于kill -9 PID
來說,kill PID
就是優(yōu)雅的。但如果單獨(dú)拿kill PID
出來說,我們能說它是優(yōu)雅的下線策略嗎?肯定不是啊,就是這個(gè)道理。
因此,本文講述的優(yōu)雅下線僅能稱之為“相對的優(yōu)雅下線”,但相對于暴力的殺死服務(wù),已經(jīng)足夠優(yōu)雅了。常見的優(yōu)雅解決方案,主要包括優(yōu)雅下線和灰度發(fā)布。而實(shí)際上,灰度發(fā)布的范圍就已經(jīng)包含優(yōu)雅下線了。最后,在本文中,我們主要講述基于 Spring Cloud 和 Euraka 的優(yōu)雅下線以及灰度發(fā)布。
優(yōu)雅下線
常見的下線方式
方式一:kill PID
使用方式:kill java進(jìn)程ID
該方式借助的是 Spring Boot 應(yīng)用的 Shutdown hook,應(yīng)用本身的下線也是優(yōu)雅的,但如果你的服務(wù)發(fā)現(xiàn)組件使用的是 Eureka,那么默認(rèn)最長會(huì)有 90 秒的延遲,其他應(yīng)用才會(huì)感知到該服務(wù)下線,這意味著:該實(shí)例下線后的 90 秒內(nèi),其他服務(wù)仍然可能調(diào)用到這個(gè)已下線的實(shí)例。因此,該方式是不夠優(yōu)雅的 。
方式二:/shutdown
端點(diǎn)
Spring Boot 提供了/shutdown
端點(diǎn),可以借助它實(shí)現(xiàn)優(yōu)雅停機(jī)。
使用方式:在想下線應(yīng)用的applicationyml
中添加如下配置,從而啟用并暴露/shutdown
端點(diǎn):
management: endpoint: shutdown: enabled: true endpoints: web: exposure: include: shutdown
發(fā)送 POST 請求到/shutdown
端點(diǎn)
curl -X http://你想停止的服務(wù)地址/actuator/shutdown
該方式本質(zhì)和方式一是一樣的,也是借助 Spring Boot 應(yīng)用的 Shutdown hook 去實(shí)現(xiàn)的。
方式三:/pause
端點(diǎn)
Spring Boot 應(yīng)用提供了/pause
端點(diǎn),利用該端點(diǎn)可實(shí)現(xiàn)優(yōu)雅下線。
使用方式:在想下線應(yīng)用的application.yml
中添加配置,從而啟用并暴露/pause
端點(diǎn):
management: endpoint: # 啟用pause端點(diǎn) pause: enabled: true # 啟用restart端點(diǎn),之所以要啟用restart端點(diǎn),是因?yàn)閜ause端點(diǎn)的啟用依賴restart端點(diǎn)的啟用 restart: enabled: true endpoints: web: exposure: include: pause,restart
發(fā)送 POST 請求到/actuator/pause
端點(diǎn):
curl -X POST http://你想停止的服務(wù)實(shí)例地址/actuator/pause
執(zhí)行后的效果類似下圖:
如圖所示,該應(yīng)用在 Eureka Server 上的狀已被標(biāo)記為DOWN
,但是應(yīng)用本身其實(shí)依然是可以正常對外服務(wù)的。在 Spring Cloud 中,Ribbon 做負(fù)載均衡時(shí),只會(huì)負(fù)載到標(biāo)記為UP
的實(shí)例上。利用這兩點(diǎn),你可以:先用/pause
端點(diǎn),將要下線的應(yīng)用標(biāo)記為DOWN
,但不去真正停止應(yīng)用;然后過一定的時(shí)間(例如 90 秒,或者自己做個(gè)監(jiān)控,看當(dāng)前實(shí)例的流量變成 0 后)再去停止應(yīng)用,例如kill
應(yīng)用。
缺點(diǎn) & 局限
缺點(diǎn) | 描述 |
---|---|
不同的版本配置不大一樣 | 早期的 Spring Cloud 版本中,pause端點(diǎn)是不依賴restart端點(diǎn)的 |
無法和 Eureka 的健康檢查配合使用 | 如果你的服務(wù)發(fā)現(xiàn)組件用的是 Eureka,并且你的應(yīng)用開啟了健康檢查eureka.client.healthcheck.enabled = true,那么/pause端點(diǎn)無效 |
方式四:/service-registry
端點(diǎn)
使用方式:在想下線應(yīng)用的application.yml
中添加配置,從而暴露/service-registry
端點(diǎn):
management: endpoints: web: exposure: include: service-registry
發(fā)送 POST 請求到/actuator/service-registry
端點(diǎn):
curl -X "POST" "http://localhost:8000/actuator/service-registry?status=DOWN" \ -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8"
實(shí)行后的效果類似如下圖:
優(yōu)雅的下線方式
在上文中,我們講述了四種常見的下線方式,對比來看,方式四 是一種比較優(yōu)雅的下線方式。
在實(shí)際項(xiàng)目中,我們可以先使用/service-registry
端點(diǎn),將服務(wù)標(biāo)記為DOWN
,然后監(jiān)控服務(wù)的流量,當(dāng)流量為 0 時(shí),即可升級(jí)該服務(wù)。當(dāng)然,這里假設(shè)我們部署了多個(gè)服務(wù)實(shí)例,當(dāng)一個(gè)服務(wù)實(shí)例DOWN
掉之后,其他服務(wù)實(shí)例仍然是可以提供服務(wù)的,如果就部署一臺(tái)服務(wù)的話,那么討論優(yōu)不優(yōu)雅就沒那么重要了。
除了上述的下線方式之外,還有一種利用EurekaAutoServiceRegistration
對象達(dá)到優(yōu)雅下線的目標(biāo)。
- 執(zhí)行
eurekaAutoServiceRegistration.start()
方法時(shí),當(dāng)前服務(wù)向 Eureka 注冊中心注冊服務(wù); - 執(zhí)行
eurekaAutoServiceRegistration.stop()
方法時(shí),當(dāng)前服務(wù)會(huì)向 Eureka 注冊中心進(jìn)行反注冊,注冊中心收到請求后,會(huì)將此服務(wù)從注冊列表中刪除。
示例代碼如下:
@RestController @RequestMapping(value = "/graceful/registry-service") public class GracefulOffline { @Autowired private EurekaAutoServiceRegistration eurekaAutoServiceRegistration; @RequestMapping("/online") public String online() { this.eurekaAutoServiceRegistration.start(); return "execute online method, online success."; } @RequestMapping("/offline") public String offline() { this.eurekaAutoServiceRegistration.stop(); return "execute offline method, offline success."; } }
到這里,我們已經(jīng)介紹了兩種相對優(yōu)雅的下線方式了。具體如何操作,我們可以根據(jù)實(shí)際上情況進(jìn)行包裝,或者利用自動(dòng)化的腳本來實(shí)現(xiàn)更加優(yōu)雅的下線方式。
灰度發(fā)布
藍(lán)綠部署
藍(lán)綠部署,英文名為 Blue Green Deployment,是一種可以保證系統(tǒng)在不間斷提供服務(wù)的情況下上線的部署方式。
如何保證系統(tǒng)不間斷提供服務(wù)呢?那就是同時(shí)部署兩個(gè)集群,但僅對外提供一個(gè)集群的服務(wù),當(dāng)需要升級(jí)時(shí),切換集群進(jìn)行升級(jí)。藍(lán)綠部署無需停機(jī),并且風(fēng)險(xiǎn)較小。其大致步驟為:
- 部署集群 1 的應(yīng)用(初始狀態(tài)),將所有外部請求的流量都打到這個(gè)集群上
- 部署集群 2 的應(yīng)用,集群 2 的代碼與集群 1 不同,如新功能或者 Bug 修復(fù)等
- 將流量從集群 1 切換到集群 2
- 如集群 2 測試正常,就刪除集群 1 正在使用的資源(例如實(shí)例),使用集群 2 對外提供服務(wù)
因?yàn)樵谑褂盟{(lán)綠部署的方式時(shí),我們需要控制流量,所以我們需要借助路由服務(wù),如 Nginx 等。
滾動(dòng)部署
滾動(dòng)部署,英文名為 Rolling Update,同樣是一種可以保證系統(tǒng)在不間斷提供服務(wù)的情況下上線的部署方式。和藍(lán)綠部署不同的是,滾動(dòng)部署對外提供服務(wù)的版本并不是非此即彼,而是在更細(xì)的粒度下平滑完成版本的升級(jí)。
如何做到細(xì)粒度平滑升級(jí)版本呢?滾動(dòng)部署只需要一個(gè)集群,集群下的不同節(jié)點(diǎn)可以獨(dú)立進(jìn)行版本升級(jí)。比如在一個(gè) 12 節(jié)點(diǎn)的集群中,我們每次升級(jí) 4 個(gè)節(jié)點(diǎn),并將升級(jí)后的節(jié)點(diǎn)重新投入使用,周而復(fù)始,直到集群中所有的節(jié)點(diǎn)都更新為新版本。
這種部署方式相對于藍(lán)綠部署,更加節(jié)約資源,因?yàn)樗恍枰\(yùn)行兩個(gè)集群。但這種方式也有很多缺點(diǎn),例如:
- 沒有一個(gè)確定 OK 的環(huán)境。使用藍(lán)綠部署,我們能夠清晰地知道老版本是 OK 的,而使用滾動(dòng)發(fā)布,我們無法確定。
- 修改了現(xiàn)有的環(huán)境。
- 如果需要回滾,很困難。舉個(gè)例子,在某一次發(fā)布中,我們需要更新 100 個(gè)實(shí)例,每次更新 10 個(gè)實(shí)例,每次部署需要 5 分鐘。當(dāng)滾動(dòng)發(fā)布到第 80 個(gè)實(shí)例時(shí),發(fā)現(xiàn)了問題,需要回滾。這時(shí),我們估計(jì)就要瘋了。
- 有的時(shí)候,我們還可能對系統(tǒng)進(jìn)行動(dòng)態(tài)伸縮,如果部署期間,系統(tǒng)自動(dòng)擴(kuò)容/縮容了,我們還需判斷到底哪個(gè)節(jié)點(diǎn)使用的是哪個(gè)代碼。盡管有一些自動(dòng)化的運(yùn)維工具,但是依然令人心驚膽戰(zhàn)。
并不是說滾動(dòng)發(fā)布不好,滾動(dòng)發(fā)布也有它非常合適的場景。
金絲雀部署
金絲雀部署又稱灰度部署(或者,灰度發(fā)布),英文名為 Canary Deployment,是指在黑與白之間,能夠平滑過渡的一種發(fā)布方式。
金絲雀的名稱來源于「礦井中的金絲雀」,早在 17 世紀(jì),英國礦井工人發(fā)現(xiàn),金絲雀對瓦斯這種氣體十分敏感,空氣中哪怕有極其微量的瓦斯,金絲雀也會(huì)停止歌唱;而當(dāng)瓦斯含量超過一定限度時(shí),雖然魯鈍的人類毫無察覺,金絲雀卻早已毒發(fā)身亡。當(dāng)時(shí)在采礦設(shè)備相對簡陋的條件下,工人們每次下井都會(huì)帶上一只金絲雀作為“瓦斯檢測指標(biāo)”,以便在危險(xiǎn)狀況下緊急撤離。
我們來看一下金絲雀部署的步驟:
- 準(zhǔn)備好部署各個(gè)階段的工件,包括:構(gòu)建工件,測試腳本,配置文件和部署清單文件
- 從負(fù)載均衡列表中移除掉“金絲雀”服務(wù)器
- 升級(jí)“金絲雀”應(yīng)用(切斷原有流量并進(jìn)行部署)
- 對應(yīng)用進(jìn)行自動(dòng)化測試
- 將“金絲雀”服務(wù)器重新添加到負(fù)載均衡列表中(連通性和健康檢查)
- 如果“金絲雀”在線使用測試成功,升級(jí)剩余的其他服務(wù)器(否則就回滾)
在金絲雀部署中,常常按照用戶量設(shè)置路由權(quán)重,例如 90% 的用戶維持使用老版本,10% 的用戶嘗鮮新版本。不同版本應(yīng)用共存,經(jīng)常與 A/B 測試一起使用,用于測試選擇多種方案。金絲雀部署比較典型的例子,就是我們在使用某個(gè)應(yīng)用的時(shí)候,該應(yīng)用邀請我們進(jìn)行“內(nèi)測”或者“新版本體驗(yàn)”,如果我們同意了,那么我們就成了金絲雀。
參考資料:
實(shí)用技巧:Spring Cloud中,如何優(yōu)雅下線微服務(wù)?
Spring cloud系列20 實(shí)現(xiàn)服務(wù)優(yōu)雅上下線
Spring Cloud 灰度發(fā)布解決方案
一文搞懂藍(lán)綠部署和金絲雀發(fā)布
微服務(wù)部署:藍(lán)綠部署、滾動(dòng)部署、灰度發(fā)布、金絲雀發(fā)布
到此這篇關(guān)于Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Spring Cloud 優(yōu)雅下線及灰度發(fā)布內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringCloud實(shí)現(xiàn)灰度發(fā)布的方法步驟
- springcloud+nacos實(shí)現(xiàn)灰度發(fā)布示例詳解
- 關(guān)于SpringCloud灰度發(fā)布的實(shí)現(xiàn)
- SpringCloud灰度發(fā)布的設(shè)計(jì)與實(shí)現(xiàn)詳解
- SpringCloud的全鏈路灰度發(fā)布方案詳解
- Spring?Cloud實(shí)現(xiàn)灰度發(fā)布的示例代碼
- SpringCloud實(shí)現(xiàn)全鏈路灰度發(fā)布的示例詳解
- Spring Cloud Gateway實(shí)現(xiàn)灰度發(fā)布方案
相關(guān)文章
新手學(xué)習(xí)JQuery基本操作和使用案例解析
這篇文章主要介紹了新手學(xué)習(xí)JQuery基本操作和使用案例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02java application maven項(xiàng)目打自定義zip包實(shí)例(推薦)
下面小編就為大家?guī)硪黄猨ava application maven項(xiàng)目打自定義zip包實(shí)例(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05一文詳解Elasticsearch和MySQL之間的數(shù)據(jù)同步問題
Elasticsearch中的數(shù)據(jù)是來自于Mysql數(shù)據(jù)庫的,因此當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行增刪改后,Elasticsearch中的數(shù)據(jù),索引也必須跟著做出改變。本文主要來和大家探討一下Elasticsearch和MySQL之間的數(shù)據(jù)同步問題,感興趣的可以了解一下2023-04-04Springboot jar文件如何打包zip在linux環(huán)境運(yùn)行
這篇文章主要介紹了Springboot jar文件如何打包zip在linux環(huán)境運(yùn)行,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02SpringCloud?LoadBalancerClient?負(fù)載均衡原理解析
LoadBalancerClient?是?SpringCloud?提供的一種負(fù)載均衡客戶端,Ribbon?負(fù)載均衡組件內(nèi)部也是集成了?LoadBalancerClient?來實(shí)現(xiàn)負(fù)載均衡,本文給大家深入解析?LoadBalancerClient?接口源碼,感興趣的朋友跟隨小編一起看看吧2022-02-02spring boot task實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建定時(shí)任務(wù)的方法
這篇文章主要介紹了spring boot task實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建定時(shí)任務(wù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01Java實(shí)現(xiàn)的并發(fā)任務(wù)處理實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)的并發(fā)任務(wù)處理方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了基于線程操作并發(fā)任務(wù)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11