本日も乙

ただの自己満足な備忘録。

負荷検証ツール「httperf」が500KBまでしかPOSTできない問題を対処した

小ネタです。
負荷検証を行う案件があり、httperfがシンプルかつ一定数のリクエストを送るのが簡単だったので使っていました。
システム内のAPIが対象で、で画像データをPOSTしその解析結果が返ってくるといったものです。以下のようなコマンドで負荷をかけていました。正確にはシステム間をまたぐため、HTTPS通信にしています。

$ httperf --client=0/1 \
--hog --server=example.com \
--ssl --ssl-protocol=TLSv1.1 --ssl-no-reuse --port=443 \
--rate 4 --num-conns=500 --num-calls=1 --timeout 60 \
--add-header="Content-Type:application/json\n" --wsesslog=100,0,request.txt
# request.txt
/foo method=POST contents="file=bar.json"

bar.json に複数枚の画像をBASE64形式に変換したものを含めていました。

ところが、何度やってもAPI側が400エラーを返してくるのです。curlコマンドで叩いても200 OKを返してきたので、httperfコマンドで誤りがあるということはわかっていました。そこで --debug オプションや tcpdump コマンドで投げられてくるリクエストを確認してみると、Bodyが500KBを超えるとそれ以降はトリムされるではありませんか!正しいリクエストが送れないため、400エラーが返されるのは納得です。

次になぜBodyが500KBを超えるとトリムされるのか、それを回避できる方法はないのかを調べました。httperfコマンドのmanを見てもそれを制限しているオプションがなかったため、内部の実装で決められているようです。次にhttperfのissueを見てみるとまさに該当するものがヒットしました。

https://github.com/httperf/httperf/pull/29

このissueでは上限を10KBから500KBまで増やすものなのでこれを利用すればさらに拡張することが可能です。本記事はその方法を紹介します。

httperfのインストール

ソースから改修する必要があるため、cloneして持ってきてビルド&インストールします。

% git clone https://github.com/httperf/httperf.git
% cd httperf
% autoreconf -i
% ./configure
% make
% make install
% httperf --version
httperf: httperf-0.9.1 compiled Aug 29 2018 without DEBUG without TIME_SYSCALLS.

ソース改変&再ビルド

こんな感じで改変します。C言語に慣れていないので修正内容はお粗末ですいません。
500KBから3.5MBまで増やしました。POSTでMBを超えることはあまりないと思うのでサイズに関しては自分たちで判断する必要があります。

% diff --git a/src/gen/wsesslog.c b/src/gen/wsesslog.c
index a213014..d675e2c 100755
--- a/src/gen/wsesslog.c
+++ b/src/gen/wsesslog.c
@@ -388,11 +388,17 @@ parse_config (void)
   FILE *fp;
   int lineno, i, reqnum;
   Sess_Private_Data *sptr;
-  char line[500000];   /* some uri's get pretty long */
-  char uri[500000];    /* some uri's get pretty long */
+  char line[3500000];  /* some uri's get pretty long */
+  char *uri;
+  uri = malloc(3500000);
+  if (uri == NULL) exit(0);
   char method_str[1000];
-  char this_arg[500000];
-  char contents[500000];
+  char *this_arg;
+  this_arg = malloc(3500000);
+  if (this_arg == NULL) exit(0);
+  char contents[3500000];
   double think_time;
   int bytes_read;
   REQ *reqptr;
@@ -575,6 +581,8 @@ parse_config (void)
          parsed_so_far += bytes_read;
        }
     }
+  free(uri);
+  free(this_arg);
   fclose (fp);

   if (DBG > 3)

修正したのを再ビルド&再インストールすることで有効化されます。

% make clean all
% ./configure
% make
% make install

再インストール後、もう一度最初にあったhttperfコマンドを実行してみてリクエストが成功していることを確認します。