CentOS 7 の yum でさくっとインストールできるバージョンで試しています。
- haproxy-1.5.14-3.el7.x86_64
その他に、ログとかスティッキーセッションとかについても書いてます。
あと、いまのところ使う予定がなかったので mode tcp
は試していません。
WEB で統計レポートを表示
プロキシのセクション(defaults/listen/frontend/backend
)で stats enable
を指定すれば、http://localhost/haproxy?stats
のような URL で HAProxy の統計レポートを表示できる。
frontend main *:80 stats enable :
URL は stats uri
で変更できる。下記の例だと http://localhost/admin?stats
となる。
frontend main *:80 stats enable stats uri /admin?stats :
stats http-request
と acl
を組み合わせればソース IP アドレスで制限できる。
frontend main *:80 acl is_private src 192.168.33.0/24 stats enable stats uri /admin?stats stats http-request allow if is_private :
stats admin
で条件を指定すると、その条件に該当するときだけ管理レベルの操作が可能になる。通常は統計レポート画面はリードオンリーな操作しかできないが、この設定が有効だとバックエンドサーバのメンテナンスモードへの切り替えや、ヘルスチェックの有効/無効、などの操作が可能になる。
frontend main *:80 acl is_private src 192.168.33.0/24 stats enable stats uri /admin?stats stats http-request allow if is_private stats admin if LOCALHOST :
↑で指定した LOCALHOST
は組み込みの acl
で、自分で定義した acl
も指定できる。
stats auth
で統計レポートの画面に認証を設けることもできる。
frontend main *:80 acl is_private src 192.168.33.0/24 stats enable stats uri /admin?stats stats http-request allow if is_private stats admin if TRUE stats auth admin:AdMiN123 :
CLI で統計レポートを表示
グローバルセクションで stats socket
を指定すると Unix ドメインソケット経由で CLI で統計レポートを得ることができる。
global stats socket /var/lib/haproxy/stats level admin :
例えば、次のように nc
とかで統計情報レポートを得ることができる。
echo "show stat -1 4 -1" | nc -U /var/lib/haproxy/stats | grep -v -E '^#|^$' | cut -d, -f2,18
level
で指定している admin
はソケット経由で操作可能なレベルを表していて、admin
ならすべての操作が可能。
また、次のように指定すれば TCP でも接続できる。
global stats socket ipv4@127.0.0.1:9999 level admin :
monitor-uri / monitor fail
monitor fail
と monitor-uri
を使うと、特定の URL へのリクエストを、条件によって 200 または 503 を返すようにすることができる。
frontend main *:80 acl is_dead nbsrv(app) lt 2 monitor fail if is_dead monitor-uri /haproxy?alive :
この例だと /haproxy?alive
へリクエストしたときに app バックエンドの生きているサーバが 2 台以上あるなら 200 を、2 台未満なら 503 を返す。
URL にクエリストリングを含めているのには特に深い意味は無い、クエリストリング無しで /alive
とかでも構わない。
monitor-net
monitor-net
を使うと、特定のアドレス帯からのリクエストは即座に 200 を応答するようになる。
frontend main *:80 monitor-net 192.168.33.0/24 :
この例だと 192.168.33.0/24
からのリクエストは直ちに 200 を応答する。
バックエンドのサーバが全滅しても 200 を応答するけど・・どういう用途に使うものなの? これ。
fullconn / maxconn / minconn
backend
の fullconn
と server
の maxconn
や minconn
の関係。
http://permalink.gmane.org/gmane.comp.web.haproxy/5378
上記によると、例えば次のような設定だと、
backend dynamic fullconn 10000 server srv1 dyn1:80 minconn 100 maxconn 1000 server srv2 dyn2:80 minconn 100 maxconn 1000 :
低負荷時には最大接続数の制限は minconn
の 100 で、バックエンド全体に対する同時接続数が増えてくると最大接続数の制限も増加する。その増加は線形で、バックエンド全体に対する同時接続数が fullconn
の 10000 になったときに maxconn
の 1000 になるように増加する。ただし maxconn
を超えることはない。
ニュースサイトとかでトラフィックパターンに大きな変動を伴うサイトでは静的な maxconn
だとちょうど良い値を設定することができない(低負荷時は小さい値にしたいし、高負荷時は大きい値にしたい)。
fullconn
と minconn
を使えばサイトの負荷に応じて動的に同時接続数の制限を変動することができる。
・・らしいんだけど maxconn
だけじゃダメな理由が良くわからない。
maxconn の設定箇所ごとの意味
global
の maxconn
はプロセスに適用されるもので、frontend
の接続の合計。
default/frontend/listen
の maxconn
は frontend
ごとに適用される。
frontend
がもたらすものよりも大きい値を server
の maxconn
に設定した場合、キューが使われることがなくなるだけで、とくに問題ではない。
HTTP のモードの設定
下記を参考に・・・
https://blog.cloudpack.jp/2014/07/28/ha-proxy-translation-document-http-transaction/ https://blog.cloudpack.jp/2014/07/28/ha-proxy-translation-document-option-httpclose/ https://blog.cloudpack.jp/2014/08/08/tips-haproxy-option-httpclose-and-http-server-close-with-tcpdump/
http-tunnel
や httpclose
は非奨励のようなので、下記のいずれかを設定する。
option http-keep-alive
- サーバ側とクライアント側の両方で keep-alive する
option http-server-close
- 応答の終わりでサーバ側はクローズするがクライアント側は keep-alive する
option forceclose
- 応答の終わりでクライアントとサーバの両方をクローズする
おおむね、次のようにしておくと良い。
option http-keep-alive
- 静的コンテンツのサーバ
option http-server-close
- アプリケーションサーバ
タイムアウト関係の設定
timeout connect
- HAProxy からバックエンドサーバへの接続のタイムアウト時間
- クライアントからの接続のプロキシ時とヘルスチェックでの両方で適用される
timeout client
- クライアントから HAProxy への接続で無応答のタイムアウト時間
- つまり、HAProxy がクライアントから ACK やデータ送信を期待したときに、どれだけ待つかの時間
- なので、リクエスト〜レスポンスのトータル時間とは異なる
timeout server
- HAProxy からバックエンドサーバへの接続で無応答のタイムアウト時間
timeout client
のバックエンドサーバの版- なので、リクエスト〜レスポンスのトータル時間とは異なる
timeout http-request
完全なリクエスト〜レスポンスのタムアウト時間クライアントから最初のバイトを受信してからクライアントに最後のバイトを送信するまでの時間- クライアントからのリクエストの開始からリクエストヘッダを受けきるまでのタムアウト時間
- リクエストボディやレスポンスにはこのタイムアウト時間は適用されない
timeout http-keep-alive
- いわゆる keep-alive のタイムアウト時間
- クライアントに最後のバイトを送信してから次のリクエストの最初のバイトを受信するまでの時間
timeout check
- ヘルスチェックで接続が確立された後の追加のタイムアウト時間
- ヘルスチェックでは接続のタイムアウト時間として
timeout connect
とinter
の小さい方が使用される - 接続が確立されると read のタイムアウト時間として
timeout check
が追加される
timeout queue
- キューに入った接続を解放するまでのタイムアウト時間
- HAProxy への接続が
server
のmaxconn
に達すると接続はキューに入ってserver
の接続の空きを待つ - タイムアウト時間が経過するとクライアントには 503 が応答される
option redispatch
スティッキークッキーが有効な場合、振り分けられるバックエンドのサーバが死ぬと他のサーバが生きていても HAProxy が当該サーバをダウンと判断するまでクライアントはサービスにアクセスすることができなくなる。
下記のオプションを指定すると、そのようなケースでも別のサーバへの振り分けが行われる。
defaults option redispatch :
また、retries
も指定されている場合、リトライの最後の施行だけ別のサーバへ振り分けられる。
defaults option redispatch retries 3 :
option httplog
HTTP のアクセスログを記録する。
次のように指定すると CLF という Apache のアクセスログでお馴染みの標準的な形式のログになる。
defaults option httplog clf :
option dontlognull
いわゆる NULL スキャンのログを記録しないオプション、、、というわけではなくて、TCP で 80 番ポートを開いて直ぐ閉じるような、内容が HTTP ではないアクセスもログをログに記録しないようにするオプション。
nmap でいうところの -sT
オプションのスキャンがログに残るかどうか、ということ(-sN
はどっちにしろ残らない)。
例えば、死活監視でポートが開いているかを監視するために bash で < /dev/tcp/127.0.0.1/80
みたいなことをやっていると、通常はこのアクセスまでログに記録されてしまうが、option dontlognull
を指定しておけば、このようなアクセスはログには残らなくなる。
インターネットのような制御されていない環境(uncontrolled environments)では指定しないことをおすすめする。
forwardfor
次のように指定すると X-Forwarded-For
や X-Original-To
ヘッダがバックエンドサーバへのリクエストに追加される。
defaults option forwardfor option originalto :
既に X-Forwarded-For
や X-Original-To
が付与されていた場合(HAProxy へのリクエストの時点でこれらのヘッダが付いていた場合)、カンマ区切りで追記される。
次のように except を追加すると、そのネットワークからのリクエストでは X-Forwarded-For
や X-Original-To
を追加しなくなる。
defaults option forwardfor except 127.0.0.0/8 option originalto except 127.0.0.0/8 :
例えば、HAProxy へのアクセスが、クライアントから直接と、既知のリバースプロキシ経由との 2 つが混在するような場合に、except でリバースプロキシを指定すれば、既知のアドレスが X-Forwarded-For
に追加されないようにすることができる。
他にも、HAProxy のホスト上から http://localhost/
などとアクセスすると X-Forwarded-For
が 127.0.0.1
になり、バックエンドサーバでこの値をアクセスログに記録している場合、まるで意味のないログになってしまう。そこで、except 127.0.0.0/8
を指定すれば X-Forwarded-For
が記録されなくなるので、Web サーバで X-Forwarded-For
がなければ通常のリモートアドレスにフォールバックするようになっていれば、アクセスログには Web サーバから見た HAProxy のアドレスが記録されるようになる・・・という使い方もできるかもしれない。
option logasap
デフォルトではログはレスポンスの完了時に記録されるが(じゃないと総転送量とかがわからない)、次のように設定するとレスポンスヘッダが送信された時点でアクセスログが記録されるようになる。
defaults option logasap :
ただ、その場合、ログに記録される転送量や転送時間は不完全なものになる。実際に見比べた感じ、このオプションがなければ 688
のような具体的な値が記録されるのに対して、このオプションを指定していると +445
のように記録される。
option log-health-checks
デフォルトではヘルスチェックのログは rise
や fall
で指定された回数のリクエストの結果を元にステータスが変化したときにだけ記録されるが、次の設定をすると、ステータスが変化する前のヘルスチェックの結果もログに記録される。
defaults option log-health-checks :
例えば、ヘルスチェックの設定が次のようになっているとき、
defaults default-server inter 2s rise 2 fall 3 :
ステータスが OK の状態でヘルスチェックに失敗したとき、上記のオプションが指定されていなければ 3 回失敗して初めてログに記録されるが、上記のオプションが指定されている場合は最初の 1 回目からログに記録され、3 回ログに記録された後にステータスが変わった旨のログが記録される。
agent-check
バックエンドサーバの Up/Down や重みをサーバの特定のポートに TCP でアクセスして返ってきた値に応じて行なう。
次のように設定すると、サーバの 1234 ポートに定期的にアクセスする。
backend app balance roundrobin default-server inter 2s rise 2 fall 3 agent-port 1234 agent-inter 3s server ap01 192.168.33.21:80 check agent-check server ap02 192.168.33.22:80 check agent-check option httpchk GET /ok.html http-check expect status 200
そのポートが 80%
のような値を返すと、振り分けの重みが 80% になる。
他にも、次のような値を返すことができる。
- サーバの Up/Down の状態
up
down
またはfailed
またはstopped
- サーバの管理状態
ready
maint
drain
- 重み
80%
など
ポートが返さなかった値は変更されない。つまり 80%
とだけ返した場合は重みだけが変更されて、Up/Down やメンテナンスなどの状態は変更されない。
また、ポートが応答がなかった場合でも Down になるわけではないので(ステータスが更新されないだけ)、option httpchk
と併用はしなければならない。
READY/MAINT/DRAIN
agent-check
の説明ででてきた READY/MAINT/DRAIN はバックエンドサーバの管理状態を意味するもので、それぞれ次のような意味。
- READY
- MAINT や DRAIN が解除された通常の状態
- DRAIN
- 新しい接続を受け入れない
- MAINT
- 新しい接続を受け入れず、かつ、死活監視も停止する
動的なサーバの取り外し
稼働中の HAProxy から一時的に特定のバックエンドサーバへの振り分けを停止する方法。
WEB での統計レポートの管理モードを有効にして、特定のサーバを DRAIN や MAINT に切り替えることで実現できる。
もしくは、CLI での統計レポートの管理モードが有効になっていれば、次のようなコマンドで切り替えることができる。
# MAINT にする echo "disable server app/ap01" | nc -U /var/lib/haproxy/stats # MAINT から元に戻す echo "enable server app/ap01" | nc -U /var/lib/haproxy/stats
# DRAIN echo "set weight app/ap01 0%" | nc -U /var/lib/haproxy/stats # DRAIN から元に戻す echo "set weight app/ap01 100%" | nc -U /var/lib/haproxy/stats
サービスダウンのログ
バックエンドサーバが全滅すると次のようなログが発生する。
Server app/ap02 is DOWN, reason: Layer7 wrong status, code: 404, info: "HTTP status check returned code <3C>404<3E>", check duration: 0ms. 0 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
backend app has no server available!
1個目のログは alert だけど2個目のログは emerg で発生する。
emerg のログは rsyslog の設定に依らず(というか rsyslog を停止しても)コンソールにブロードキャストされる。
Broadcast message from systemd-journald@ha01 (Tue 2016-04-19 14:04:43 JST): haproxy[7758]: backend app has no server available!
見ての通り systemd-journald
が出しているもので、/etc/systemd/journald.conf
の MaxLevelWall
のデフォルトが emerg だからなのだと思われる。