分布式系統測試在阿里云的實踐
分布式系統的測試是一個比較大的話題,在這里,我們僅用幾個阿里云飛天分布式系統測試中比較有特點的實踐方式來闡述一下我們對分布式系統測試的理解,希望對大家有所幫助。
1. 阿里云的分布式系統
飛天是阿里云獨立開發的大規模分布式計算與存儲系統,兼有分布式存儲和分布式計算的多重功能。基于飛天大規模分布式系統,我們開發了彈性計算,海量郵箱服務,Key-Value存儲引擎,結構化數據存儲引擎和海量數據處理服務等一系列的上層服務,并且基于這些上層服務,我們運營了了Open Table Service和Open Storage Service等多項開放服務。
2. 測試的層次結構
按照層次和功能,測試可以分為單元測試,功能測試,系統測試,集成測試,端到端測試等若干種測試。這里首先要提的是單元測試,單元測試更像是一種預防代碼錯誤的手段,而不是檢測代碼錯誤的手段,我們用覆蓋率(包括行覆蓋和分支覆蓋)來檢驗單元測試的質量。當然我們也都知道這些指標不能作為單元測試好壞的標準,所以,在項目中,我們也非常注重代碼審查,其中包括了單元測試代碼的審查。
傳統的一般來說,一個產品一般只有對外接口進行功能測試和系統測試,但是由于飛天的代碼非常的復雜,模塊非常多,每個模塊都具有了一個產品的復雜度。所以,我們在模塊層面也會進行功能測試和系統測試,為的是保證系統質量能夠得到回歸,在有代碼修改的時候,影響上層業務使用的接口或者隱含邏輯一旦發生變化,能夠第一時間知曉。功能測試非常注重對接口函數的覆蓋,并且會對各種參數的邊界進行復雜的探測,而系統測試比較注重穩定性,一致性,性能甚至容災能力等各個方面。
在飛天系統內部,有專門的集成測試部門,集成測試團隊有一個非常大的責任是通過回歸測試用例來保證系統中的各個模塊,在版本發布時在一起能夠很好的工作,并對之前每個模塊定下的質量驗收標準進行驗證。一旦發現重大風險,集成測試部門有權力不發布其中某些Feature,如果這個Feature有某種重要的商業用途,則進行推遲整體版本的發布。這一點可能和傳統軟件不太一樣。當分布式軟件已經比較成熟的時候,底層很多模塊的Feature在某個版本的刪減,大多數時候不會影響到用戶的正常使用,但是如果由于這個Feature的發布導致分布式系統出現不穩定或者性能大幅下降,則得不償失。
端到端測試在內部有個簡潔的名字叫做E2E Testing。E2E Testing的責任人需要負責向上層使用這個模塊或者系統的用戶方了解具體的需求,這個需求不僅是一個對接口功能的需求,還包含了數據量的需求,機器規模的需求,吞吐率的需求,延遲時間的需求以及業務量在一天或者一周內的曲線等等信息,然后設計E2E的測試程序,能夠盡可能的模擬真實的數據情況。在本身上層業務就已經有數據的情況下,還可以通過導入真實業務的數據進行測試。通過長時間的E2E測試,驗證各種指標。
一般來說,我們只有在通過了最后的E2E測試之后才能發布版本,上線讓應用使用我們的分布式系統。
3. 注重探索式測試
分布式系統的測試非常的復雜,你既無法通過窮舉來羅列所有的情況,也不能簡單的對接口和性能進行回歸來證明一個版本的合格。因為對于分布式系統,不同的數據量,不同的壓力,不同的機器規模,有可能在代碼里面走的路徑完全不一樣。而且,由于在大的壓力下,磁盤,內存和網絡有可能成為系統的瓶頸。更有甚者,在壓力不均勻的情況下,單臺機器可能會成為整個系統的瓶頸。所以,我們是沒有辦法設計這么多的測試用例來分別覆蓋所有的這些分支情況的。
我們有詳細的監控系統可以監控整個集群的各種參數,這些參數不光是硬件參數,更多的是軟件本身通過調用我們監控系統的API來完成對自身某些指標的統計。這些統計不光在線上系統能夠起到監控的作用,執行測試的人員可以通過不斷改變測試的各項參數,結合這些指標的變化進行探索式的測試。通常,通過指標在某些壓力變化下或者隨著時間推移時的異常行為,測試人員會更容易找到一些深藏的Bug。另外,在系統級測試時,通過對系統內部Error Log的監控也能達到很好的效果。
4. 灰盒測試是分布式測試的最有效方法
上面講到了探索式的測試十分重要,但是光有探索,如果測試人員本身不了解系統的一些內部邏輯,會出現兩種情況:第一種是,只驗證設計好的場景,其他一些異常的情況,自己無法解釋,但是本身又不是驗證標準,導致很多隱藏的問題最終在線上爆發;第二種是,一個沒頭的蒼蠅,漫無目的的進行探索,最終浪費了時間,卻達不到好的效果。在飛天分布式系統測試中,我們要求測試人員必須從方案設計之初甚至是討論需求的時候就和開發的同學在一起討論,測試的同學需要比開發更加理解系統的設計原則。
有一個很典型的例子是,早期,我們內部開發一個基于表結構的存儲引擎時,曾經出現過這樣一件事情:測試程序在最終驗證一致性時,一直都是通過的,但是業務方和我們一起做E2E測試的時候,會有很低的概率發現數據讀出來是錯誤的。測試人員百思不得其解,最后發現,這份數據在寫入的時候,會先在三個地方進行修改,但是由于一些時序和鎖的問題,在改過了兩個地方之后就返回成功了,第三個地方是在內存中,過一陣子就會被重新刷成正確的值。如果當時測試的同學知道系統里面這些設計,當時就會設計寫入過程中,對數據一致性的檢測,不會在用戶場景中再發現問題,解決的效率也會因此而提高。
5. 帶壓力和隨機故障模擬的長時間穩定性測試
分布式系統往往是在多臺機器上運行多個進程,每個進程都是一個獨立主體,運行著自己獨立的邏輯,各個進程都有可能因為軟硬件故障導致邏輯執行異常。分布式系統要保證的是任何局部的進程異常都不會影響系統的可用性,因此必須要做必要故障模擬和恢復測試。由于進程之間通訊協議的復雜,故障類型的多樣,并不能夠模擬所有可能出現故障和進程狀態的組合,也就是說這樣的組合是爆炸的。
在飛天實際的測試過程中,我們采用的是帶背景壓力和隨機故障模擬的長時間穩定性測試。這也是飛天主版本發布的最后一道關。背景壓力主要是各個主要模塊的讀寫壓力,還有一些諸如CPU,Memory,Network的資源消耗器,以模擬機器資源緊張場景。故障模擬操作又比如磁盤錯誤,包括壞盤,只讀等,機器宕機,重啟,斷網,主要模塊進程重啟,假死等,這些操作都會按照預先設定比例進行隨機組合;在這樣的背景壓力和故障操作下,長時間(至少7x24 小時)持續運行上層應用模擬程序/作業。同時通過在線監控工具來檢查系統是否正常。飛天很多重要的bug都是通過這個測試被發現的。當然這類測試也有短處,就是問題調查需要較長的時間,要求測試人員對系統有較深的了解和診斷能力。
6. 如何保障測試的質量
單元測試雖然可以用Coverage工具來檢驗行覆蓋和分支覆蓋,但是功能測試和系統測試在運行時,進程運行在上百上千臺機器上,很難通過既有的軟件來搜集到coverage數據。我們內部開發了一個叫做Log Coverage的工具,能夠通過程序在運行過程中輸出的Log信息的多少來判斷測試是否有足夠的覆蓋率。通過拿到生產線上的Log與測試中的Log進行比較,會找到我們之前沒有測試到的地方。另外,通過對程序中從來沒有打印出的Error Log的檢查,我們也可以知道有多少異常邏輯我們沒有測試過。