MOBILUS TECH BLOG

モビルスのプロダクト開発を支えるメンバーが 日々の開発現場の情報を発信します。

Go製の負荷テストツール「Vegeta」を使ってみた

はじめまして。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

plot_image
plot_image

使用例(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でテストシナリオを作成してみたい方はぜひ試してみてください!

モビルスでは、一緒に働く仲間を募集中です! 興味のある方は、ぜひ採用情報のページをご覧ください!