はじめまして。Platform Development DivisionのWataru.Nと申します!
先日、Next.jsについてブログを書いていた Alek さんと同じチームで開発を行っています。
最近、調査の一環として簡易な負荷テストを行う機会があり、Goで作られた Vegeta というオープンソースのツールを使いました。
(名前についてはリポジトリを開くとわかりますが、あのベジータです)
Vegetaは基本的にはCLIベースでシンプルに使えるものですが、Goのライブラリとしてシナリオを書くこともできます。私が担当しているサービス(Security Suite、CRM Connect)ではバックエンドの開発言語にGoを使用しているため、親和性も考慮して採用してみました。
本記事ではその基本的な使い方を紹介します。
使用例(CLI)
まず、CLIでサクッと使用する例です。 コマンドをベタ書きして実行することも、用途別にファイルを用意してそれを入力とすることもできます。 今回は管理のしやすい後者のやり方で行いたいと思います。
インストール
以下の公式リポジトリに書いてある手順を参考にインストールします。
https://github.com/tsenart/vegeta?tab=readme-ov-file#install
macOSの場合:
$ brew update && brew install vegeta ... $ vegeta -version Version: 12.12.0
準備
以下のようなファイルを作成します(各ファイル名は任意です)。
. ├── input.json # リクエストボディを定義 └── targets.txt # リクエストを定義
リクエストメソッドおよびURL、ヘッダなどを targets.txt
に定義しておき、実行時に input.json
からリクエストボディを取得してリクエストを行うという流れになります。
targets.txt
今回は例として、ローカルで起動しているアプリの認証APIを叩くものとします。
※一般公開されているURLに対しては行わないようご注意ください
POST http://localhost:8080/app/auth Content-Type: application/json @input.json
input.json
認証APIへのリクエストに使用するリクエストボディを記載します。
{ "email": "sample@sample.com", "password": "samplepassword" }
実行
以下は、targets.txt
ファイルで定義した認証APIへのリクエストを 10リクエスト/秒 で 5秒間 投げ続ける例です。
$ vegeta attack -rate=10 -duration=5s -targets=targets.txt > result.bin | vegeta report Requests [total, rate, throughput] 50, 10.20, 10.08 Duration [total, attack, wait] 4.96s, 4.9s, 59.857ms Latencies [min, mean, 50, 90, 95, 99, max] 57.258ms, 61.022ms, 59.972ms, 61.551ms, 62.448ms, 99.702ms, 99.702ms Bytes In [total, mean] 8800, 176.00 Bytes Out [total, mean] 5300, 106.00 Success [ratio] 100.00% Status Codes [code:count] 200:50 Error Set:
- 実行は attackコマンド で行います
- 結果は
result.bin
に保存され、最後にそれを reportコマンド で読み込んでメトリクスを表示しています
結果の項目の意味については reportコマンド のセクションに記載されています。
今回でいうと
Requests[total]
より、合計50リクエスト実行されたことLatencies[mean]
より、平均レイテンシは 61.022ms であったこと
などがわかります。
また、plotコマンドを使用することで、結果ファイルから「レイテンシ - 時間経過」のグラフをHTML出力することが可能です。
$ vegeta plot result.bin > plot.html
使用例(Goライブラリ)
続いて、先程と同様のテストシナリオをGoで作成し、実行してみます。
環境
OS: macOS Sequoia 15.2 Go: go1.22.1 darwin/arm64 vegeta: v12.7.0+incompatible
コード
sample.go
package main import ( "encoding/json" "log" "os" "time" vegeta "github.com/tsenart/vegeta/lib" ) // ログインリクエストのパラメータ type LoginRequest struct { Email string `json:"email"` Password string `json:"password"` } func main() { // 10リクエスト/秒 rate := vegeta.Rate{Freq: 10, Per: time.Second} // 実行時間 = 5秒間 duration := 5 * time.Second // リクエストボディの作成 req := LoginRequest{ Email: "sample@sample.com", Password: "samplepassword", } body, err := json.Marshal(req) if err != nil { panic(err) } // targeterを定義 targeter := vegeta.NewStaticTargeter(vegeta.Target{ Method: "POST", URL: "http://localhost:8080/app/auth", Header: map[string][]string{ "Content-Type": {"application/json"}, }, Body: body, }) // attackerを定義 attacker := vegeta.NewAttacker() // 実行 var metrics vegeta.Metrics for res := range attacker.Attack(targeter, rate, duration, "Login Test") { metrics.Add(res) } metrics.Close() // 結果をレポート reporter := vegeta.NewTextReporter(&metrics) if err := reporter.Report(os.Stdout); err != nil { panic(err) } }
コードとしては、CLIの例で作成した targets.txt
, input.json
の内容を targeter
変数に持たせるようなイメージです。
その情報をもとに、attacker.Attack()
で指定された頻度でリクエストを実行します。
Attack()
の内部ではセマフォを使用することで並行リクエストを管理しているようです。
実行
上記コードを実行すると、CLIで行った場合と同様に以下のような結果が出力されました。
$ go run sample.go Requests [total, rate, throughput] 50, 10.20, 10.08 Duration [total, attack, wait] 4.961705416s, 4.900639666s, 61.06575ms Latencies [mean, 50, 95, 99, max] 65.302604ms, 60.294812ms, 99.862207ms, 169.72579ms, 169.725791ms Bytes In [total, mean] 8800, 176.00 Bytes Out [total, mean] 4350, 87.00 Success [ratio] 100.00% Status Codes [code:count] 200:50 Error Set:
まとめ
負荷テストツールVegetaについて、CLIベースでの使い方とGoのライブラリとしての基本的な使い方を紹介しました。
動作が軽量なことに加え、実施したいテストの内容や複雑さによって2パターンの使い分けができる点が良いなと感じました。
シンプルに負荷テストを行いたい方、あるいはGoでテストシナリオを作成してみたい方はぜひ試してみてください!
モビルスでは、一緒に働く仲間を募集中です! 興味のある方は、ぜひ採用情報のページをご覧ください!