從零開始用golang編寫一個分佈式測試工具

起源

當開發http 接口的時候,每每咱們會關心開發的server能承受多少壓力,這時候一個比較經常使用的工具是 apache bench。一部分狀況下ab工具確實能知足需求,可是不少時候並不能,須要分佈式式測試工具。python

壓力測試比較關心的是產生壓力獲取測試對象的如TPS、響應時延等性能數據主機資源如cpu,memory消耗數據以定位性能瓶頸,簡單的單機測試工具並不能很好的知足這些需求。nginx

咱們能夠選擇雲平臺的分佈式測試工具,好比騰訊的wetest,阿里雲也有相似產品。可是這種產品每每收費不菲。也能夠選擇相似的開源產品,好比locust。可是調研發現,這種開源產品每每比較簡單,或者過於陳舊。google官網有一個壓力測試例子,用的就是locust。你們能夠看一下這個工具,基於python,功能很是簡陋,master,slave模式,不支持在線編輯腳本,修改測試要重啓。git

如何設計這樣的壓力測試工具

k8s是目前比較流行的容器編排系統,是否能夠在k8s上本身作一個分佈式測試工具呢。固然能夠用google推薦的作法,在k8s上運行master slave 模式的locust,又或者本身動手作一個。
既然運行在k8s上,那麼這個測試工具實際上關心的事就比較簡單了:k8s已經實現了調度,資源監控,咱們的工具只須要定義腳本,運行腳本,統計測試結果,收集測試過程的資源消耗。
須要說明的是,測試工具運行在k8s上只是爲了利用k8s的基礎設施,簡化工具設計,事實上測試的對象能夠是運行在k8s上或者在k8s外的任何服務。github

使用golang作測試腳本

選擇golang做爲測試腳本的緣由一是語言成熟,語法簡單,二是goroutine很方便,很容易把壓力打上去,三是即有編譯型語言的高性能,同時又像腳本同樣可以快速運行(編譯很快)。golang

golang自己是編譯型語言,不是腳本語言,運行要先編譯,可是由於編譯很快,實際上很容易當成一個腳原本執行,好比這個例子。或者顯式的運行go build,go run,像docker/distribution項目的dockerfile這樣。那麼要實現一個"動態"運行golang的工具要作的就是:定義一種類型的任務,用戶的測試腳本只要實現這種任務的interface,客戶端就能夠裝載這種腳本編譯運行。具體舉例以下。docker

// 1. 定義一個TTask做爲interface
type TTask interface {
    Name() string
    Run() int
}

// 2. 用戶的測試腳本實現這個interface
// New ....
func newhello() task.TTask {
    return &hellotask{}
}

type hellotask struct {
}

func (h *hellotask) Name() string {
    return "task"
}

func (h *hellotask) Run() int {
    time.Sleep(time.Microsecond * 10)
    return 0
}

// 3. 實現一種註冊式的插件機制,讓用戶的任務註冊進來
var tasksets = make(map[string]NewFunc, 0)
func Register(newfunc NewFunc) {
    t := newfunc()
    _, registered := tasksets[t.Name()]
    if registered {
        panic(fmt.Sprintf("TTask named %s already registered", t.Name()))
    }
    tasksets[t.Name()] = newfunc
}

// 用戶腳本中要註冊他的腳本
Register(task.NewFunc(newhello))

// 4. 測試客戶端不關心用戶腳本的實現細節,運行tasksets裏面TTask就能夠了
func main() {
    for _, f := range tasksets {
        f().Run()
        ...
    }
}複製代碼

一個更復雜一點的例子在這裏apache

使用k8s的基礎設施

首先實現測試任務,使用job是很合適不過的,設置parallelism併發運行。bash

其次要實現任務的動態添加和掛載,可使用k8s的configmap來實現。使用configmap來保存用戶的腳本,運行agent的時候將腳本自動掛載到agent的容器對應路徑,容器啓動腳本中加入build流程,這樣就能很方便的實現一種"動態"的運行golang腳本的效果了。併發

當壓力測試使用多個節點的時候,咱們每每須要同時觀測測試客戶端和服務端的cpu等資源監控,由於客戶端已經自然的運行在k8s上了,能夠直接使用k8s的監控設施。
另外測試工具的設計並無侷限在測試運行在k8s上的server,可是若是恰好,被測試的對象也運行在k8s上,那麼也能夠很方便的或者server的宿主機metrics,若是不是,那麼server端就須要裝一個收集metric的deamon實現一樣的效果了。分佈式

效果

dashboard支持查看測試任務,每一個任務有一個最近運行的記錄和建立時間。

編輯一個測試項目,測試腳本是用golang編輯的,須要實現一個TTaskSet 的interface。支持設置任務的goroutine和運行時間,權重,設置權重以後goroutine數量會在多個taskset之間分配,一個taskset又能夠添加多個task。taskset併發運行,一個taskset中的task串行運行,這樣設計的好處是能夠知足用戶併發,串行,帶context的串行多種需求,很是靈活。任務能夠選擇運行的節點,多個節點併發測試。

運行完測試的效果,目前尚未加入測試中的client,server資源監控,可是簡單的測試統計已經有了。如圖是測試的一個運行在1G虛擬機的nginx容器的測試結果。測試結果同時有各個節點的運行結果和彙總結果,同時繪製latency的百分位圖。


完整項目地址在 github.com/arlert/ymir 歡迎拍磚。

相關文章
相關標籤/搜索