8

讓開發人員如沐春風的壓力測試工具 - K6

 1 year ago
source link: https://blog.darkthread.net/blog/k6-load-testing/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

讓開發人員如沐春風的壓力測試工具 - K6

2023-04-06 07:53 PM 2 6,528

前兩篇 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 ToolK6 基本介紹、安裝及實作,輕鬆上手!)

  1. Smoke Testing 煙霧測試 - 驗證系統在低硬體配備、正常負載下不會出錯
  2. Load Testing 負載測試 - 取得在一般及尖峰負載下的系統效能數字(用戶數、Throughput)
  3. Stress Testing 壓力測試 - 測試在高度負載或極端條件下系統的穩定性及可靠度,找出系統極限
  4. Spike Testing 尖峰測試 - 故意製造瞬間流量驟升取得系統效能數字
  5. Soak Testing 浸泡測試 - 測試系統在長期運作下的穩定性及可靠度

依此定義,前兩篇 JMeter 練習應屬負載測試而非壓力測試。不過,「壓力測試」是比較通俗常用的說法,所以我會繼續統稱壓力測試,有特定目標的測試再特別區分。

在 Windows 安裝很容易,我是用 Chocolatey choco install -y k6 兩分鐘搞定。寫幾行程式存成 script.js,再執行 k6 run script.js 便做能完簡單測試,得到平均回應時間(http_req_duration)及 Throughput (http_reqs):

Fig1_638163789541659508.png

回到我的樂透投注服務案例,我需要先呼叫 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);
}

簡單記錄重點:

  1. 初始化動作寫在 setup 函式,若有收尾善後動作放在 teardown 函式。default 函式則是每次測試的動作,會反覆執行,HTTP 請求發送動作也會放在其中
  2. open() 可讀取檔案,但必須放在全域範圍,不能在 setup 或 default 函式中能呼叫。我的案例雖有一萬個 JSON 檔案,但總體積不到 4MB,我的解法是將它們全部讀入記憶體存成 Dictionary 備用,用空間換取方便
  3. 最早是把一萬筆 JSON 存成陣列,在 default 函式用 pop() 取出內容,但 K6 會有多 Virtual User(VU) 同時執行 default(),陣列物件做不到 Thread-Safe,導致多個 VU 抓到同一筆 JSON 資料重複。我的解法是用 __VU (Virtual User 編號) 跟 __ITER (執行第幾次) 這兩個系統變數組出唯一索引值(如:0001\0012)對映 JSON,確保唯一性
  4. K6 支援指定每個 Virtual User 執行的次數,做法是在 options 設定 Scenario,指定 executor: 'per-vu-iterations'
  5. 上傳 JSON 記得加 Content-Type: application/json Request Header

實測成功,得到跟 JMeter 相近的結果,平均回應時間 1.14s、Throughput 86.6 RPS:

Fig2_638163789547394389.png

本次學習使用 K6 的過程,就像學習引用一個新程式庫般自然,而測試程式採用 JavaScript,對有前端經驗的開發者格外親切,實作過程也很順利,全無接觸陌生軟體的生澀茫然,倒有如沐春風的感覺。

對程式開發人員來說,K6 比 JMeter 簡單直覺,誰需要華麗操作介面,與滑滑鼠相比,寫程式才是程序員心裡最柔軟的那一塊。(註:真的想用 K6 又非要 GUI 不可,可考慮 K6 Cloud 雲端服務)

對非程式背景使用者,設定與結果看得到摸得到的 JMeter 才是人類該用的工具。但對愛寫程式的人,用程式碼控制才是王道(連 3D 列印都是寫程式建模型的我,不意外地被 K6 圈粉),有什麼客製需求加個函式便能輕易實現,能無限擴充的感覺超讚。

K6 的設計哲學及使用方式格外貼近開發者思維,完全可以理解 K6 為何被開發讀者們大推。而我,應該也會加入 K6 的行列。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK