K6

使用紀錄

20241124 ws chat 負載測試

  • 一開始是測試 500 人
  • 途中發現瓶頸卡在我的網路速度只有 20M
  • 造成大量的 delay timeout 錯誤
    • 在 pgsql connection pool 上限 5 個 & 超過 3 秒超時的狀況下完成 8X% 的處理
      • Image Not Showing Possible Reasons
        • The image was uploaded to a note which you don't have access to
        • The note which the image was originally uploaded to has been deleted
        Learn More →
    • 其他的都卡在取得連線超時上
    • 目前先簡單測試個 100 人做個紀錄
      • Image Not Showing Possible Reasons
        • The image was uploaded to a note which you don't have access to
        • The note which the image was originally uploaded to has been deleted
        Learn More →
      • 這次測試使用的 script
      ​​​​​​​​import ws from 'k6/ws';
      ​​​​​​​​import { check, sleep } from 'k6';
      
      ​​​​​​​​function generateToken() {
      ​​​​​​​​    return Math.random().toString(36).substring(2, 15);
      ​​​​​​​​}
      
      ​​​​​​​​export const options = {
      ​​​​​​​​    // stages: [
      ​​​​​​​​    //     { duration: '1m', target: 100 }, // 1 分鐘內增加到 100 個連線
      ​​​​​​​​    //     { duration: '3m', target: 500 }, // 3 分鐘內穩定在 500 個連線
      ​​​​​​​​    //     { duration: '1m', target: 0 },   // 1 分鐘內降到 0 個連線
      ​​​​​​​​    // ],
      ​​​​​​​​    stages: [
      ​​​​​​​​        { duration: '10s', target: 10 },
      ​​​​​​​​        { duration: '10s', target: 50 },
      ​​​​​​​​        { duration: '10s', target: 100 },
      ​​​​​​​​        { duration: '10s', target: 0 },
      ​​​​​​​​    ],
      ​​​​​​​​};
      
      ​​​​​​​​export default function () {
      ​​​​​​​​    const token = generateToken();
      ​​​​​​​​    const url = `wss://axum.kawa.homes/ws?token=${token}`;
      ​​​​​​​​    // const url = `ws://127.0.0.1:3000/ws?token=${token}`;
      
      ​​​​​​​​    const response = ws.connect(url, {}, (socket) => {
      ​​​​​​​​        socket.on('open', () => {
      ​​​​​​​​            // console.log(`Connected: ${token}`);
      
      ​​​​​​​​            // 發送多條消息,模擬使用者交談
      ​​​​​​​​            for (let i = 0; i < 10; i++) {
      ​​​​​​​​                let messageContent = generateToken();
      ​​​​​​​​                let data = {
      ​​​​​​​​                    message_type: "Message",
      ​​​​​​​​                    content: `k6 testing ${token} says ${messageContent}`,
      ​​​​​​​​                    from: token,
      ​​​​​​​​                    to: "All"
      ​​​​​​​​                };
      ​​​​​​​​                socket.send(JSON.stringify(data));
      ​​​​​​​​                sleep(1); // 每隔 1 秒發送一次
      ​​​​​​​​            }
      
      ​​​​​​​​            // 關閉連線
      ​​​​​​​​            socket.close();
      ​​​​​​​​        });
      ​​​​​​​​    });
      
      ​​​​​​​​    check(response, { 'WebSocket status is 101': (r) => r && r.status === 101 });
      ​​​​​​​​}
      
      
    • 測試後發現負載測試 100 人就會吃光我的網路頻寬了
    • 要再測試更多人可能要等提升網路 or 其他方法了

resource

簡介

  • k6 是一款現代的開源負載測試工具,它可以幫助開發者進行性能測試、壓力測試和容量規劃等工作。k6 的核心特點包括:
    • 簡單易用:k6 使用 JavaScript 腳本語言進行編程,使用者可以快速上手。
    • 現代化:k6 支持 ES6/ES7 的語法特性,具有現代化的開發體驗。
    • 高效可靠:k6 的測試引擎基於 Go 語言開發,具有高效、可靠的特點。
    • 高度可擴展:k6 支持多個使用者和腳本的同步運行,可以輕鬆地進行大規模的測試。
    • 雲端部署:k6 Cloud 提供了方便的雲端部署和管理,並且提供了實時的監控和報告功能。
  • k6 的使用場景包括:
    • 測試 Web 應用程式的性能和穩定性;
    • 測試 API 和微服務的性能和可靠性;
    • 測試數據庫和消息佇列等基礎設施的性能和容量;
    • 進行 CI/CD 測試和自動化測試等。
  • 總體來說,k6 是一款現代化、高效可靠且易於使用的負載測試工具,適合用於各種不同的場景和應用。

docker 版本的執行測試指令

# 測試線上
docker run --rm -i grafana/k6 run - <script.js

# 模擬 5 使用者,測試 5 秒
docker run --rm -i grafana/k6 run --vus 5 --duration 5s - <script.js

持久化資料

  • output.json 要先建立,不然會建立成資料夾然後報錯
docker run -i -u "$(id -u):$(id -g)" -v "$(pwd)/output.json:/output.json" grafana/k6 run - <script.js -o json=/output.json

摸索紀錄

  • 選擇使用 docker 版本
docker pull grafana/k6
  • 測試是以撰寫的 js 檔案為基礎來執行的

shell 範例

  • 以當前資料夾的 script.js 內容執行測試
#!/bin/bish

rm output.json
touch output.json

docker run --rm \
	-i \
	-v $PWD/script.js:/app/script.js \
	-v $PWD/output.json:/output.json \
	-u $(id -u):$(id -g) \
	-w /app \
	grafana/k6 run script.js -o json=/output.json

script 範例

import http from 'k6/http';
import { sleep } from 'k6';
export let options = {
  stages: [
    { duration: '30s', target: 10 },
    { duration: '1m30s', target: 30 },
    { duration: '20s', target: 0 },
  ],
};

export default function () {
  // http.get('https://kawa.homes/blog');
  
  // 使用 docker 測試本機的網址
  http.get('http://host.docker.internal:3000/api/ttest');
  sleep(1);
}