docker && k8s 分散式壓測 locust_boomer 方案

少年發表於2020-07-20

前言

為什麼要做這樣的一個方案

很多時候,我們對外暴露的 API 很少,如果僅僅對暴露的 API 做壓測,不能夠達到想要的壓測結果,或者是對外暴露的 API 做了限流的限制,會將壓力擋在外面。像 docker & k8s 有很多定製開發的內容服務或元件,只能在內部訪問,無法對外暴露(應該是對外暴露不安全,不能暴露),所以希望壓測能夠作為 k8s 的一個內部元件,對其他可通訊的內部元件,進行壓力測試。

這裡採用 docker-compose 的方式來編排容器,k8s 的 demo 後續會更新。

為什麼不用 Locust

先簡單說下什麼是 Locust,主要是基於 python 的 gevent 實現的偽併發來產生壓力。實現方式比較多樣,可以手寫程式設計函式,豐富可測試的範圍,並配置併發佔比,模擬真實使用者。

from locust import HttpUser, task, between

class MyUser(HttpUser):
wait_time = between(5, 15)

@task(2)
def index(self):
self.client.get("/")

@task(1)
def about(self):
self.client.get("/about/")

這個是一個簡單的 demo,展示的是使用者會隨機等待 5-15s 發起請求,併發策略是三分之一的併發量請求 /,三分之二的併發量請求 /about。測試很有場景性,而且可以將壓測作為一個函式來程式設計,可以根據專案來進行改造適配,通用測試很多系統。

當然,受限於 python 語言本身 GIL 鎖的限制,高併發下很不穩定,給的壓力也一言難盡。所以不用 Locust,顯然易見。

當然如果不需要很高壓力的情況下,是可以考慮使用 Locust 的,因為提供的場景很豐富。而且 Locust 支援分散式,一個 4 核 CPU 的伺服器,可以設定 1 個 master 和 3 個 slave 來產生壓力,進一步提高效能。

為什麼用 Boomer

Boomer 其實還是 Locust,只是在 Locust 的基礎上,進一步提升了可產生的壓力。上面提到,Locust 開啟分散式的時候,會產生 1 個 master (python) 和 3 個 slave (python),而 Boomer 開啟分散式的使用,會產生 1 個 master (python) 和 3 個 slave (go),也就是還是有 locust-python-master 來作為管理中心,但是實際執行的 locust-python-slave 變成了 boomer-go-slave。

這樣做的變化:

  1. 原來的併發基於 python 的 gevent 進行實現,現在是用 goroutine 的方式,進一步提高了併發的方式。
  2. 原來 Locust 併發的是使用者這個概念,Boomer 裡面沒有使用者的概念,併發的是函式。

Locust & Boomer 缺點

壓測資料展示用的是 Locust 建議的 web 介面,資料不能儲存,重新整理就沒有了。

這點好辦,可以改造一下,新增 promethues 作為資料庫來上報資料,用 grafana 來展示,已經有實現方案了,在 Boomer 專案裡面,使用 prometheus_exporter.py 啟動 locust-master。

locust --master -f prometheus_exporter.py

專案

專案 demo:shaonian/boomer-locust 歡迎來 star ~

原理:把壓測也作為 k8s 內部的一個元件提供服務,那麼對內訪問的通道就被開啟了,這樣我們就可以直接在叢集的內部產生我們想要的壓力了。

demo 分析

如上圖所示,flask-demo 是一個簡易的伺服器,我已經取消了對外暴露的訪問,只有在叢集內部才能訪問到,於此同時,locust-master & locust-slave 也作為一個容器服務,同在一個叢集網路中。locust-master & locust-slave & flask-demo 的映象均已打包好, docker-compose.yml 詳情如下:

version: '2'
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/data:/root/prometheus/prometheus-data
links:
- locust-master
ports:
- "9090:9090"

grafana:
image: grafana/grafana
volumes:
- ./grafana/data:/var/lib/grafana
links:
- prometheus
ports:
- "3000:3000"

flask-demo:
image: shaonian/flask-demo:latest

locust-master:
image: shaonian/locust-master:latest
ports:
- "8089:8089"

locust-slave1:
image: shaonian/locust-slave:latest
command:
- ./flask
- --master-host
- locust-master
links:
- locust-master
- flask-demo

# locust-slave2:
# image: shaonian/locust-slave:latest
# command:
# - ./flask
# - --master-host
# - locust-master
# links:
# - locust-master
# - flask-demo

locust-master 啟動以後開始監聽有沒有 slave 連上。

locust-slave 啟動以後開始根據指定的 master-host 進行連線。

此時 locust-master & locust-slave 已經建立了通訊。

現在我們來對內部網路的 http://flask-demo:5000/ & http://flask-demo:5000/text 這個兩個路由進行 1:3 比重的壓測訪問。這裡的 host 不再是傳統的 URL,而是一個容器服務的名字。

此時檢視 flask-demo 的容器日誌,發現壓力已經正常產生。

此時原生 locust 圖表展示如下:

兩個路由的比重滿足 1:3 的條件。

此時 grafana & promethues 的擴充套件圖表展示如下:

此時,各元件間通訊建立成功,叢集內部壓力產生成功,壓力圖表擴充套件成功。

相關文章