天天看點

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

作者:林帆(花名金戟),阿裡雲雲效效能洞察産品進階技術專家

前言

阿裡的許多實踐看似簡單,背後卻蘊涵着許多思考,譬如測試環境的管理。

網際網路産品的服務通常是由Web應用、中間件、資料庫和許多背景業務程式組成的,一套運作環境就是一個自成一體的小生态。最基本的運作環境是線上環境,部署産品的正式釋出版本,為使用者提供持續可靠的服務。

除此以外,還有許多不對外部使用者開放的運作環境,用于産品團隊日常的開發和驗證,統稱為測試環境。正式環境的穩定性,除去軟體自身的品質因素,主要與運作的主機、網絡等基礎設施相關,而測試環境的穩定性則更多受到人為因素影響。由于頻繁的版本變更,以及部署未經充分驗證的代碼,測試環境出故障的情況屢見不鮮。

良好的代碼送出習慣、适當的變更前檢查有助于減少故障的發生,但無法徹底杜絕後患。增加多套測試環境副本能夠有效控制故障的影響範圍,然而企業的資源終歸有限,降低測試環境成本和提高測試環境穩定性成為了沖突的兩面。

在這個領域裡,獨具匠心的阿裡研發效能團隊設計了一種服務級複用的虛拟化技術,稱為“特性環境”,其巧妙的思路令人贊歎。本文将圍繞測試環境管理的話題,聊聊這種具有阿裡特色的工作方式。

測試環境管理的困局

測試環境的用途很廣泛,常見的測試環境譬如系統內建測試環境、使用者驗收測試環境、預釋出測試環境、灰階測試環境等,它們展現了産品的傳遞生命周期,也間接反映出整個團隊的組織結構。

小作坊型産品團隊的測試環境管理起來十分簡單,每個工程師本地就能啟動全套軟體元件進行調試,倘若不放心,再加上一個公共的內建測試環境也就足夠。

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

随着産品規模擴大,本地啟動所有服務元件逐漸變得既費時又費事,工程師們隻能在本地運作一部分待調試的元件,然後利用公共測試環境上的其餘元件組成完整系統。

與此同時,團隊規模的擴張,使得每個團隊成員的職責進一步細分,新的子團隊被劃分出來,這意味着項目的溝通成本增加,公共測試環境的穩定性開始變得難以控制。在這個過程中,測試環境管理複雜性帶來的影響,不僅展現在服務聯調變得繁瑣,更直接反映在傳遞流程和資源成本的變化上。

在傳遞流程方面,一個顯著的變化是測試環境種類增多。出于不同的用途和目的,工程師們設計出了各式各樣的專用測試環境。這些測試環境的組合形成了各個企業獨具特色的傳遞流程。下圖展示了一種用于大型項目的複雜傳遞流程。

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

從單獨服務的角度來看,環境與環境之間是由流水線相連的,再加上自動化測試或手工審批操作組成關卡,實作環境之間的傳遞。通常越進階别環境的部署頻率越低,是以相對穩定性也越高。與之相反,在級别較低的環境上,就随時可能存在新的部署,會打擾正在使用該環境的其他人。有時為了複現某些特殊的問題場景,一些開發者不得不直接登入到伺服器上面去“搞事情”,進一步影響環境的穩定性和可用性。

面對随時可能崩潰的測試環境,小企業會試着去“堵”:限制服務變更時間、設立嚴格的變更規範,大企業則善于用“疏”:增加測試環境副本,隔離故障影響範圍。顯然,不堪重負的測試環境一定越“堵”越“漏”,千年以前大禹治水的故事早就揭示了的道理,刻意的管控拯救不了脆弱的測試環境。

近年來,DevOps文化的興起,端到端解放了開發者的雙手,這對于測試環境的管理而言卻是一把雙刃劍。一方面,DevOps鼓勵開發人員參與運維,了解産品的完整生命周期,有助于減少不必要的低級運維事故;另一方面,DevOps讓更多的手伸向測試環境,更多的變更、更多的Hotfix出現了。這些實踐從全局來看利大于弊,然而并不能緩解測試環境的動蕩。單純的流程疏通同樣拯救不了脆弱的測試環境。

那麼該投入的還得投入。将不同團隊所用的低級别測試環境各自獨立,此時每個團隊看到的都是線性流水線,從整體上觀察,則會程現出河流彙聚的形狀。

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

由此推廣,理想情況下,每位開發者都應該得到獨占且穩定的測試環境,各自不受幹擾的完成工作。然而由于成本因素,現實中在團隊内往往隻能共享有限的測試資源,不同成員在測試環境互相幹擾成為影響軟體開發品質的隐患。增加測試環境副本數本質上是一種提高成本換取效率的方法,然而許多試圖在成本和效率之間尋找最優平衡的探索者們,似乎都在同一條不歸路上越行越遠。

由于客觀的規模和體量,上述這些測試環境管理的麻煩事兒,阿裡的産品團隊都無法幸免。

首先是測試環境種類的管理。

在阿裡内部,同樣有十分豐富的測試環境區分。各種測試環境的命名與其作用息息相關,雖然業界有些常用的名稱,但都未形成權威的标準。實際上,環境的名稱隻是一種形式,關鍵還在于各種測試環境應當分别适配于特定應用場景,且場景之間應當或多或少存在一些差異。

這種差異有些在于運作的服務種類,譬如性能測試環境很可能隻需要運作與壓力測試相關的那部分通路量最大的關鍵業務服務,其他服務運作了也是浪費資源。有些差異在于接入資料的來源,譬如開發自測的環境的資料源與正式環境肯定不一樣,這樣測試使用的假資料就不會污染線上使用者的請求;預釋出環境(或使用者驗收測試環境)會用與正式環境一緻的資料源(或正式資料源的拷貝),以便反映新功能在真實資料上運作的情況;自動化測試相關的環境會有單獨的一套測試資料庫,以避測試運作過程中受到其他人為操作的幹擾。

還有些差異在于使用者的不同,譬如灰階和預釋出環境都使用正式的資料源,但灰階環境的使用者是一小撮真實的外部使用者,而預釋出環境的使用者都是内部人員。總之,沒必要為一個不存在業務特殊性的測試場景專門發明一種測試環境。

在集團層面,阿裡對流水線形式的限制相對寬松。客觀的講,隻有在一線的開發團隊知道最适合團隊的傳遞流程應該是什麼樣子。阿裡的開發平台隻是規範了一些推薦的流水線模闆,開發者可在此基礎上進行發揮。列舉幾個典型的模闆例子:

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

這裡出現了幾種外界不太常見的環境類型名稱,稍後會詳細介紹。

其次是測試環境成本的管理。

成本管理的問題十分棘手且十分值得深究。與測試環境相關的成本主要包括管理環境所需的“人工成本”和購買基礎設施所需的“資産成本”。通過自動化以及自服務化的工具可以有效降低人工相關的成本,自動化又是個很大的話題,宜另起一篇文章讨論,此處暫且收住。

資産購買成本的降低依賴技術的改良和進步(排除規模化采購帶來的價格變化因素),而基礎設施技術的發展史包括兩大領域:硬體和軟體。硬體發展帶來的成本大幅下降,通常來自于新的材料、新的生産工藝、以及新的硬體設計思路;軟體發展帶來的基礎設施成本大幅下降,目前看來,大多來自于虛拟化(即資源隔離複用)技術的突破。

最早的虛拟化技術是虛拟機,早在20世紀50年代,IBM就開始利用這種硬體級的虛拟化方法獲得成倍的資源使用率提升。虛拟機上的不同隔離環境之間各自運作完整作業系統,具有很好的隔離性,通用性強,但對于運作業務服務的場景,顯得略為笨重。2000年後,KVM、XEN等開源項目使得硬體級虛拟化廣泛普及。

與此同時,另一種更輕量的虛拟化技術出現了,以OpenVZ、LXC為代表的早期容器技術,實作了建立于作業系統核心之上的運作環境虛拟化,減少了獨立作業系統的資源消耗,以犧牲一定隔離性為代價,獲得更高的資源使用率。

之後誕生的Docker以其鏡像封裝和單程序容器的理念,将這種核心級虛拟化技術推上百萬人追捧的高度。阿裡緊随技術前進的步伐,早早的就用上了虛拟機和容器,在2017年雙十一時,線上業務服務的容器化比例已經達到100%。然而,接下來的挑戰是,基礎設施資源使用率還能做得更高嗎?

甩掉了虛拟機的硬體指令轉換和作業系統開銷,運作在容器中的程式與普通程式之間隻有一層薄薄的核心Namespace隔離,完全沒有運作時性能損耗,虛拟化在這個方向上似乎已經發展到了極限。唯一的可能是,抛開通用場景,專注到測試環境管理的特定場景上,繼續尋找突破。終于,阿裡在這個領域裡發現了新的寶藏:服務級虛拟化。

所謂服務級虛拟化,本質上是基于消息路由的控制,實作叢集中部分服務的複用。在服務級虛拟化方式下,許多外表龐大的獨立測試環境實際隻需要消耗極小的額外基礎設施資源,即使給每個開發者配備一套專用的測試環境叢集都不再是吹牛。

具體來說,在阿裡的傳遞流程上,包含兩種特殊類型的測試環境:“公共基礎環境”和“特性環境”,它們形成了具有阿裡特色的測試環境使用方法。公共基礎環境是一個全套的服務運作環境,它通常運作一個相對穩定的服務版本,也有些團隊将始終部署各服務的最新版本的低級别環境(稱為“日常環境”)作為公共基礎環境。

特性環境是這套方法中最有意思的地方,它是虛拟的環境。從表面上看,每個特性環境都是一套獨立完整的測試環境,由一系列服務組成叢集,而實際上,除了個别目前使用者想要測試的服務,其餘服務都是通過路由系統和消息中間件虛拟出來的,指向公共基礎環境的相應服務。由于在阿裡通常的開發流程中,開發任務需要經過特性分支、釋出分支和諸多相關環節最後釋出上線,大多數環境都從釋出分支部署,唯獨這種開發者自用的虛拟環境部署來自代碼特性分支的版本,故可稱為“特性環境”(阿裡内部叫“項目環境”)。

舉個具體例子,某交易系統的完整部署需要由鑒權服務、交易服務、訂單服務、結算服務等十幾種小系統以及相應的資料庫、緩存池、消息中間件等組成,那麼它的公共基礎環境就是這樣一套具備所有服務和周邊元件的完整環境。假設此時有兩套特性環境在運作,一套隻啟動了交易服務,另一套啟動了交易服務、訂單服務和結算服務。對于第一套特性環境的使用者而言,雖然除交易服務外的所有服務實際上都由公共基礎環境代理,但在使用時就像是自己獨占一整套完整環境:可以随意部署和更新環境中交易服務的版本,并對它進行調試,不用擔心會影響其他使用者。對于第二套特性環境的使用者,則可以對部署在該環境中的三個服務進行聯調和驗證,倘若在場景中使用到了鑒權服務,則由公共基礎環境的鑒權服務來響應。

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

咋看起來,這不就是動态修改域名對應的路由位址、或者消息主題對應的投遞位址麼?實事并沒那麼簡單,因為不能為了某個特性環境而修改公共基礎環境的路由,是以單靠正統路由機制隻能實作單向目标控制,即特性環境裡的服務主動發起調用能夠正确路由,若請求的發起方在公共基礎環境上,就無法知道該将請求發給哪個特性環境了。對于HTTP類型的請求甚至很難處理回調的情況,當處于公共基礎環境的服務進行回調時,域名解析會将目标指向公共基礎環境上的同名服務。

在阿裡,我們如何管理測試環境前言測試環境管理的困局小結推薦效能工具:相關閱讀:

如何才能實作資料雙向的正确路由和投遞呢?不妨先回到這個問題的本質上來:請求應該進入哪個特性環境,是與請求的發起人相關的。是以實作雙向綁定的關鍵在于,識别請求發起人所處的特性環境和進行端到端的路由控制。這個過程與“灰階釋出”很有幾分相似,可采用類似的思路解決。

得益于阿裡在中間件領域的技術積累,和鷹眼等路由追蹤工具的廣泛使用,識别請求發起人和追溯回調鍊路都不算難事。如此一來,路由控制也就水到渠成了。當使用特性環境時,使用者需要“加入”到該環境,這個操作會将使用者辨別(如IP位址或使用者ID)與指定的特性環境關聯起來,每個使用者隻能同時屬于一個特性環境。當資料請求經過路由中間件(消息隊列、消息網關、HTTP網關等),一旦識别到請求的發起人目前處在特性環境中,就會嘗試把請求路由給該環境中的服務,若該環境沒有與目标一緻的服務,才路由或投遞到公共基礎環境上。

特性環境并不是孤立存在的,它可以建立在容器技術之上,進而獲得更大的靈活性。正如将容器建立在虛拟機之上得到基礎設施擷取的便利性一樣,在特性環境中,通過容器快速而動态的部署服務,意味着使用者可以随時向特性環境中增加一個需要修改或調試的服務,也可以将環境中的某個服務随時銷毀,讓公共基礎環境的自動接替它。

還有一個問題是服務叢集調試。

配合AoneFlow的特性分支工作方式,倘若将幾個服務的不同特性分支部署到同一個特性環境,就可以進行多特性的即時聯調,進而将特性環境用于內建測試。不過,即使特性環境的建立成本很低,畢竟服務是部署在測試叢集上的。這意味着每次修改代碼都需要等待流水線的建構和部署,節約了空間開銷,卻沒有縮短時間開銷。

為了進一步的降低成本、提高效率,阿裡團隊又搗鼓出了一種開腦洞的玩法:将本地開發機加入特性環境。在集團内部,由于開發機和測試環境都使用内網IP位址,稍加變通其實不難将特定的測試環境請求直接路由到開發機。這意味着,在特性環境的使用者即使通路一個實際來自公共基礎環境的服務,在後續處理鍊路上的一部分服務也可以來自特性環境,甚至來自本地環境。現在,調試叢集中的服務變得非常簡單,再也不用等待漫長的流水線建構,就像整個測試環境都運作在本地一樣。

DIY體驗特性環境

覺得服務級虛拟化太小衆,離普通開發者很遠?實事并非如此,我們現在就可以動手DIY個體驗版的特性環境來玩。

阿裡的特性環境實作了包括HTTP調用、RPC調用、消息隊列、消息通知等各類常用服務通信方式的雙向路由服務級虛拟化。要完成這樣的功能齊全的測試環境有點費勁,從通用性角度考慮,咱不妨從最符合大衆口味的HTTP協定開始,做個支援單向路由的簡易款。

為了便于管理環境,最好得有一個能跑容器的叢集,在開源社群裡,功能齊全的Kubernetes是個不錯的選擇。在Kubernetes中有些與路由控制有關的概念,它們都以資源對象的形式展現給使用者。

簡單介紹一下,Namespace對象能隔離服務的路由域(與容器隔離使用的核心Namespace不是一個東西,勿混淆),Service對象用來指定服務的路由目标和名稱,Deployment對象對應真實部署的服務。類型是ClusterIP(以及NodePort和LoadBalancer類型,暫且忽略它們)的Service對象可路由相同Namespace内的一個真實服務,類型是ExternalName的Service對象則可作為外部服務在目前Namespace的路由代理。這些資源對象的管理都可以使用YAML格式的檔案來描述,大緻了解完這些,就可以開始動工了。

基礎設施和Kubernetes叢集搭建的過程略過,下面直接進正題。先得準備路由兜底的公共基礎環境,這是一個全量測試環境,包括被測系統裡的所有服務和其他基礎設施。暫不考慮對外通路,公共基礎環境中的所有服務相應的Service對象都可以使用ClusterIP類型,假設它們對應的Namespace名稱為pub-base-env。這樣一來,Kubernetes會為此環境中的每個服務自動賦予Namespace内可用的域名“服務名.svc.cluster”和叢集全局域名“服務名.pub-base-env.svc.cluster”。有了兜底的保障後,就可以開始建立特性環境了,最簡單的特性環境可以隻包含一個真實服務(例如trade-service),其餘服務全部用ExternalName類型的Service對象代理到公共基礎環境上。假設它使用名稱為feature-env-1的Namespace,其描述的YAML如下(省略了非關鍵字段的資訊):

kind: Namespace

metadata:

name: feature-env-1

kind: Service

name: trade-service

namespace: feature-env-1

spec:

type: ClusterIP

...

kind: Deployment

name: order-service

type: ExternalName

externalName: order-service.pub-base-env.svc.cluster

注意其中的order-service服務,它在目前特性環境Namespace中可以使用局部域名order-service.svc.cluster通路,請求會路由到它配置的全局域名order-service.pub-base-env.svc.cluster,即公共基礎環境的同名服務上處理。處于該Namespace中的其它服務感覺不到這個差異,而是會覺得這個Namespace中部署了所有相關的服務。

若在特性的開發過程中,開發者對order-service服務也進行了修改,此時應該将修改過的服務版本添加到環境裡來。隻需修改order-service的Service對象屬性(使用Kubernetes的patch操作),将其改為ClusterIP類型,同時在目前Namespace中建立一個Deployment對象與之關聯即可。

由于修改Service對象隻對相應Namespace(即相應的特性環境)内的服務有效,無法影響從公共基礎環境回調的請求,是以路由是單向的。在這種情況下,特性環境中必須包含待測調用鍊路的入口服務和包含回調操作的服務。例如待測的特性是由界面操作發起的,提供使用者界面的服務就是入口服務。即使該服務沒有修改,也應該在特性環境中部署它的主線版本。

通過這種機制也不難實作把叢集服務局部替換成本地服務進行調試開發的功能,倘若叢集和本地主機都在内網,将ExternalName類型的Service對象指向本地的IP位址和服務端口就可以了。否則需要為本地服務增加公網路由,通過動态域名解析來實作。

與此同時,雲效也正在逐漸完善基于Kubernetes的特性環境解決方案,屆時将會提供更加全面的路由隔離支援。值得一提的是,由于公有雲的特殊性,在聯調時将本地主機加入雲上叢集是個必須克服的難題。為此雲效實作了通過隧道網絡+kube-proxy自身路由能力,将本地區域網路主機(無需公網IP位址)加入到不在同一内網Kubernetes叢集進行聯調的方式。其中的技術細節也将在近期的雲效公衆号向大家揭曉,敬請留意。

小結

當許多人還在等待,在虛拟機和容器之後,下一輪虛拟化技術的風口何時到來的時候,阿裡已經給出了一種答案。創業者的心态讓阿裡人懂得,能省必須省。其實,限制創新的往往不是技術而是想象力,服務級虛拟化的理念突破了人們對環境副本的傳統認知,以獨特的角度化解了測試環境成本與穩定性的沖突。

作為一種頗具特色的技術載體,特性環境的價值不僅僅在于輕量的測試環境管理體驗,更在于為每位開發人員帶來流暢的工作方式,實則是“簡約而不簡單”。

實踐出真知,阿裡巴巴雲效平台緻力于解決大型項目協作、靈活高速疊代、海量代碼托管、高效測試工具、分布式秒級建構、大規模叢集部署釋出等世界級業務和技術難題,為阿裡巴巴集團内部、生态夥伴以及雲上開發者服務。誠摯歡迎業界同行與我們探讨交流。

推薦效能工具:

雲效·Insight(效能洞察)是基于阿裡巴巴多年研發效能實踐,最終向外輸出,提供面向企業研發管理層的研發效能數字化度量服務。通過對研發過程資料的分析和提煉,雲效Insight 提供了針對項目、跨項目、跨代碼庫、以及組織人員度量能力,通過研發過程可視化為效能優化提供可靠依據。直覺地反映企業的整體研發進展情況,最大化發揮團隊作戰優勢。

立即體驗

相關閱讀:

在阿裡,我們如何管理代碼分支 當kubernetes應用遇到阿裡分批釋出模式 點此

了解雲效測試平台