HAProxy 1.7 ではマルチプロセス時の統計情報が正しく取得できない

f:id:kyagi:20190616100100p:plain

HAProxy 1.7 をマルチプロセスで動かした場合、統計情報がおかしくなる

Kubernetes 上で haproxy を HTTP/HTTPS のロードバランサとして使用したところ、動作的には問題ないが prometheus/grafana で出力する統計情報(stats)が正しくないことに気がついた。正確に言うとシングルプロセス(nbproc 1)の場合は正しいものの、マルチプロセス(nbproc 4)になるとおかしくなる。マルチプロセスでそれぞれのメモリに統計情報を保持しているため、それらをまとめて出力する手段を持ち合わせていないことに由来するようだ。

1.7 のマニュアルを参照すると stats bind-process 1 を指定することで最も PID が若いプロセスに限定して統計情報を取得する説明があったものの、実際に試してみたところ、期待していた動作とは違っていた。

  • マニュアル
By default the stats socket is bound to all processes, causing a warning to be emitted when nbproc is greater than 1 because there is no way to select the target process when connecting. However, by using this setting, it becomes possible to pin
the stats socket to a specific set of processes, typically the first one. 

https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#stats

  • 実際の動作

f:id:kyagi:20190616101815p:plain

上記のグラフは 1.7 を利用して 1. シングルプロセス、2. マルチプロセス(nbproc=4), 3. マルチプロセス(nbproc=4, stats bind-process 1) それぞれを設定して、http リクエストを一定時間流した結果である。負荷が一定であれば単純な Counter 値である haproxy_frontend_http_requests_total は rate() した場合、右肩上がりになってから水平になるのが正しいはず。この例では 1. シングルプロセス時は正しい動きになっているものの、2.マルチプロセス(nbproc=4) および 3.マルチプロセス(nbproc=4, stats-bid-process 1) の時は値がおかしくなっている。本来であればマルチプロセス時に統計情報を取得するプロセスを固定するのが stats bind-process 1 のはずだが、こちらを指定しても機能はせず取得するプロセスはランダムになるようだ(stats ページにブラウザでアクセスしリロードを繰り返すと都度 PID が移り変わることも確認)

Each process has its own memory area, which means:
  (... snip ...)
  Information is stored locally in each process memory area and can't be shared:
    - stick table + traced counters
    - statistics
  (... snip ...)

www.slideshare.net

また、haproxy の統計情報を prometheus が取得(pull)するためのエンドポイントを提供するために haproxy-exporter を利用したが、こちらもメトリクスタイプを Counter ではなく Gauge としてしまうバグが 2015 年から放置されているようだ(こちらも fluentd のエンドポイントを curl して出力されるメトリクスタイプのコメントが gauge になっていることを確認)

github.com

このままでは正しく統計情報を取得できないままになってしまうため、解決策として2019年夏にリリースが予定されている 2.0(-dev7) を利用して、再度動作を確認してみることにする(続く) (o)

www.haproxy.com