淺析微服務全鏈路灰度解決方案

語言: CN / TW / HK

作者:

十眠|微服務引擎 MSE 研發工程師

揚少|微服務引擎 MSE 研發工程師

本文摘選自《微服務治理技術白皮書》,該白皮書歷經半年多籌備,長達 379 頁。希望通過本書,能對高效解決雲原生架構下的微服務治理難題,起到一點點作用,電子版免費下載地址:

https://developer.aliyun.com/ebook/7565

1.png

長按二維碼直達下載地址

單體架構下的服務釋出

⾸先,我們先看⼀下在單體架構中,如何對應⽤中某個服務模組進⾏新版本釋出。如下圖,應⽤中的 Cart 服務模組有新版本迭代:

2.png

由於 Cart 服務是應⽤的⼀部分,所以新版本上線時需要對整個應⽤進⾏編譯、打包以及部署。服務級別釋出問題變成了應⽤級別的釋出問題,我們需要對應⽤的新版本⽽不是服務來實施有效的釋出策略。 

⽬前,業界已經有⾮常成熟的服務釋出⽅案,例如藍綠髮布和灰度釋出。藍綠髮布需要對服務的新版本進⾏冗餘部署,⼀般新版本的機器規格和數量與舊版本保持⼀致,相當於該服務有兩套完全相同的部署環境,只不過此時只有舊版本在對外提供服務,新版本作為熱備。當服務進⾏版本升級時,我們只需將流量全部切換到新版本即可,舊版本作為熱備。我們的例⼦使⽤藍綠髮布的示意圖如下,流量切換基於四層代理的流量⽹關即可完成。

3.png

在藍綠髮布中,由於存在流量整體切換,所以需要按照原服務佔⽤的機器規模為新版本克隆⼀套環境,相當於要求原來 1 倍的機器資源。灰度釋出的核⼼思想是根據請求內容或者請求流量的⽐例將線上流量的⼀⼩部分轉發⾄新版本,待灰度驗證通過後,逐步調⼤新版本的請求流量,是⼀種循序漸進的釋出⽅式。我們的例⼦使⽤灰度釋出的示意圖如下,基於內容或⽐例的流量控制需要藉助於⼀個七層代理的微服務⽹關來完成。

4.png

其中,Traffic Routing 是基於內容的灰度⽅式,⽐如請求中含有頭部 stag=gray 的流量路由到應⽤ v2 版本;Traffic Shifting 是基於⽐例的灰度⽅式,以⽆差別的⽅式對線上流量按⽐重進⾏分流。相⽐藍綠髮布,灰度釋出在機器資源成本以及流量控制能⼒上更勝⼀籌,但缺點就是釋出週期過⻓,對運維基礎設施要求較⾼。

微服務架構下的服務釋出

在分散式微服務架構中,應⽤中被拆分出來的⼦服務都是獨⽴部署、運⾏和迭代的。單個服務新版本上線時,我們再也不需要對應⽤整體進⾏發版,只需關注每個微服務⾃身的釋出流程即可,如下:

5.png

為了驗證服務 Cart 的新版本,流量在整個調⽤鏈路上能夠通過某種⽅式有選擇的路由到 Cart 的灰度版本,這屬於微服務治理領域中流量治理問題。常⻅的治理策略包括基於 Provider 和基於 Consumer 的⽅式。 

  1. 基於 Provider 的治理策略。配置 Cart 的流量流⼊規則,User 路由到 Cart 時使⽤ Cart 的流量流⼊規則。
  2. 基於 Consumer 的治理策略。配置 User 的流量流出規則, User 路由到 Cart 時使⽤ User 的流量流出規則。

此外,使⽤這些治理策略時可以結合上⾯介紹的藍綠髮布和灰度釋出⽅案來實施真正的服務級別的版本釋出。

什麼是全鏈路灰度

繼續考慮上⾯微服務體系中對服務 Cart 進⾏釋出的場景,如果此時服務 Order 也需要釋出新版本,由於本次新功能涉及到服務 Cart 和 Order 的共同變動,所以要求在灰度驗證時能夠使得灰度流量同時經過服務 Cart 和 Order 的灰度版本。如下圖:

6.png

按照上⼀⼩節提出的兩種治理策略,我們需要額外配置服務 Order 的治理規則,確保來⾃灰度環境的服務 Cart 的流量轉發⾄服務 Order 的灰度版本。這樣的做法看似符合正常的操作邏輯,但在真實業務場景中,業務的微服務規模和數量遠超我們的例⼦,其中⼀條請求鏈路可能經過數⼗個微服務,新功能釋出時也可能會涉及到多個微服務同時變更,並且業務的服務之間依賴錯綜複雜,頻繁的服務釋出、以及服務多版本並⾏開發導致流量治理規則⽇益膨脹,給整個系統的維護性和穩定性帶來了不利因素。 

對於以上的問題,開發者結合實際業務場景和⽣產實踐經驗,提出了⼀種端到端的灰度釋出⽅案,即全鏈路灰度。全鏈路灰度治理策略主要專注於整個調⽤鏈,它不關⼼鏈路上經過具體哪些微服務,流量控制視⻆從服務轉移⾄請求鏈路上,僅需要少量的治理規則即可構建出從⽹關到整個後端服務的多個流量隔離環境,有效保證了多個親密關係的服務順利安全釋出以及服務多版本並⾏開發,進⼀步促進業務的快速發展。

全鏈路灰度的解決方案

如何在實際業務場景中去快速落地全鏈路灰度呢?⽬前,主要有兩種解決思路,基於物理環境隔離和基於邏輯環境隔離。

物理環境隔離

物理環境隔離,顧名思義,通過增加機器的⽅式來搭建真正意義上的流量隔離。\

7.png

這種⽅案需要為要灰度的服務搭建⼀套⽹絡隔離、資源獨⽴的環境,在其中部署服務的灰度版本。由於與正式環境隔離,正式環境中的其他服務⽆法訪問到需要灰度的服務,所以需要在灰度環境中冗餘部署這些線上服務,以便整個調⽤鏈路正常進⾏流量轉發。此外,註冊中⼼等⼀些其他依賴的中介軟體元件也 需要冗餘部署在灰度環境中,保證微服務之間的可⻅性問題,確保獲取的節點 IP 地址只屬於當前的⽹絡環境。 

這個⽅案⼀般⽤於企業的測試、預發開發環境的搭建,對於線上灰度釋出引流的場景來說其靈活性不夠。況且,微服務多版本的存在在微服務架構中是家常便飯,需要為這些業務場景採⽤堆機器的⽅式來 維護多套灰度環境。如果您的應⽤數⽬過多的情況下,會造成運維、機器成本過⼤,成本和代價遠超收益;如果應⽤數⽬很⼩,就兩三個應⽤,這個⽅式還是很⽅便的,可以接受的。

邏輯環境隔離

另⼀種⽅案是構建邏輯上的環境隔離,我們只需部署服務的灰度版本,流量在調⽤鏈路上流轉時,由流經的⽹關、各個中介軟體以及各個微服務來識別灰度流量,並動態轉發⾄對應服務的灰度版本。如下圖:

8.png

上圖可以很好展示這種方案的效果,我們用不同的顏色來表示不同版本的灰度流量,可以看出無論是微服務閘道器還是微服務本身都需要識別流量,根據治理規則做出動態決策。當服務版本發生變化時,這個呼叫鏈路的轉發也會實時改變。相比於利用機器搭建的灰度環境,這種方案不僅可以節省大量的機器成本和運維人力,而且可以幫助開發者實時快速的對線上流量進行精細化的全鏈路控制。 

那麼全鏈路灰度具體是如何實現呢?通過上⾯的討論,我們需要解決以下問題: 

1.鏈路上各個元件和服務能夠根據請求流量特徵進⾏動態路由。

2.需要對服務下的所有節點進⾏分組,能夠區分版本。

3.需要對流量進⾏灰度標識、版本標識。

4.需要識別出不同版本的灰度流量。 

接下來,會介紹解決上述問題需要⽤到的技術。

標籤路由

標籤路由通過對服務下所有節點按照標籤名和標籤值不同進⾏分組,使得訂閱該服務節點資訊的服務消費端可以按需訪問該服務的某個分組,即所有節點的⼀個⼦集。服務消費端可以使⽤服務提供者節點上的任何標籤資訊,根據所選標籤的實際含義,消費端可以將標籤路由應⽤到更多的業務場景中。

9.png

節點打標

那麼如何給服務節點新增不同的標籤呢?在如今⽕熱的雲原⽣技術推動下,⼤多數業務都在積極進⾏容器化改造之旅。這⾥,我就以容器化的應⽤為例,介紹在使⽤ Kubernetes Service 作為服務發現和使⽤⽐較流⾏的 Nacos 註冊中⼼這兩種場景下如何對服務 Workload 進⾏節點打標。 

在使⽤ Kubernetes Service 作為服務發現的業務系統中,服務提供者通過向 ApiServer 提交 Service 資源完成服務暴露,服務消費端監聽與該 Service 資源下關聯的 Endpoint 資源,從 Endpoint 資源中獲取關聯的業務 Pod 資源,讀取上⾯的 Labels 資料並作為該節點的元資料資訊。所以,我們只要在業務應⽤描述資源 Deployment 中的 Pod 模板中為節點新增標籤即可。

10.png

在使⽤ Nacos 作為服務發現的業務系統中,⼀般是需要業務根據其使⽤的微服務框架來決定打標⽅式。如果 Java 應⽤使⽤的 Spring Cloud 微服務開發框架,我們可以為業務容器新增對應的環境變數來完成標籤的新增操作。⽐如我們希望為節點新增版本灰度標,那麼為業務容器新增spring.cloud.nacos.discovery.metadata.version=gray,這樣框架向 Nacos 註冊該節點時會為其新增⼀個標籤verison=gray

11.png

流量染色

請求鏈路上各個元件如何識別出不同的灰度流量?答案就是流量染⾊,為請求流量新增不同灰度標識來⽅便區分。我們可以在請求的源頭上對流量進⾏染⾊,前端在發起請求時根據⽤戶資訊或者平臺資訊的不同對流量進⾏打標。如果前端⽆法做到,我們也可以在微服務⽹關上對匹配特定路由規則的請求動態 新增流量標識。此外,流量在鏈路中流經灰度節點時,如果請求資訊中不含有灰度標識,需要⾃動為其染⾊,接下來流量就可以在後續的流轉過程中優先訪問服務的灰度版本。

分散式鏈路追蹤

還有⼀個很重要的問題是如何保證灰度標識能夠在鏈路中⼀直傳遞下去呢?如果在請求源頭染⾊,那麼請求經過⽹關時,⽹關作為代理會將請求原封不動的轉發給⼊⼝服務,除⾮開發者在⽹關的路由策略中實施請求內容修改策略。接著,請求流量會從⼊⼝服務開始調⽤下⼀個微服務,會根據業務程式碼邏輯形成新的調⽤請求,那麼我們如何將灰度標識新增到這個新的調⽤請求,從⽽可以在鏈路中傳遞下去呢? 

從單體架構演進到分散式微服務架構,服務之間調⽤從同⼀個執行緒中⽅法調⽤變為從本地程序的服務調⽤遠端程序中服務,並且遠端服務可能以多副本形式部署,以⾄於⼀條請求流經的節點是不可預知的、不確定的,⽽且其中每⼀跳的調⽤都有可能因為⽹絡故障或服務故障⽽出錯。分散式鏈路追蹤技術對⼤型分散式系統中請求調⽤鏈路進⾏詳細記錄,核⼼思想就是通過⼀個全域性唯⼀的 traceid 和每⼀條的 spanid 來記錄請求鏈路所經過的節點以及請求耗時,其中 traceid 是需要整個鏈路傳遞的。 

藉助於分散式鏈路追蹤思想,我們也可以傳遞⼀些⾃定義資訊,⽐如灰度標識。業界常⻅的分散式鏈路追蹤產品都⽀持鏈路傳遞⽤戶⾃定義的資料,其資料處理流程如下圖所示:

12.png

邏輯環境隔離

⾸先,需要⽀持動態路由功能,對於 Spring Cloud、Dubbo 開發框架,可以對出⼝流量實現⾃定義 Filter,在該 Filter 中完成流量識別以及標籤路由。同時需要藉助分散式鏈路追蹤技術完成流量標識鏈路傳遞以及流量⾃動染⾊。此外,需要引⼊⼀箇中⼼化的流量治理平臺,⽅便各個業務線的開發者定義⾃⼰的全鏈路灰度規則。如下圖所示:

13.png

總體上看,實現全鏈路灰度的能⼒,⽆論是成本還是技術複雜度都是⽐較⾼的,以及後期的維護、擴充套件都是⾮常⼤的成本,但確實更精細化的提高了釋出過程中的應用穩定性。

點選此處,前往微服務引擎 MSE 官網檢視更多詳情!