作者:來自 vivo 網際網路研發效能團隊- Wang Kang
測試環境全鏈路多版本部署,解決多測試環境資源爭搶等問題。
一、背景介紹
軟體系統中全鏈路指的是從使用者請求發起,到最終返回響應的整個過程中所涉及到的所有環節和元件。在微服務軟體架構風格盛行的今天,因為微服務獨立部署、松耦合等特性,往往一個業務系統由數目較多的服務組成,較多的服務往往帶來一系列操作上的複雜性。
全鏈路部署指的是將整個軟體系統的所有服務一次性部署環境中的一種部署方式,這種部署方式可以簡化我們日常釋出流程,確保系統的所有服務協同工作。
vivo 的 CICD 釋出系統從【構建部署指令碼自動化】>【持續整合平臺化】>【整合更多 DevOps 功能和元件】,演進到現在更加靈活編輯的多服務編排方式。為了適應最新的微服務軟體架構風格,CICD 釋出系統透過中介軟體元件和呼叫鏈技術實現的落地,基於容器建立了全鏈路多版本流水線部署能力。
多版本部署則是基於灰度釋出的理念,在同一時間內,將不同版本的服務部署在同一個環境中,使得不同版本的服務可以同時執行和提供服務的一種部署方式。
隨著網際網路發展增速,軟體開發和部署需要快速迭代,軟體釋出變得越來越頻繁和複雜。迭代版本持續交付過程中,多個版本並行基本是所有專案常態化的情況,為此專案團隊往往會搭建多套測試環境以備功能驗證。多套環境的服務、元件和配置資料維護不僅大量佔用研發人員的日常工作時間,環境部署所需資源也佔用越來越多的公司硬體成本,即便這樣可能也無法完全滿足產品研發過程中遇到的緊急修復版本或臨時插入的高優需求這樣需要佔用環境的問題。當前專案的應對措施往往都是讓當前常規版本臨時“讓開”,先讓緊急分支版本釋出到正在使用的測試環境上,驗證透過後再釋放環境,讓常規版本回歸繼續測試驗證。
我們希望透過全鏈路多版本部署解決傳統測試環境存在的如下幾個問題。
二、全鏈路多版本部署技術方案
2.1 部署架構
上文就全鏈路多版本部署名稱解釋和與傳統環境區別做了簡單介紹,為進一步給大家清晰區分全鏈路多版本部署的測試環境與傳統測試環境區別,下面從部署架構圖的角度再次闡述下兩者的區別。
傳統測試環境就是將業務線上的服務全量部署幾套以供使用。傳統測試環境使用也比較簡單,不同環境通常擁有不同的域名或者同一個域名不同的 hosts 對映,使用者透過修改配置直接訪問到具體環境上。
在全鏈路多版本環境中,只有基線環境是將業務線上的服務全量部署,其餘特性環境只需拉起需要的個別服務即可。
使用全鏈路多版本環境時,不同環境訪問的域名都是同一個,使用者需要透過代理工具新增 Request headers,設定 tc_fd = 環境標識,這樣帶有標識的請求經過閘道器時,會根據配置的路由規則轉發到指定環境。這裡路由規則會由 CICD 平臺根據服務編排的組成,自動配置到 HTTP 閘道器、Dubbo、MQ 等中介軟體平臺上。
如下圖黃色箭頭所示,帶有 tc_fd = 1 標識的請求鏈路為 service_A_1->service_B_1->service_C->service_D_1。因為特性環境1中不存在 service_C,所以請求流量在 service_C 時回落到基線環境,往下呼叫時繼續路由到 service_D_1 服務,保證了環境的完整性。
想要達成全鏈路多版本流水線的快速部署,邏輯隔離等特性,需要 CICD 平臺把控多服務多版本的統一部署,環境治理和標籤管理,容器平臺保證業務的彈性伸縮能力,業務的流量灰度由 HTTP 閘道器和 Dubbo、訊息中介軟體路由策略實現,同時需要配置中心來管理所有服務的配置,以及最重要的底層鏈路追蹤和監控來實現完整的微服務架構。
為了實現全鏈路多版本部署方案,業務程式遵循微服架構,訪問時實現邏輯隔離、將系統的流量劃分為不同的通道或環境,每個環境都有其獨立的流量,避免它們相互影響是關鍵的一環。
想要達成全鏈路多版本流水線的快速部署,邏輯隔離等特性,技術上需要實現如下幾點:
-
流量染色
-
流量隔離
-
標籤傳遞
-
環境管理
2.2 流量染色
介面呼叫請求時,需要在鏈路中新增染色標識稱作流量染色。針對流量型別不同,服務呼叫方式不同,可以透過如下幾種方式進行染色。
2.2.1 客戶端 HTTP 服務呼叫
瀏覽器端或者 APP 端發起的 HTTP 請求,使用者可以透過本地安裝的代理工具攔截 HTTP 請求,再按規則配置注入 tc_fd 流量標識。
推薦的代理工具有Charles 和 Chrome 瀏覽器外掛 ModHeader。
2.2.2 服務端 HTTP 服務呼叫
如果是對外提供的 REST API 服務,服務呼叫方請求時不帶流量標識,可以在閘道器層按呼叫方配置“請求頭改寫”,實現全域性修改。
2.2.3 Dubbo 服務呼叫
本地服務除錯時,Dubbo 消費端可以在上下文中設定標籤RpcContext.getContext().setAttachment("Dubbo.tag","流量標識")。
針對整個消費端服務,也可以透過新增 JVM 引數 -Dvivotag = 流量標識進行全域性設定。
2.2.4 分散式任務呼叫
對應配置在“分散式任務排程平臺”基於給定的時間點,給定的時間間隔或者給定執行次數自動執行的任務,平臺側也已支援在排程策略上配置當前策略排程分組,以及是否需要呼叫時新增多版本流量標識。
2.3 流量隔離
上述介紹了幾種流量染色方式,當流量染色後,如何將帶有環境標識的流量轉發到對應的環境呢。我們目前針對 HTTP、Dubbo、MQ 等幾種常見流量型別實現了邏輯隔離方案,實現過程中主要考慮到如下幾點要素:
-
應用侵入性低,減少應用接入成本,由平臺自動配置和中介軟體框架實現隔離邏輯;
-
支援業務常見流量型別,覆蓋大部分業務邏輯;
-
流量隔離改造需考慮效能問題;
-
滿足特性環境任意擴充套件的需求,元件支援動態擴縮容。
2.3.1 HTTP 流量隔離
HTTP 流量隔離透過 VUA 閘道器配置實現,VUA(vivo unity access,公司流量統一接入層)是 vivo 統一接入層,基於 APISIX 的二次開發統一接入平臺。透過 VUA 中的 traffic-split 外掛可以透過配置 match 和 weighted_upstreams 屬性,從而動態地將部分流量引導至各種上游服務。
建立新的流水線後,CICD 釋出系統根據新增容器工作負載自動到 VUA 閘道器上建立 upstream,並且配置按環境標識配置 match 屬性,用於引導流量按自定義規則,常見支援的規則有判斷 HTTPHeader,pathParam,cookie 引數等。
2.3.2 Dubbo 流量隔離
Dubbo 提供了豐富的流量管控策略,透過基於路由規則的流量管控,可以對每次請求進行條件匹配,並將符合條件的請求路由到特定的地址子集。針對全鏈路多版本測試環境,我們採取動態配置標籤路由規則的方式進行打標,標籤主要是指對 Provider 端應用例項的分組,標籤路由透過將某一個服務的例項劃分到不同的分組,約束具有特定標籤的流量只能在指定分組中流轉,不同分組為不同的流量場景服務,從而實現流量隔離的目的。
具體做法為由 Dubbo 服務治理平臺提供標籤新增/刪除介面用於動態配置標籤路由規則,CICD 釋出系統在部署時透過容器 Init Container 特性在例項啟動前呼叫新增 tag 介面打標,完成標籤路由規則的自動配置。
2.3.3 MQ 訊息隔離
除了應用層 RPC(Remote Procedure Call,遠端過程呼叫)協議的流量隔離,大多數業務場景還會對訊息的全鏈路有一定的訴求。vivo 線上業務側訊息中介軟體自2022完成了從 RabbitMQ 到 RocketMQ 的平滑升級,目前業務現狀仍是使用了 RabbitMQ 的 SDK,由平臺側中介軟體團隊提供 mq-proxy 訊息閘道器元件負責 AMQP 協議與 RocketMQ 協議的相互轉換,此為我們公司特殊背景。實現訊息隔離的過程分生產者和消費者兩部分實現。
-
生產者在傳送訊息的時候,透過在 user-property 中加上一些欄位將環境標籤附帶在訊息體中,使得訊息傳送到 RocketMQ server 的時候就包含灰度資訊。
-
消費者客戶端 SDK 使用全鏈路 Agent 將版本標識新增到連線屬性當中,啟動時根據環境標識,由 mq-proxy 自動建立當前帶環境標籤的 group,並透過消費訂閱的訊息屬性過濾機制,從 topic 中過濾出來屬於自己版本的訊息。
2.4 標籤傳遞
以上大概介紹了我們支援的三種元件進行流量、訊息隔離的基本實現原理。在多版本環境中,真實的業務鏈路往往是使用者透過 HTTP 請求經過閘道器訪問到 service_A 服務,再由 service_A 服務透過 RPC 介面呼叫到 service_B 服務,service_B 服務生產訊息提供給 service_C 服務消費。整個呼叫過程中如果使用者發起請求時加上了 tc_fd 環境標籤,也就是流量被染色,請求頭中有特定標識之後,標籤需要在呼叫鏈路中傳遞下去叫做標籤傳遞。有了這個標識鏈路傳遞,我們再為鏈路上的所有應用定義流量隔離策略才會生效。
標籤傳遞功能借助分散式鏈路跟蹤系統實現,我司分散式鏈路跟蹤系統簡稱呼叫鏈,主要覆蓋開發語言為 Java。呼叫鏈的 Agent 模組透過位元組碼增強技術,使用 Java 探針做到了不侵入業務程式碼的前提下,對服務的類進行攔截,從而植入一些監控埋點上報或者其他程式碼。
應用到全鏈路多版本環境部署功能中來,就是在服務接收到請求時,從報文裡獲取到標籤資訊,向下遊服務發起新的服務請求時,再將獲取到的標籤資訊設定到指定引數位置。向下遊傳遞時幾種呼叫方式的標籤設定方式如下:
-
HTTP 請求,透傳引數以 key-value 形式附加在 HTTPRequest 的 headers 中,支援向上游回傳,回傳的引數存在於 HTTPResponse 的 headers 中;
-
Dubbo 呼叫,透傳引數以 key-value 形式附加在 RpcInvocation 的 attachments 中;
-
RMQ Procuder 傳送訊息時,透傳引數以 key-value 形式附加在訊息屬性 MessageProperties 的 header 中。
2.5 環境管理
相比之前使用流水線部署傳統測試環境,全鏈路多版本流水線在部署過程中賦予測試環境更多的配置屬性,在建立和使用測試環境上更加靈活多變。所以從 CICD 平臺建設上,我們需要儘可能的完善平臺自動化程度,抹平因為流水線差異導致使用者增加使用全鏈路多版本流水線的操作和理解成本。
2.5.1 基線環境
基線環境作為全鏈路多版本環境中最基礎的環境,是當請求連結不帶任何環境標籤時預設訪問到的環境,基線環境被其他特性環境共享,所以保障基線環境穩定性十分重要。我們在前期推廣全鏈路多版本流水線過程中,為了環境規範化部署,要求業務方接入時需要新建基線環境,且同一服務下基線環境存在唯一性。這樣做的好處是環境管理更加規範,壞處卻是提高了使用成本,一套服務全都新建基線環境佔用大量硬體和人力成本,與推廣全鏈路多版本流水線初衷不符。在吸收使用者意見及後續最佳化後,我們支援了在已有測試環境的基礎上進行基線環境改造,以支援其他特性環境的相容。為了管理基線環境,我們還採取以下措施:
-
統一環境配置:為了避免不同環境使用不同的基線環境配置,需要統一基線環境配置,以確保不同特性環境使用的基線環境一致。
-
定期更新和維護基線環境:為保證基線環境穩定,需要減少基線環境釋出頻率,保證部署程式碼分支質量穩定。按照專案管理特點,可以配置生產環境部署後觸發基線環境部署生產環境程式碼分支;
-
監控和報警:對基線環境進行監控,如 CPU、記憶體、磁碟等資源的使用情況,及時發現問題並進行處理。
2.5.2 特性環境
特性環境是指為了測試和驗證某個特性而建立的獨立環境,在測試環境場景中與版本屬性有關聯,每個特性環境有屬於自己的環境標籤屬性,具有快速建立和銷燬的特性。特性環境的管理也具備如下幾個方面的功能:
-
標籤管理:每個特性環境建立時會自動生成全域性唯一的環境標籤,或者指定已有的環境標籤。
-
快速建立:快速拉起一套新的特性環境,按既有服務流水線模板編排成多服務環境,實現一鍵執行構建部署所需的多個服務例項。
-
環境配置自動化:建立特性環境時,避免建立前申請容器資源,建立後配置路由規則等繁瑣操作,具體配置功能儘可能由平臺實現自動化。
-
定時銷燬:每個特性環境設定使用生命週期,到期不用後定時清理流水線和容器例項,避免冗餘環境長期不用佔用資源。
2.5.3 鏈路監控
現在大規模微服務分散式架構軟體模組的背景下,幫助理解系統行為、用於分析效能問題的工具分散式鏈路跟蹤系統應運而生。因為全鏈路多版本流水線特性環境流量隔離的特性,因為鏈路問題可能會導致服務呼叫串環境,鏈路監控功能就更為重要。目前關於鏈路監控的功能建設如下:
-
互動便捷:在流水線頁面遷入鏈路視覺化選單,並按環境標籤定位到當前環境資料。
-
呼叫拓撲圖:透過呼叫拓撲圖展示服務間的呼叫關係和資料流向,在鏈路後設資料中增加環境標籤資訊,在鏈路圖形化展示上標記環境資訊。
-
問題排查:HTTP 呼叫時透過呼叫鏈返回當前 traceId 到 ResponseHeader 上,更加方便使用者透過 traceId 直接定位到具體日誌。
三、未來與展望
CICD 部署平臺建設全鏈路多版本流水線初衷是為了實現降本增效,節約公司的硬體和環境運營成本,提升研發人員日常工作效率。在具體推廣全鏈路多版本流水線的過程中也遇到了一些問題,如重新搭建基線環境增加成本,已改為相容原有測試環境替代。當前全鏈路流水線建設還剛剛起步,未來還有更多空間值得最佳化:
-
支援更多元件和語言:目前流量隔離已支援了 RPC 層的 HTTP 和 Dubbo 流量,訊息中介軟體的 MQ 元件,對於其他 RPC 框架,訊息中介軟體元件,或涉及到非 Java 語言應用時,由於使用範圍不普遍,優先順序較低,目前還未支援。這項問題會根據公司業務發展和技術應用流行趨勢進行調整。
-
支援資料邏輯隔離:資料的底層儲存通常是 MySQL,Redis,MongoDB 等,因為業務場景複雜,資料隔離實現成本高,暫未實現邏輯隔離的功能。如業務有需求,通常建議準備多套資料庫使用物理隔離方案,在配置中心建立多套資料庫配置資訊方便切換。但是若想業務灰度使用更加絲滑,資料邏輯隔離還需要具備。
-
更多應用場景:目前全鏈路多服務流水線只應用在測試環境部署,如果業務使用流量染色的功能更加熟悉和穩定,未來此項特性線上上 A/B 測試等場景也可支援。