k6でAPI負荷テストしてみる
3行でまとめ!
- 🪨 k6を使用した負荷テストの方法をご紹介します!
- 🤠 5つの負荷テストのパターンをお勉強します!
- 🐳 Docker環境用意しました
docker compose up -d
とするだけで試すことができます!
🚀 ソースコードはGitHubで公開しています
k6とは?
- Grafanaが提供するオープンソースの負荷テストツール
- JavaScriptで負荷テストを記述できる
- 仮想的なユーザ数や、負荷の大きさ、許容エラー数の閾値設定などを簡単に行える
環境構築
今回は以下の構成でテスト環境を構築します:
- Go言語で実装したAPIサーバー
- MySQLデータベース
- k6負荷テストツール
APIサーバーの実装
コードを公開しているので、APIサーバのエンドポイントだけ、ざっと紹介します。
エンドポイント | メソッド | 機能 |
---|---|---|
/health |
GET | ヘルスチェック |
/users |
POST | ユーザ作成(DBに保存) |
APIサーバのコード(抜粋)
// app/main.go
package main
// ...
type User struct {
ID int `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at,omitempty"`
}
func main() {
// ...
r.POST("/users", createUser)
r.GET("/health", healthCheck)
// ...
}
func createUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
result, err := db.Exec("INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)",
user.Name, user.Email, time.Now())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
id, _ := result.LastInsertId()
user.ID = int(id)
c.JSON(http.StatusCreated, user)
}
func healthCheck(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
})
}
k6で負荷テストを作ってみる
10人のユーザが1秒毎にリクエストを送信するような負荷テストを作ってみます。
何人のユーザで、どれくらいの期間負荷を与えるかという設定を
options
オブジェクトに指定します。
// script.js
export const options = {
vus: 10, // 仮想ユーザー数
duration: '30s' // テスト実行時間
};
APIリクエストの方法や、レスポンス内容の確認などを関数で定義します。
// script.js
export default function () {
// APIサーバにリクエスト
const res = http.get('http://localhost:8080/health');
// レスポンスのチェック(ステータスコードをチェック)
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
あとは、このスクリプトを実行するだけです!
k6 run script.js
実行すると、10人のユーザがリクエストを送りつける様子が確認できます。
k6の基本的な機能
Check
- リクエストステータスは正常か
- レスポンスは正しいか
- レスポンス時間は一定時間内か
このような条件を設定することができます。
check(res, {
'status is 201': (r) => r.status === 201,
'response has user id': (r) => JSON.parse(r.body).id !== undefined,
'response time OK': (r) => r.timings.duration < 500
});
Threshold
個々のリクエストの成功/失敗を判定するcheck
とは別に、
テスト全体の合格/不合格の基準を設定するthreshold
があります。
export const options = {
thresholds: {
errors: ['rate<0.1'], // エラー率10%未満
http_req_duration: ['p(95)<500'], // 95%のリクエストが500ms未満
},
};
Stages
「だんだんと負荷を増やしていきたい」という願いを叶えてくれる機能です。
どれくらいで(duration
)、どこまで増やすか(target
)を指定するだけで、自動的に制御してくれます。
export const options = {
stages: [
{ duration: '30s', target: 10 }, // 0→10ユーザーまで30秒かけて増加
{ duration: '1m', target: 10 }, // 10ユーザーを1分間維持
{ duration: '30s', target: 0 } // 10→0ユーザーまで30秒かけて減少
]
};
メトリクス
テストが完了すると以下のようなメトリクスが一覧で表示されます。
基本的なメトリクス | 説明 |
---|---|
checks | チェックの成功率 |
data_received | 受信データ量 |
data_sent | 送信データ量 |
http_req_blocked | TCP接続待ち時間 |
http_req_duration | リクエスト全体の所要時間 |
http_req_failed | 失敗したリクエスト数 |
http_req_receiving | レスポンス受信時間 |
http_req_sending | リクエスト送信時間 |
http_req_waiting | サーバー処理待ち時間 |
http_reqs | 総リクエスト数 |
iterations | 反復回数 |
vus | 仮想ユーザー数 |
負荷テストパターン
k6を使用して、以下の5つの異なるテストパターンを実装します。
1. スモークテスト(基本機能確認)
基本的な機能が正常に動作することを確認するための軽量なテスト。
export const options = {
vus: 2, // 2人の仮想ユーザー
duration: '30s', // 30秒間の実行
thresholds: {
errors: ['rate<0.1'], // エラー率10%未満
http_req_duration: ['p(95)<500'], // 95%のリクエストが500ms未満
},
};
2. スパイクテスト(急激な負荷上昇)
突発的なトラフィック増加への対応を確認するテスト。
export const options = {
stages: [
{ duration: '20s', target: 10 }, // 通常負荷
{ duration: '10s', target: 50 }, // スパイク
{ duration: '30s', target: 50 }, // スパイク継続
{ duration: '10s', target: 10 }, // 通常負荷に戻る
{ duration: '10s', target: 0 }, // 終了
],
};
3. ストレステスト(限界検証)
システムの限界を探るためのテスト。
export const options = {
stages: [
{ duration: '30s', target: 20 }, // 徐々に上昇
{ duration: '1m', target: 50 }, // さらに上昇
{ duration: '1m', target: 100 }, // ピーク
{ duration: '30s', target: 0 }, // スケールダウン
],
};
4. 耐久テスト(長時間安定性)
長時間の安定性を確認するテスト。
export const options = {
stages: [
{ duration: '30s', target: 30 }, // 徐々に上昇
{ duration: '3m', target: 30 }, // 3分間維持
{ duration: '30s', target: 0 }, // スケールダウン
],
};
5. ブレークポイントテスト(限界点特定)
システムが破綻するポイントを特定するテスト。
export const options = {
stages: [
{ duration: '30s', target: 50 }, // 初期負荷
{ duration: '30s', target: 100 }, // 中負荷
{ duration: '30s', target: 200 }, // 高負荷
{ duration: '30s', target: 300 }, // より高負荷
{ duration: '30s', target: 0 }, // クールダウン
],
};
まとめ
JavaScriptで簡単に負荷テストが作れてしまうk6、ステキ!
[宣伝] komichi というアプリを作っています!
「どこ行こうかなぁ〜」と考えてたら休日が終わることってありませんか?
このアプリを使うと、現在地や好きな場所から、自動的に付近の場所を検索してお出かけプランを提案してくれます!
見知った場所でも意外としらないスポットが出てきて面白いですよ!
先日、Android版をリリースいたしましたので、Androidユーザの方はぜひインストールお願いします!
Discussion