讓開發人員如沐春風的壓力測試工具 - K6
4 |
前兩篇 JMeter 負載測試練習文章(1 2)分享後,FB 留言一面倒大推另一個壓測工具 - K6。身為沙場老兵,心中響起警鈴,提醒我耳朵別太硬;事出必有原因,讀者的話要聽,即便不用也看過再決定。
所以,K6 體驗文來惹~
與老牌工具 JMeter 相比,K6 比較年輕(2017 vs 2007),架構與設計現代化許多,採用 Go + JavaScript,聽起來就比 Java 年輕有活力。K6 沒有如 JMeter 的華麗友善 GUI,測試細節全靠指令參數與程式碼決定,但這正中程式開發人員下懷,CLI、敲指令才是王道呀! 誰需要 GUI 那種麻瓜介面? 我第二篇 JMeter 文章最後也走上 CLI 這條路,也算印證。
K6 核心以 Go 開發,不用擔心程式效能(依文件說明,K6 靠單一主機便可產生每秒 30 萬次請求);測試程式則採用 ES6 / JavaScript 語言,讓前端/全端工程師備感親切,進階應用需要對 Module、webpack 有點概念,但單純測試一個 .js 就能搞定,不難上手。官方文件整理得頗詳細,建議花點時間約略讀過再上路,許多東西文件都有寫到,不要瞎查資料胡亂嘗試浪費時間。(此乃親身經驗,良心建議)
2023-04-11 補充:推薦工程良田小球場的投影片 - twMVC#44 讓我們用 k6 來進行壓測吧,整理得很精簡完整。
先釐清一點,雖然口語上我們很習慣說「壓力測試」或「壓測」,實際上這些相關測試可再細分成:
(參考:An Introduction to k6: An API Load-Testing Tool、K6 基本介紹、安裝及實作,輕鬆上手!)
- Smoke Testing 煙霧測試 - 驗證系統在低硬體配備、正常負載下不會出錯
- Load Testing 負載測試 - 取得在一般及尖峰負載下的系統效能數字(用戶數、Throughput)
- Stress Testing 壓力測試 - 測試在高度負載或極端條件下系統的穩定性及可靠度,找出系統極限
- Spike Testing 尖峰測試 - 故意製造瞬間流量驟升取得系統效能數字
- Soak Testing 浸泡測試 - 測試系統在長期運作下的穩定性及可靠度
依此定義,前兩篇 JMeter 練習應屬負載測試而非壓力測試。不過,「壓力測試」是比較通俗常用的說法,所以我會繼續統稱壓力測試,有特定目標的測試再特別區分。
在 Windows 安裝很容易,我是用 Chocolatey choco install -y k6
兩分鐘搞定。寫幾行程式存成 script.js,再執行 k6 run script.js
便做能完簡單測試,得到平均回應時間(http_req_duration)及 Throughput (http_reqs):
回到我的樂透投注服務案例,我需要先呼叫 API 清除 DB、讀取事先準備好的 JSON 當成 HTTP Request Body,似乎比教學範例複雜一個等級,又該怎麼做?(可惡,感覺像上幼稚園第一天就被叫上台考兩位數加法...)
總之,經過一番摸索,我總算做出來了。
import http from 'k6/http';
import { SharedArray } from 'k6/data';
import { sleep, check } from 'k6';
const host = 'http://10.8.0.4'
const jsons = {};
JSON.parse(open('./index.json')).forEach(function(path, i) {
jsons[path] = open(`.\\tickets\\${path}.json`);
});
export let options = {
scenarios: {
registration: {
executor: 'per-vu-iterations',
vus: 100,
iterations: 100,
maxDuration: '300s',
},
}
};
export function setup() {
http.post(`${host}/DemoData/ClearLotteryEntries`);
}
const params = {
headers: {
'Content-Type': 'application/json'
}
}
export default function () {
// __VU - virtual user index, zero when setup/teardown functions
// __ITER - interation number
if (__ITER > 99 || __VU > 100) {
return;
}
const key = (__VU - 1).toString().padStart(4, '0') + '\\' + __ITER.toString().padStart(4, '0');
const payload = jsons[key];
let res = http.post(`${host}/Registration/Register`, payload, params);
check(res, {
'status is 200': (r) => r.status === 200
});
//sleep(1);
}
簡單記錄重點:
- 初始化動作寫在 setup 函式,若有收尾善後動作放在 teardown 函式。default 函式則是每次測試的動作,會反覆執行,HTTP 請求發送動作也會放在其中
- open() 可讀取檔案,但必須放在全域範圍,不能在 setup 或 default 函式中能呼叫。我的案例雖有一萬個 JSON 檔案,但總體積不到 4MB,我的解法是將它們全部讀入記憶體存成 Dictionary 備用,用空間換取方便
- 最早是把一萬筆 JSON 存成陣列,在 default 函式用 pop() 取出內容,但 K6 會有多 Virtual User(VU) 同時執行 default(),陣列物件做不到 Thread-Safe,導致多個 VU 抓到同一筆 JSON 資料重複。我的解法是用 __VU (Virtual User 編號) 跟 __ITER (執行第幾次) 這兩個系統變數組出唯一索引值(如:0001\0012)對映 JSON,確保唯一性
- K6 支援指定每個 Virtual User 執行的次數,做法是在 options 設定 Scenario,指定 executor: 'per-vu-iterations'
- 上傳 JSON 記得加 Content-Type: application/json Request Header
實測成功,得到跟 JMeter 相近的結果,平均回應時間 1.14s、Throughput 86.6 RPS:
【心得】
本次學習使用 K6 的過程,就像學習引用一個新程式庫般自然,而測試程式採用 JavaScript,對有前端經驗的開發者格外親切,實作過程也很順利,全無接觸陌生軟體的生澀茫然,倒有如沐春風的感覺。
對程式開發人員來說,K6 比 JMeter 簡單直覺,誰需要華麗操作介面,與滑滑鼠相比,寫程式才是程序員心裡最柔軟的那一塊。(註:真的想用 K6 又非要 GUI 不可,可考慮 K6 Cloud 雲端服務)
對非程式背景使用者,設定與結果看得到摸得到的 JMeter 才是人類該用的工具。但對愛寫程式的人,用程式碼控制才是王道(連 3D 列印都是寫程式建模型的我,不意外地被 K6 圈粉),有什麼客製需求加個函式便能輕易實現,能無限擴充的感覺超讚。
K6 的設計哲學及使用方式格外貼近開發者思維,完全可以理解 K6 為何被開發讀者們大推。而我,應該也會加入 K6 的行列。
In this article, you will find a straightforward introduction to K6, which will be utilized to conduct a load test by reading a JSON file and sending a predetermined number of requests.
Comments
# by 鳥毅
黑大,補充一下, JMeter在1998年就有1.0版,我在2000年時開始用的,當時好像還沒有GUI。 https://en.wikipedia.org/wiki/Apache_JMeter 。
# by Jeffrey
to 鳥毅,原來真的 1998 就有了。我有查到那篇 Wiki,2007 年上方那段 ... 讓我猶豫了,以為到 2007 才算公認的正式發佈。
# by Huang
想請問黑大有在Windows環境用過Postman to K6套件進行轉換嗎? 我照個官方文件進行操作,並使用管理者權限執行Command Line進行轉換時噴出EISDIR: illegal operation on a directory , read 。已確認過讀取Testapi.json檔案的路徑是正確的,Google後多數都指向問題是套件本身的引用模組有問題,不知道這種問題應該要如何除錯
# by Jeffrey
to Huang, 我沒用過 Postman to K6 套件,但依經驗這類問題多半是 npm 模組版本不相容造成的,如果要追就是看錯誤訊息的程式碼行數一層層追進去,都是 JavaScript 有程式可看,但有沒有能力改是另一回事。(我 JS 不夠熟,改成功的機率很低)