HAProxyのACLとCriteria

HAProxyのACLについて仕事で使う機会があったので、いくつか調べたものを復習としてメモします。(HAProxyはかなり設定可能な項目が多いので、主にCriteriaです。)
※バージョンは、1.4.8で確認しました。

nbsrv

現在稼働中のbackendのサーバー数を返します。

設定例:backend のサーバーの生存台数が2台であれば、それらに振り分ける。

frontend db_front
        bind :3306
        acl is_db_backend nbsrv(db_backend) eq 2
        use_backend db_backend if is_db_backend

backend db_backend
       mode tcp
       balance roundrobin
       option mysql-check
       server db1 192.168.0.1:3306 check rise 1 fall 3
       server db2 192.168.0.2:3306 check rise 1 fall 3

frontendブロックにて、aclキーワードを使用し、is_db_backendというACLを定義します。

acl is_db_backend nbsrv(db_backend) eq 2

このとき is_db_backendは、db_backendというbackendブロックの生きているサーバー数が"2"であるか?という意味を持ちます。nbsrvは数値を返すので、「eq 2」などとして数値で比較をする必要があります。
その次の行の、

use_backend db_backend if is_db_backend

で、どのbackendサーバーを使用するかという設定になります。※今回は、backendが一つしかないですが、複数定義することが可能となっています。
このときの使用条件で、is_db_backend の値を参照していて、if キーワードで is_db_backend が"2"であるかどうかを判定しています。db_backend のサーバーが全て生きていたら、db_backend のサーバーを使用します。もし、db_backend のサーバーが一つでも落ちていたら、db_backendは使用されません。
また条件を変えて、

nbsrv(db_backend) ge 1

とすれば、1つでも生きていたらという意味になるかと思います。
ちなみに、

acl is_db_backend nbsrv(db_backend) eq 2
use_backend db_backend if is_db_backend

を1行で書くとこうなります。

use_backend db_backend if { nbsrv(db_backend) eq 2 }

"{","}"を使用して記述します。※"{","}"の前後にスペースが必要です。

srv_is_up

指定されたサーバーが生きていたらTRUE、それ以外であればFALSEという結果を返します。

設定例:あるbackendのサーバーが生きていれば、そのサーバーを主系として振り分ける。

frontend db_front
        bind :3306
        acl is_db1_up srv_is_up(db_backend1/db1)
        acl is_db2_up srv_is_up(db_backend2/db2)
        use_backend db_backend1 if is_db1_up
        use_backend db_backend2 if is_db2_up

backend db_backend1
       mode tcp
       option mysql-check
       server db1 192.168.0.1:3306 check rise 1 fall 3

backend db_backend2
       mode tcp
       option mysql-check
       server db2 192.168.0.2:3306 check rise 1 fall 3

まず、frontend ブロックでの

acl is_db1_up srv_is_up(db_backend1/db1)
acl is_db2_up srv_is_up(db_backend2/db2)

の部分で2つのACLを定義しました。上の方は、db_backend1のdb1というサーバーがあがっているかどうかを定義し、下の方は、db_backend2のdb2というサーバーがあがっているかどうかを定義しています。
サーバーがあがっているかどうかの判定部分は、

srv_is_up(db_backend1/db1)

の部分になります。そして、次の2行で、

use_backend db_backend1 if is_db1_up
use_backend db_backend2 if is_db2_up

どのbackendサーバーを使用するかを定義しています。ここで2つuse_backendというキーワードを使っていて、どのbackendを利用するかという疑問があるかと思いますが、上に記述された方から先に評価をしていき、条件が満たされるものがあればそれを使用していくという動きになっています。
is_db1_upがTRUEであれば、db_backend1のサーバーを使います。もし、db_backendのdb1サーバーが落ちていた場合は、次の行のis_db2_upが評価され、db_backend2が使用されるか判定されます。
評価の方法は、nbsrvの記述部分と同じで、ifキーワードを利用しています。

src

HAProxyに接続してきているIPアドレスを意味する

設定例:特定のIPアドレス(192.168.0.1)からの接続は、サーバーAに振り分け、それ以外はサーバーBに振り分ける

rontend web_front
        bind :80
        acl is_src src 192.168.0.1
        use_backend web_a if is_src
        use_backend web_b unless is_src

backend web_a
       mode http
       server web1 192.168.0.2:80 check rise 1 fall 1
       option httpchk

backend web_b
       mode http
       server web2 192.168.0.3:80 check rise 1 fall 1
       option httpchk

接続してきたIPアドレスが、「192.168.0.1」であるかどうかを判定し、use_backend キーワードで振り分けを実現しています。unless は、if の反対の意味を持ちます。

acl is_src src 192.168.0.1
use_backend web_a if is_src
use_backend web_b unless is_src

src_port

src がIPアドレスに対し、こちらはポートによる設定が可能。

dst

HAProxy側のIPアドレスを意味する。
※使用するケースとして、HAProxyが稼働しているサーバーに複数のIPが割り当てられているときに使用するようなケースだと思ってます。

設定例:IPアドレスAで接続してきたリクエストは、サーバーAへ。IPアドレスBで接続してきたリクエストは、サーバーBへ振り分ける。

rontend web_front
        bind :80
        acl is_dst dst 192.168.0.1
        acl is_dst_local dst 127.0.0.1
        use_backend web_a if is_dst
        use_backend web_b if is_dst_local

backend web_a
       mode http
       server web1 192.168.0.2:80 check rise 1 fall 1
       option httpchk

backend web_b
       mode http
       server web2 192.168.0.3:80 check rise 1 fall 1
       option httpchk

この設定の場合、「192.168.0.1」でリクエストした場合は、サーバーAへ振り分けられます。また、ローカルホストから「127.0.0.1」でリクエストした場合は、サーバーBへ振り分けられます。
srcもそうですが、違うネットワーク同士で振り分けを変えたいときに使えるか思います。

dst_port

dst がIPアドレスが対象なのに対し、こちらはポートによる設定が可能。

be_conn

backend で確立された(established)コネクションの接続数が適用されます。

設定例:一定の接続数を超えたら、エラーページにリダイレクトさせる。

backend web1
       mode http
       server web1 172.16.1.129:80 check rise 1 fall 3 
       acl is_be_conn be_conn gt 1 # テストのため"1"を設定
       option httpchk
       redirect location /error.html if is_be_conn

backendセクション内でaclキーワードで"1"を超える接続というACLを定義。超えたときの振る舞いとして、reirectキーワードでACLを評価するように定義しておく。
(サイズ重めの画像をWebサーバー上に配置しておき、それをブラウザで強制リロードをすばやく2度やると、リダイレクトされることを確認しました。)

他にも接続数、単位時間でのセッション作成数といったリクエスト数に応じたCriteriaもいくつかあるようです。
 =>"fe_conn", "queue" , "be_sess_rate" , "fe_sess_rate"


ここまでのものは下位のレイヤーの話のものなので、上位のレイヤーになれば高度なことができるようです。
 =>HTTPヘッダの内容でACLを定義、等。


ここに書いたことは本当に一部分にすぎないので、もっと有効な使い方があるかと思いますが、HAProxyはかなり高機能でお手軽に負荷分散や可用性を高めることが可能なのでおすすめです。