1. Qiita
  2. 投稿
  3. curl

curl でサッと HTTP ベンチマーク

  • 35
    いいね
  • 0
    コメント

何故 curl を使うか

HTTP のベンチマークといえば ab, JMeter, wrk など専用のツールがありますが、何故あえて単純な HTTP クライアントである curl を使うのか。
それは curl がある種の共通言語になっているからです。

さらに、いくつかのツールには HTTP リクエストを curl コマンドとしてコピーする機能が実装されています。
例えば Google Chrome では Developer Tools で Network タブ上から任意のリクエストを curl コマンドとしてコピーできます。

image

また、mitmproxy にもそのような機能があるようです。 (まだ自分では試してませんが)

つまり、PC ブラウザ上でのリクエストも、スマートフォンアプリ等でのリクエストも、curl コマンドとして簡単に取得できます。
スマートフォンアプリで具体的にどうするかは以下の記事を参照してください。

さらに、こういった方法で curl コマンドをコピーできると嬉しいのは、HTTP ヘッダ等を含めほぼ完全な HTTP リクエストを取得できるということです。
例えば Authorization ヘッダやセッション ID のクッキーが必要な場合に、それらの値をいちいち調べたり、さらにツールごとにどうやって渡せばいいか、といったことを調べる必要がなくなります。

curl でレスポンスタイムを取得する

まずは curl コマンドを用意します。
今回は自分のブログのトップページのものを Google Chrome から取得してみました。
(Cookie は削っています)

$ curl 'http://blog.yuyat.jp/' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,ja;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Connection: keep-alive' --compressed

このままだとレスポンスボディが出力されるだけです。
このコマンドの末尾に以下を加えます。

-s -o /dev/null -w  "%{time_starttransfer}\n"

-s はリクエスト中の進捗表示を抑制するため、-o はレスポンスボディを /dev/null に捨てるため。
そして大事なのは -w です。
これは様々な値を指定したフォーマットで出力するためのもので、ここではレスポンスタイムとして time_starttransfer を指定してみました。
(レスポンスタイムとしてこれが適切なのか、は正直あんまり自信ないのでツッコミ待ちです)
このオプションで取得できるものは様々なので、例えばレスポンスタイムだけでなくレスポンスの全てが帰るまでの時間を計測したい、といった場合などはより適切な値を選択してください。

これを実行すると以下のように出力されます。

$ curl 'http://blog.yuyat.jp/' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,ja;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Connection: keep-alive' --compressed -o /dev/null -w  "%{time_starttransfer}\n" -s
0.582

レスポンスタイムが 0.582 秒だとわかりました。

応用編: レスポンスタイムのパーセンタイル値を取得する

1 回だけのリクエストでは適切なベンチマークとは言えません。
ここでは 100 回リクエストを行ってそのパーセンタイル値を取得してみましょう。
(もっと多い方がいいかもしれないけど、あくまでこの記事はサッとやるだけなのでこの辺で)

zsh には repeat コマンドというのがあって、任意のコマンドを指定回数繰り返し実行することができます。
先ほどのコマンドの先頭に repeat 100 を追加するだけです。

$ repeat 100 curl 'http://blog.yuyat.jp/' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,ja;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Connection: keep-alive' --compressed -o /dev/null -w  "%{time_starttransfer}\n" -s
0.626
0.821
0.710
0.572
0.563
0.556
(以下略)

repeatzsh でしか使えませんが、拙作の ntimes というコマンドを入れると bash 等でも同じことができるようになります。
使い方は repeatntimes に置換してコマンドの前に -- を挟むだけです。
よかったですね。

この通り、1 回では 0.582 秒でも、繰り返し実行してみると幅があることがわかります。
というわけでこれのパーセンタイル値を取得してみましょう。
これまた拙作の percentile というコマンドを使います。
さっきのコマンドをパイプでこの percentile に繋げるだけです。

$ repeat 100 curl 'http://blog.yuyat.jp/' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,ja;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Connection: keep-alive' --compressed -o /dev/null -w  "%{time_starttransfer}\n" -s | percentile
50%:    0.575
66%:    0.655
75%:    0.715
80%:    0.734
90%:    0.929
95%:    1.167
98%:    1.472
99%:    1.937
100%:   2.613