原創:張少華
背景
隨著自動化測試用例的增長,模塊持續集成中的驗證環節時間也隨之增長。如果使用單臺機器,可能需要幾個小時的時間才能完成一次所有用例的運行。這裡我們能想到的最直接的方法,就是增加機器資源,並行運行測試用例。我們首先使用的方法是,在jenkins中將運行時間長的模塊的功能測試job,拆分為多個可並行執行的job。但即使我們封裝了許多jenkins相關的操作方法,可以使用腳本快速生成一系列job,但是依然存在以下問題:
增減機器成本太高,需調整整個jenkins的任務。並行job運行時間不固定,瓶頸為最慢的job運行的時間。穩定性問題,並行執行機器任何一臺出現問題,都會影響整體任務。
建設目標
為了解決上面的問題,當時我們期望的測試系統有以下要求:
穩定性高,比如某個機器出現問題不會影響整體任務:穩定是重中之重。分布式執行,同一job的多臺機器可並行執行,同時,多個模塊之間也可以並行執行測試任務:充分利用機器資源,提升自動化測試效率。配置方便,機器資源池維護簡單:可以節省維護的人力,將時間用於更有意義的事情上。結果報告清晰,排查問題方便:錯誤case日誌、環境等信息及時保存。我們並沒有使用一些開源的分布式框架,因為我們的需求相對來說比較簡單,而且有一些定製化的需求,同時希望之後測試同學們可以在此之上做二次開發,所以最終我們決定自己實現這一系統。
具體實現
總體設計
整個系統主要分為三個角色模塊:客戶端、控制中心(Master)及worker端,其中client端在。
對於一個Jenkins job觸發的分布式任務,主要步驟有:
Jenkins job調用客戶端發送請求到控制中心,傳遞job相關信息,請求創建任務。控制中心(Master)根據請求信息創建任務,篩選case創建task列表(每一個case對應一個task,可分布式執行),分配worker。Jenkins客戶端請求控制中心查詢任務狀態接口,列印當前狀態。Worker端請求控制中心獲取可執行的命令,做出相應的拉取代碼、準備環境、執行單個case task、清理環境等命令。所有task執行完後,jenkins客戶端獲取任務結果,退出任務。詳細的交互過程如下如所示:
如何實現並行執行?
由於我們的case在單臺機器上不能並行執行,所以我們所說的並行是指多臺機器同時執行case;在創建任務的時候,會篩選出所需執行的case,每個case將會對應創建一個task並加入task隊列;worker請求命令時,會從task隊列中挑選合適的task進行分配(case的運行時間長的優先級高,避免出現最後等待case運行結束時間長的情況發生)。
控制中心(Master)
控制中心包括server和後臺數據兩部分,後臺資料庫存儲job信息、case信息、worker信息(資源池)、result信息、配置信息等。Server提供接口供客戶端及worker端訪問,分步執行的控制邏輯都在控制中心實現。
由於控制中心沒有頁面,所以控制中心提供了一系列接口供其他模塊使用:
客戶端
客戶端,即jenkins job中運行的腳本,每一個jenkins job對應著一個分布式的任務。
首先需要創建任務,請求/job/create接口的時候,我們會把從jenkins job的環境變量中獲取的一些信息發送給Master,如jenkins job的名稱,BUILD_NUM,以及最為重要的模塊信息及代碼倉庫、分支信息。
然後,會使用/job/status循環查詢任務的狀態,實時列印在控制臺輸出裡。
最後,根據任務運行狀況返回結果。
worker端
worker端,即實際case運行所在的機器,每個worker都是獨立的,互不影響。通過控制中心接口不停詢問自己應該執行什麼操作。
首先在worker端我們添加了一個系統服務,守護進程持續執行中。
然後,worker在空閒狀態的時候,會根據接口/worker_get_command循環請求控制中心,如果有命令的話,就會去執行,執行完後,將執行產生的結果、日誌文件上傳到日誌平臺;同時調用/result_update接口,把命令的運行結果傳遞到控制中心。
收益與問題
系統上線後,完美取代了我們之前手動jenkins分組執行自動化測試的方法,首先從服務的健壯性性及正確性來說,很少會出現因為測試環境或是工具出問題而影響整個測試任務的情況,讓開發和測試同學將精力聚焦於case反映出的業務代碼問題上;其次,配置簡單,大大節省了維護時間;最後,由於worker資源池擴充方便,大大發揮了並行的作用,使整個測試任務效率有了很大的提升。
當然,還是存在著進一步優化的空間,比如現在的機器資源是在創建任務時分配好的,可以優化為在整個任務過程中動態調整,充分利用機器資源等。