post Image
GoでHTTP負荷テストフレームワークをつくった

最近、HTTP負荷テストをしたいという要求が高まり、負荷テストツール/フレームワークを探しました。
要件としては、以下のような具合です。

  • シナリオを自由にかつ楽に組めること(できればコードで)
    • 同時に複数のパスへのリクエストを送信できること(単体でリクエストも可能であること)
    • 全てのリクエストに対してそれぞれ異なるリクエストヘッダやリクエストパラメータなどを付与できること
  • 並列性があり、ある程度のパフォーマンスが出ること
  • 依存が(少)なく、どこでも動かせるとうれしい

JMeterやSiegeやwrkなどいろいろ見てはみましたが、なんかどれも帯に短したすきに長しという具合で微妙というかんじになってしまいました。

そこで、これらを全て満たすやつをGoで書きました。
Goで書いたのは依存を少なくするためと、並列性能に期待したからですが、Goを書いてみたかったからというのもありました。Goを試すには打って付けのお題だと思ったのです。
なので、ほとんど初めて書いたGoコードという感じです。

こんな具合で使えます。

package main

import (
    "github.com/karupanerura/gostress"
    "log"
    "math/rand"
    "runtime"
    "time"
)

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    rand.Seed(time.Now().UnixNano())

    client := gostress.NewHttpClient(
        gostress.HttpClientConfig{
            Server: gostress.ServerConfig{
                Hostname: "myhost.com",
                Secure: false,
            },
            Headers: map[string]string{},
            UserAgent: "Gostress/alpha",
            MaxIdleConnsPerHost: 1024,
            RequestEncoder: &gostress.JsonRequestEncoder{},
            ResponseDecoder: &gostress.JsonResponseDecoder{},
        },
    )
    state := map[string]string{}
    context := gostress.NewScenarioContext(client, state)
    scenario := makeScenario()
    context.Run(scenario)
}

func makeScenario() gostress.Scenario {
    scenarios := gostress.NewSeriesScenarioGroup(256) // 直列で実行するシナリオ
    scenarios.MinInterval =   500 * time.Millisecond
    scenarios.MaxInterval = 10000 * time.Millisecond
    scenarios.Next(makeHTTPScenario("GET", "/", nil))
    scenarios.Next(
        &gostress.SleepScenario{Duration: 1 * time.Millisecond},
    )
    scenarios.Next(
        gostress.NewConcurrentScenarioGroup(3).Add(// 並列で実行するシナリオ
            makeHTTPScenario("GET", "/api/foo", nil),
        ).Add(
            makeHTTPScenario("GET", "/api/bar", nil),
        ).Add(
            makeHTTPScenario("GET", "/api/baz", nil),
        ),
    )
    scenarios.Next(
        &gostress.DelayScenario{// 一定時間後に発火するシナリオ
            Duration: 1 * time.Millisecond,
            Scenario: makeHTTPScenario("GET", "/api/hoge", nil),
        },
    )
    scenarios.Next(
        &gostress.DeferScenario{
            Defer: func (state gostress.ScenarioState) gostress.Scenario {
                // 遅延して実行するシナリオを決定する
                return makeHTTPScenario("GET", "/api/fuga", nil)
            },
        },
    )
    scenarios.Next(
        &gostress.DeferScenario{
            Defer: func (state gostress.ScenarioState) gostress.Scenario {
                // 遅延して実行するシナリオを決定する
                return &gostress.NoopScenario{} // なにもしない
            },
        },
    )
    return scenarios
}

func makeHTTPScenario(method, path string, content interface{}) gostress.Scenario {
    return &gostress.HttpScenario{
        Method:  method,
        Path:    path,
        Content: content,
        OnComplete: func(state gostress.ScenarioState, res *gostress.HttpResponse, duration time.Duration) {
            log.Printf("method:%s\tpath:%s\tstatus:%d\ttime:%f", method, path, res.StatusCode, duration.Seconds())
        },
        OnError: func(state gostress.ScenarioState, err error) {
            log.Printf("Error: %s", err)
        },
    }
}

性能的には、別ネットワークから1台で数千並列で動かして、JSONのREST APIだけのリクエストで数百Mbps出せるくらいの性能はあるようです。
いったんGithubに公開してありますが、えいやで作ったので、まだテストもドキュメントも書けていないです。
近いうちに整えたい。

明日は @htk291 さんです!


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。