つかびーの技術日記

情報系修士卒のWeb系技術日記です。現在のフォーカス分野はアドテクです。

spray-canのサンプルにabコマンド打つと16000reqくらいで止まる

   

題名通りです。

abコマンドで自分のサーバに対して負荷をかけるとなぜか止まってしまう・・・という話です。

自分の今回の場合はspray-canという高速HTTPサーバライブラリで発生しました。これを起動してabコマンドで大量にリクエストを投げるとなぜか16000リクエストを投げたあたりで止まります。

結論としては以下のどれかで解決します。詳しく知りたい人は続きを読んでください。読んだ方が良いと思います。

  1. sudo sysctl -w net.inet.tcp.msl=1000 でTIME_WAITを短くする
  2. wrkコマンドを入れてこちらを使う
  3. そのままabコマンド使うが-kオプションを足す

spray-canサンプル

https://github.com/spray/spray/tree/master/examples/spray-can/simple-http-server/src/main

このあたりにあります。これを適当にコピって来て、libraryDependenciesにspray-canとakka-actorを追加すれば動きます。

サンプルを見れば分かりますが、/pingというエンドポイントがあるので、ここにHTTP GETすれば結果が取れます。

実際にココに対して適当にabコマンドを叩くと・・・

1秒あたり約3200reqさばけています。凄い。

abコマンドの問題

さて、ここでリクエスト数を増やしてみます。

何度やっても16000reqくらいでtime outが発生するように・・・意味が分からない・・・

別にプログラムが落ちる訳でもなく・・・

解決方法

意味が分からんし、どうぐぐったものか・・・と思っていたのですが、意外と見つかりました。

https://groups.google.com/forum/#!topic/spray-user/fiT_mNNd8Xg

こっちはrubyのthinサーバですが、自分とほぼ全く同じ状況に

http://stackoverflow.com/questions/9156537/why-does-a-simple-thin-server-stop-responding-at-16500-requests-when-benchmarkin

sudo sysctl -w net.inet.tcp.msl=1000 を実行するか、wrkコマンドを使えばOKです。wrkはデフォルトでは入っていませんので、homebrewユーザならばbrew install wrkで入れてください。

解説

そもそもなぜ16000reqほどで止まってしまうのでしょうか。

それは空きポートが無いから、です。まずはこれを見てみます。

49152 port以上は特に予約されておらず自由に使えます。HTTP通信するときに受信側は当然port80で待ち受けますが、送信側は適当なポートを使います。ここで自由に使えるポートの数はというと、65535 – 49152 = 16383、という訳で約16000です。

通信なんざすぐに終わるし、使えるポートが16000でも問題ないのでは、と思いますが、実は一度使ったポートはすぐには使えません。一定の時間(TIME_WAIT)待ち時間があり、待ち時間が終わると再度ポートが使えるようになります。

なぜこうなっているかというと、遅延パケットの伝達によりアプリが狂ってしまうことを防ぐ為です。アプリAがportXで2回通信した後でportXを解放して、その直後にアプリBがportXを使ったとき、初めのアプリAに対するresponseがportXに到達したとき、アプリBが狂ってしまう可能性があります。

という訳でabコマンドで大量リクエストが送れない云々はこういう理由でした。

みなさんTCP portの空きやTIME_WAITやabコマンドには気をつけましょう。

 - サーバ , ,