天天看點

深入剖析全鍊路灰階技術内幕

作者:揚少

當服務有新版本要釋出上線時,通過引流一小部分流量到新版本,可以及時發現程式問題,有效阻止大面積故障的發生。業界上已經有比較成熟的服務釋出政策,比如藍綠釋出、A/B 測試以及金絲雀釋出,這些釋出政策主要專注于如何對單個服務進行釋出。在微服務體系架構中,服務之間的依賴關系錯綜複雜,有時某個功能發版依賴多個服務同時更新上線。我們希望可以對這些服務的新版本同時進行小流量灰階驗證,這就是微服務架構中特有的全鍊路灰階場景,通過建構從網關到整個後端服務的環境隔離來對多個不同版本的服務進行灰階驗證。

本文将會揭開全鍊路灰階的神秘面紗,深入剖析全鍊路灰階技術内幕,引出兩種不同的實作方案,并對實作方案的技術細節進行深入探讨,最後通過實踐環節來展示全鍊路灰階在實際業務中的使用場景。

微服務架構帶來的挑戰

為了滿足業務的疊代速度,開發者開始對原來的單體架構進行細粒度的拆分,将單體應用中的服務子產品拆分成一個個獨立部署運作的微服務,并且這些微服務的生命周期由對應的業務團隊獨自負責,有效的解決了單體架構中存在的靈活性不足、靈活性不強的問題。常見的做法是根據業務域或者功能域進行服務拆分,如下圖:

深入剖析全鍊路灰階技術内幕

其中,流量網關是四層代理,主要功能有負載均衡、TLS 解除安裝以及一些安全防護功能;微服務網關是七層代理,主要用來暴露後端服務、流量治理、通路控制和流量監控。以"高内聚、低耦合"作為設計理念的微服務架構為開發者帶來了前所未有的開發體驗,每個業務團隊專注于自身業務的代碼邏輯,并通過 API 形式對外釋出。服務依賴方隻需引入服務提供方的 API 定義,即可完成服務之間通信,無需關心服務提供方的部署形态和内部實作。

但任何架構都不是銀彈,在解決舊問題同時勢必會引入一些新的問題。微服務體系中最令人頭疼的問題,是如何對衆多微服務進行高效、便捷的治理,主要表現在可見性、連接配接性和安全性這三個方面。進一步細化,微服務架構帶來了以下的挑戰:

深入剖析全鍊路灰階技術内幕

本文的重點主要關注服務釋出這一子領域,如何保證微服務體系中服務新版本更新過程中平滑無損,以及如何低成本的為多個微服務建構流量隔離環境,友善開發者同時對多個服務新版本進行充分的灰階驗證,避免故障的發生。

什麼是全鍊路灰階

單體架構下的服務釋出

首先,我們先看一下在單體架構中,如何對應用中某個服務子產品進行新版本釋出。如下圖,應用中的 Cart 服務子產品有新版本疊代:

深入剖析全鍊路灰階技術内幕

由于 Cart 服務是應用的一部分,是以新版本上線時需要對整個應用進行編譯、打包以及部署。服務級别釋出問題變成了應用級别的釋出問題,我們需要對應用的新版本而不是服務來實施有效的釋出政策。

目前,業界已經有非常成熟的服務釋出方案,例如藍綠釋出和灰階釋出。藍綠釋出需要對服務的新版本進行備援部署,一般新版本的機器規格和數量與舊版本保持一緻,相當于該服務有兩套完全相同的部署環境,隻不過此時隻有舊版本在對外提供服務,新版本作為熱備。當服務進行版本更新時,我們隻需将流量全部切換到新版本即可,舊版本作為熱備。我們的例子使用藍綠釋出的示意圖如下,流量切換基于四層代理的流量網關即可完成。

深入剖析全鍊路灰階技術内幕

在藍綠釋出中,由于存在流量整體切換,是以需要按照原服務占用的機器規模為新版本克隆一套環境,相當于要求原來1倍的機器資源。灰階釋出的核心思想是根據請求内容或者請求流量的比例将線上流量的一小部分轉發至新版本,待灰階驗證通過後,逐漸調大新版本的請求流量,是一種循序漸進的釋出方式。我們的例子使用灰階釋出的示意圖如下,基于内容或比例的流量控制需要借助于一個七層代理的微服務網關來完成。

深入剖析全鍊路灰階技術内幕

其中,Traffic Routing 是基于内容的灰階方式,比如請求中含有頭部 stag=gray 的流量路由到應用 v2 版本;Traffic Shifting 是基于比例的灰階方式,以無差别的方式對線上流量按比重進行分流。相比藍綠釋出,灰階釋出在機器資源成本以及流量控制能力上更勝一籌,但缺點就是釋出周期過長,對運維基礎設施要求較高。

微服務架構下的服務釋出

在分布式微服務架構中,應用中被拆分出來的子服務都是獨立部署、運作和疊代的。單個服務新版本上線時,我們再也不需要對應用整體進行發版,隻需關注每個微服務自身的釋出流程即可,如下:

深入剖析全鍊路灰階技術内幕

為了驗證服務 Cart 的新版本,流量在整個調用鍊路上能夠通過某種方式有選擇的路由到 Cart 的灰階版本,這屬于微服務治理領域中流量治理問題。常見的治理政策包括基于 Provider 和基于 Consumer 的方式。

  • 基于 Provider 的治理政策。配置 Cart 的流量流入規則,User 路由到 Cart 時使用 Cart 的流量流入規則。
  • 基于 Consumer 的治理政策。配置 User 的流量流出規則, User 路由到 Cart 時使用 User 的流量流出規則。

此外,使用這些治理政策時可以結合上面介紹的藍綠釋出和灰階釋出方案來實施真正的服務級别的版本釋出。

全鍊路灰階

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

深入剖析全鍊路灰階技術内幕

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

對于以上的問題,開發者結合實際業務場景和生産實踐經驗,提出了一種端到端的灰階釋出方案,即全鍊路灰階。全鍊路灰階治理政策主要專注于整個調用鍊,它不關心鍊路上經過具體哪些微服務,流量控制視角從服務轉移至請求鍊路上,僅需要少量的治理規則即可建構出從網關到整個後端服務的多個流量隔離環境,有效保證了多個親密關系的服務順利安全釋出以及服務多版本并行開發,進一步促進業務的快速發展。

全鍊路灰階的解決方案

如何在實際業務場景中去快速落地全鍊路灰階呢?目前,主要有兩種解決思路,基于實體環境隔離和基于邏輯環境隔離。

實體環境隔離

實體環境隔離,顧名思義,通過增加機器的方式來搭建真正意義上的流量隔離。

深入剖析全鍊路灰階技術内幕

這種方案需要為要灰階的服務搭建一套網絡隔離、資源獨立的環境,在其中部署服務的灰階版本。由于與正式環境隔離,正式環境中的其他服務無法通路到需要灰階的服務,是以需要在灰階環境中備援部署這些線上服務,以便整個調用鍊路正常進行流量轉發。此外,注冊中心等一些其他依賴的中間件元件也需要備援部署在灰階環境中,保證微服務之間的可見性問題,確定擷取的節點 IP 位址隻屬于目前的網絡環境。

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

邏輯環境隔離

另一種方案是建構邏輯上的環境隔離,我們隻需部署服務的灰階版本,流量在調用鍊路上流轉時,由流經的網關、各個中間件以及各個微服務來識别灰階流量,并動态轉發至對應服務的灰階版本。如下圖:

深入剖析全鍊路灰階技術内幕

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

那麼全鍊路灰階具體是如何實作呢?通過上面的讨論,我們需要解決以下問題:

  1. 鍊路上各個元件和服務能夠根據請求流量特征進行動态路由
  2. 需要對服務下的所有節點進行分組,能夠區分版本
  3. 需要對流量進行灰階辨別、版本辨別
  4. 需要識别出不同版本的灰階流量

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

标簽路由

标簽路由通過對服務下所有節點按照标簽名和标簽值不同進行分組,使得訂閱該服務節點資訊的服務消費端可以按需通路該服務的某個分組,即所有節點的一個子集。服務消費端可以使用服務提供者節點上的任何标簽資訊,根據所選标簽的實際含義,消費端可以将标簽路由應用到更多的業務場景中。

深入剖析全鍊路灰階技術内幕
深入剖析全鍊路灰階技術内幕

節點打标

那麼如何給服務節點添加不同的标簽呢?在如今火熱的雲原生技術推動下,大多數業務都在積極進行容器化改造之旅。這裡,我就以容器化的應用為例,介紹在使用 Kubernetes Service 作為服務發現和使用比較流行的 Nacos 注冊中心這兩種場景下如何對服務 Workload 進行節點打标。

在使用 Kubernetes Service 作為服務發現的業務系統中,服務提供者通過向 ApiServer 送出 Service 資源完成服務暴露,服務消費端監聽與該 Service 資源下關聯的 Endpoint 資源,從 Endpoint 資源中擷取關聯的業務 Pod 資源,讀取上面的 Labels 資料并作為該節點的中繼資料資訊。是以,我們隻要在業務應用描述資源 Deployment 中的 Pod 模闆中為節點添加标簽即可。

深入剖析全鍊路灰階技術内幕

在使用 Nacos 作為服務發現的業務系統中,一般是需要業務根據其使用的微服務架構來決定打标方式。如果 Java 應用使用的 Spring Cloud 微服務開發架構,我們可以為業務容器添加對應的環境變量來完成标簽的添加操作。比如我們希望為節點添加版本灰階标,那麼為業務容器添加`spring.cloud.nacos.discovery.metadata.version=gray`,這樣架構向Nacos注冊該節點時會為其添加一個标簽`verison=gray`。

深入剖析全鍊路灰階技術内幕

流量染色

請求鍊路上各個元件如何識别出不同的灰階流量?答案就是流量染色,為請求流量添加不同灰階辨別來友善區分。我們可以在請求的源頭上對流量進行染色,前端在發起請求時根據使用者資訊或者平台資訊的不同對流量進行打标。如果前端無法做到,我們也可以在微服務網關上對比對特定路由規則的請求動态添加流量辨別。此外,流量在鍊路中流經灰階節點時,如果請求資訊中不含有灰階辨別,需要自動為其染色,接下來流量就可以在後續的流轉過程中優先通路服務的灰階版本。

分布式鍊路追蹤

還有一個很重要的問題是如何保證灰階辨別能夠在鍊路中一直傳遞下去呢?如果在請求源頭染色,那麼請求經過網關時,網關作為代理會将請求原封不動的轉發給入口服務,除非開發者在網關的路由政策中實施請求内容修改政策。接着,請求流量會從入口服務開始調用下一個微服務,會根據業務代碼邏輯形成新的調用請求,那麼我們如何将灰階辨別添加到這個新的調用請求,進而可以在鍊路中傳遞下去呢?

從單體架構演進到分布式微服務架構,服務之間調用從同一個線程中方法調用變為從本地程序的服務調用遠端程序中服務,并且遠端服務可能以多副本形式部署,以至于一條請求流經的節點是不可預知的、不确定的,而且其中每一跳的調用都有可能因為網絡故障或服務故障而出錯。分布式鍊路追蹤技術對大型分布式系統中請求調用鍊路進行詳細記錄,核心思想就是通過一個全局唯一的 traceid 和每一條的 spanid 來記錄請求鍊路所經過的節點以及請求耗時,其中 traceid 是需要整個鍊路傳遞的。

借助于分布式鍊路追蹤思想,我們也可以傳遞一些自定義資訊,比如灰階辨別。業界常見的分布式鍊路追蹤産品都支援鍊路傳遞使用者自定義的資料,其資料處理流程如下圖所示:

深入剖析全鍊路灰階技術内幕

邏輯環境隔離——基于 SDK

上面我們詳細介紹了實作全鍊路灰階所需要的幾種技術,如果想為現有的業務接入全鍊路灰階能力,不可避免的需要為業務使用的開發架構 SDK 進行改造。首先,需要支援動态路由功能,對于 Spring Cloud、Dubbo 開發架構,可以對出口流量實作自定義 Filter,在該 Filter 中完成流量識别以及标簽路由。同時需要借助分布式鍊路追蹤技術完成流量辨別鍊路傳遞以及流量自動染色。此外,需要引入一個中心化的流量治理平台,友善各個業務線的開發者定義自己的全鍊路灰階規則。基于 SDK 實作方式的圖例如下:

深入剖析全鍊路灰階技術内幕

邏輯環境隔離——基于 Java Agent

基于 SDK 方式的弊端在于需要業務進行 SDK 版本更新,甚至會涉及到業務代碼的變動。企業内部各個微服務雖然使用同一種開發架構,但很難保證架構版本是一緻的,是以不得不為每一個版本維護一份全鍊路灰階的代碼。業務代碼與 SDK 代碼緊耦合,SDK 版本疊代會觸發業務不必要的發版變更,對業務的侵入性比較強。

另一種比較流行的方式是基于位元組碼增強技術在編譯時對開發架構進行功能拓展,這種方案業務無感覺,以無侵入方式為業務引入全鍊路灰階能力。基于 Java Agent 的實作方式的圖例如下:

深入剖析全鍊路灰階技術内幕
深入剖析全鍊路灰階技術内幕

但仍然無法避免是開發者需要為業務使用版本不一緻的開發架構維護對應的 Java Agent 的版本。如果您比較傾向于這種無侵入的方案但又不想自己來維護,您可以選擇阿裡雲 MSE 服務治理産品,該産品就是一款基于 Java Agent 實作的無侵入式企業生産級服務治理産品,您不需要修改任何一行業務代碼,即可擁有不限于全鍊路灰階的治理能力,并且支援近 5 年内所有的 Spring Boot、Spring Cloud 和 Dubbo。

邏輯環境隔離——基于 Service Mesh

在業務系統的微服務架構中,如果存在大量使用不同的技術棧、語言棧的微服務,Java Agent 的方式就無能為力了。我們可能需要為每一個語言的 SDK 編寫和維護全鍊路灰階代碼,不僅需要不同語言棧的開發者,而且涉及到語言無關的 bug 修複時需要全語言版本的 SDK 共同更新,這種代價不見得比基于實體環境隔離方案小。

那有沒有一種與語言無關的方案呢?有,下一代微服務架構服務網格,Service Mesh。它将分布式服務的通信層抽象為單獨的一層,在這一層中實作負載均衡、服務發現、認證授權、監控追蹤、流量控制等分布式系統所需要的功能。顯然,我們所需的全鍊路灰階能力也可以在這個流量治理基礎設施層來實作。幸運的是,服務網格明星産品Istio以聲明式 API 資源對流量治理進行了統一抽象,借助于 VirtualService 和 DestinationRule 治理規則可以很容易實作全鍊路灰階的效果,并且Istio內建了各種主流的分布式鍊路追蹤架構。基于 Service Mesh 的實作方式的圖例如下:

深入剖析全鍊路灰階技術内幕

在實際生産環境中,服務多版本并行開發是很常見的事情,而且版本疊代速度非常快。版本每次變更都需要修改 VirtualSerivice 資源中路由比對規則,另外 VirtualSerivice 資源中并沒有提供容災能力。比如存在一條路由規則通路服務提供方的某個灰階版本,如果目标服務不存在該灰階版本或者不可用,按照目前 Istio 的實作是仍然将流量轉發至該版本,缺乏容災機制。還有一種業務場景,如果我們希望對處于一定 UID 範圍的使用者流量轉發指定灰階環境,是無法通過 Istio 現有的流量治理規則實作的。此時,您可以選擇阿裡雲服務網格産品 ASM,是一個統一管理微服務應用流量、相容 Istio 的托管式平台。ASM 針對上述兩個場景都有應對方案,輕松解決您在多語言場景下的全鍊路灰階訴求。

三種方式對比

下表是三種方式對比,從多個方面進行了對比。

深入剖析全鍊路灰階技術内幕
  • 如果您傾向于使用無侵入式的 Java Agent 的方式,但又擔心自建帶來的穩定性問題,您可以選擇 MSE 微服務治理産品,該産品是阿裡巴巴内部多年在微服務治理領域的沉澱的産出,經曆了各種大促考驗。
  • 如果您傾向于使用語言無關、無侵入式的 Service Mesh 的方式,但又擔心自建帶來的穩定性問題,您可以選擇阿裡雲 ASM 産品,相比開源 Istio,在功能性、穩定性和安全性都有很大的提升。

流量入口:網關

在分布式應用中,作為流量入口的網關是不可或缺的。在全鍊路灰階場景中,就要求微服務網關具備豐富的流量治理能力,支援服務多版本路由,支援對特定路由規則上的請求進行動态打标。對于入口服務可見性問題,網關需要支援多種服務發現方式。安全性問題上,網關作為叢集對外的入口可以對所有請求流量進行認證鑒權,保障業務系統不被非法流量入侵。

在虛拟化時期的微服務架構下,業務通常采用流量網關 + 微服務網關的兩層架構,流量網關負責南北向流量排程和安全防護,微服務網關負責東西向流量排程和服務治理。在容器和 K8s 主導的雲原生時代,Ingress 成為 K8s 生态的網關标準,賦予了網關新的使命,使得流量網關 + 微服務網關合二為一成為可能。阿裡雲 MSE 釋出的雲原生網關在能力不打折的情況下,将兩層網關變為一層,不僅可以節省 50% 的資源成本,還可以降低運維及使用成本。最重要的是,雲原生網關支援與後端微服務治理關聯實作端到端的全鍊路灰階。

深入剖析全鍊路灰階技術内幕

從 0 到 1 實踐全鍊路灰階

看到這裡,相信大多數讀者對全鍊路灰階有了大概的認識,也了解了幾種解決方案以及實作細節。接下來,我們會基于文中提到的 MSE 雲原生網關和 MSE 服務治理産品,從 0 到 1 對全鍊路灰階進行實踐,一方面加深對全鍊路灰階的認識,另一方面可以了解下阿裡雲是如何将阿裡巴巴内部的最佳實踐輸出到雲産品中。

我們假設應用的架構由 MSE 雲原生網關以及後端的微服務架構(Spring Cloud)來組成,後端調用鍊路有 3 跳,購物車(a),交易中心(b),庫存中心(c),通過用戶端或者是 H5 頁面來通路後端服務,它們通過 Nacos 注冊中心做服務發現。現在希望使用全鍊路灰階能力建構一個灰階環境,友善對服務 A 和服務 C 同時進行灰階驗證。

深入剖析全鍊路灰階技術内幕

前提條件

必備的資源清單

  • 已擁有一個 MSE 雲原生網關
  • 已擁有一個 MSE Nacos 注冊中心
  • 已擁有一個 ACK 運維叢集
  • 已開通 MSE 微服務治理專業版

部署 Demo 應用程式

将下面的檔案儲存到 ingress-gray.yaml 中,并執行 

kubectl apply -f ingress-gray.yaml

 以部署應用,這裡我們将要部署 A,B,C 三個應用,A 和 C 應用分别部署一個基線版本和一個灰階版本,B 應用部署一個基線版本。

有以下注意點:

  1. 全鍊路灰階能力是與注冊中心無關的,本文用例暫以 MSE Nacos 作為注冊中心,是以需要将 spring.cloud.nacos.discovery.server-addr 換成業務自己的 Nacos 注冊中心位址
  1. 接入雲原生網關的服務,如果需要使用灰階釋出,需要在釋出服務時在中繼資料資訊增加版本标。在我們的例子,服務 A 是需要暴露給網關,是以釋出時為基線版本添加spring.cloud.nacos.discovery.metadata.version=base,為灰階版本添加 spring.cloud.nacos.discovery.metadata.version=gray。
# A 應用 base 版本
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: spring-cloud-a
  name: spring-cloud-a
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-a
  template:
    metadata:
      annotations:
        msePilotCreateAppName: spring-cloud-a
      labels:
        app: spring-cloud-a
    spec:
      containers:
      - env:
        - name: LANG
          value: C.UTF-8
        - name: JAVA_HOME
          value: /usr/lib/jvm/java-1.8-openjdk/jre
        - name: spring.cloud.nacos.discovery.server-addr
          value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848
        - name: spring.cloud.nacos.discovery.metadata.version
          value: base
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT
        imagePullPolicy: Always
        name: spring-cloud-a
        ports:
        - containerPort: 20001
          protocol: TCP
        resources:
          requests:
            cpu: 250m
            memory: 512Mi
      
# A 應用 gray 版本
---            
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: spring-cloud-a-new
  name: spring-cloud-a-new
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-a-new
  strategy:
  template:
    metadata:
      annotations:
        alicloud.service.tag: gray
        msePilotCreateAppName: spring-cloud-a
      labels:
        app: spring-cloud-a-new
    spec:
      containers:
      - env:
        - name: LANG
          value: C.UTF-8
        - name: JAVA_HOME
          value: /usr/lib/jvm/java-1.8-openjdk/jre
        - name: profiler.micro.service.tag.trace.enable
          value: "true"
        - name: spring.cloud.nacos.discovery.server-addr
          value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848
        - name: spring.cloud.nacos.discovery.metadata.version
          value: gray
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT
        imagePullPolicy: Always
        name: spring-cloud-a-new
        ports:
        - containerPort: 20001
          protocol: TCP
        resources:
          requests:
            cpu: 250m
            memory: 512Mi
            
# B 應用 base 版本
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: spring-cloud-b
  name: spring-cloud-b
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-b
  strategy:
  template:
    metadata:
      annotations:
        msePilotCreateAppName: spring-cloud-b
      labels:
        app: spring-cloud-b
    spec:
      containers:
      - env:
        - name: LANG
          value: C.UTF-8
        - name: JAVA_HOME
          value: /usr/lib/jvm/java-1.8-openjdk/jre
        - name: spring.cloud.nacos.discovery.server-addr
          value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:0.2-demo-SNAPSHOT 
        imagePullPolicy: Always
        name: spring-cloud-b
        ports:
        - containerPort: 8080
          protocol: TCP
        resources:
          requests:
            cpu: 250m
            memory: 512Mi
            
# C 應用 base 版本
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: spring-cloud-c
  name: spring-cloud-c
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-c
  template:
    metadata:
      annotations:
        msePilotCreateAppName: spring-cloud-c
      labels:
        app: spring-cloud-c
    spec:
      containers:
      - env:
        - name: LANG
          value: C.UTF-8
        - name: JAVA_HOME
          value: /usr/lib/jvm/java-1.8-openjdk/jre
        - name: spring.cloud.nacos.discovery.server-addr
          value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.2-demo-SNAPSHOT
        imagePullPolicy: Always
        name: spring-cloud-c
        ports:
        - containerPort: 8080
          protocol: TCP
        resources:
          requests:
            cpu: 250m
            memory: 512Mi
            
# C 應用 gray 版本
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: spring-cloud-c-new
  name: spring-cloud-c-new
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-c-new
  template:
    metadata:
      annotations:
        alicloud.service.tag: gray
        msePilotCreateAppName: spring-cloud-c
      labels:
        app: spring-cloud-c-new
    spec:
      containers:
      - env:
        - name: LANG
          value: C.UTF-8
        - name: JAVA_HOME
          value: /usr/lib/jvm/java-1.8-openjdk/jre
        - name: spring.cloud.nacos.discovery.server-addr
          value: mse-455e0c20-nacos-ans.mse.aliyuncs.com:8848
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.2-demo-SNAPSHOT
        imagePullPolicy: Always
        name: spring-cloud-c-new
        ports:
        - containerPort: 8080
          protocol: TCP
        resources:
          requests:
            cpu: 250m
            memory: 512Mi      

完成雲原生網關初步配置

第一步,為雲原生網關添加 Nacos 服務來源,服務管理,來源管理,點選建立來源,

深入剖析全鍊路灰階技術内幕

選擇 MSE Nacos 服務來源,選擇需要關聯的 Nacos 注冊中心,點選确定。

深入剖析全鍊路灰階技術内幕

第二步,導入要通過雲原生網關暴露給外部的服務。選擇服務管理,服務清單,點選建立服務。

選擇服務來源為 MSE Nacos,選擇服務 sc-A。

深入剖析全鍊路灰階技術内幕

點選服務 A 的政策配置,為入口服務 A 建立多版本,版本劃分依據服務注冊時所帶的中繼資料資訊 version(注意,這裡可以是任意可以區分服務版本的标簽值,取決于使用者注冊服務時所采用的中繼資料資訊),建立以下兩個版本 base 和 gray。

深入剖析全鍊路灰階技術内幕

路由配置

建立基線環境的路由比對規則,關聯域名 base.example.com,路由到服務 sc-A 的 base 版本中。

深入剖析全鍊路灰階技術内幕

建立灰階環境的路由比對規則,關聯的域名與基線環境保持一緻,注意此處增加了請求頭相關的配置,并且路由的目标服務為服務 sc-A 的 gray 版本。

深入剖析全鍊路灰階技術内幕

這時,我們有了如下兩條路由規則,

深入剖析全鍊路灰階技術内幕

此時,通路 

base.example.com

 路由到基線環境

curl -H "Host: base.example.com" http://118.31.118.69/a
A[172.21.240.105] -> B[172.21.240.106] -> C[172.21.240.46]      

如何通路灰階環境呢?隻需要在請求中增加一個 

header x-mse-tag: gray

 即可。

curl -H "Host: base.example.com" -H "x-mse-tag: gray" http://118.31.118.69/a
Agray[172.21.240.44] -> B[172.21.240.146] -> Cgray[172.21.240.147]      

可以看到 雲原生網關 将灰階流量路由到了 A 和 C 的灰階版本,由于B沒有指定的灰階版本,是以流量自動回退到基線版本。

分析

從上面可以看出,我們隻需要開通 MSE 微服務治理專業版,在雲原生網關配置入口服務的路由規則,并且對入口流量進行灰階染色,即可滿足我們對 A 和 C 全鍊路灰階的要求。另外還有一個很重要的點是,業務需要自行對節點打标并對入口服務開啟鍊路傳遞。為 Pod 模闆的 Annotations添加 alicloud.service.tag 鍵值對完成節點打标,Java Agent 會在業務向注冊中心時登記節點時自動為其添加這個中繼資料資訊,同時需要為入口服務的業務容器添加環境變量 

profiler.micro.service.tag.trace.enable=true

 開啟鍊路傳遞灰階辨別。MSE 服務治理元件預設使用 x-mse-tag 來辨別流量,并在整個調用鍊路中傳遞。

另外,您可以設定其他自定義或業務已有的字段來辨別流量,更多詳情操作、場景展示參考文檔:

https://help.aliyun.com/document_detail/359851.html

總結

本文從單體架構向微服務架構演進過程中帶來的挑戰展開,着重對其子領域服務釋出在單體架構和微服務架構體系下的形态進行分析,引出了分布式應用場景中特有的全鍊路灰階問題。針對業務對全鍊路能力的要求,介紹了基于實體環境隔離和基于邏輯環境隔離兩種方案,其中對基于邏輯環境隔離方案進行詳細分析,對涉及到的各個技術點也進行了很好的解釋,接着提出了三種基于邏輯環境隔離的落地方案,并進行了簡單的對比分析,最後引出了阿裡雲 MSE 雲原生、MSE 服務治理和服務網格 ASM 是如何提供不限于全鍊路灰階的流量治理能力。

最後,對網關、微服務治理領域感興趣的同學,可以釘釘搜尋群号 34754806 或掃描下方二維碼加入使用者群交流、答疑。

深入剖析全鍊路灰階技術内幕

點選

此處

,檢視微服務治理之全鍊路灰階直播回放!