HAProxyを使用してMySQL負荷分散を設定する方法
プレリュード
HAProxyは、HTTPサーバーとTCPサーバーの負荷を分散できるオープンソースソフトウェアです。 HAProxy に関する以前の記事では、HTTPの負荷分散を構成しましたが、今回はMySQLでも同じことを行います。 負荷分散にはすべてのバックエンドへの読み取りと書き込みの両方が含まれるため、すべてのMySQLサーバーはマスター-マスターレプリケーションを実行するように構成する必要があります。
この記事では、次の3つの液滴を使用します。
ドロップレット1-ロードバランサーホスト名:haproxy OS:UbuntuプライベートIP:10.0.0.100
ドロップレット2-ノード1ホスト名:mysql-1 OS:Debian 7プライベートIP:10.0.0.1
ドロップレット2-ノード2ホスト名:mysql-2 OS:Debian 7プライベートIP:10.0.0.2
続行する前に、すべてのMySQLサーバーが稼働中であり、データベース書き込みを適切に複製していることを確認してください。
MySQLサーバーを準備する
HAProxy用に2人の追加ユーザーを作成して、MySQLサーバーを準備する必要があります。 最初のユーザーは、サーバーのステータスを確認するためにHAProxyによって使用されます。
root@mysql-1# mysql -u root -p -e "INSERT INTO mysql.user (Host,User) values ('10.0.0.100','haproxy_check'); FLUSH PRIVILEGES;"
HAProxyからMySQLクラスターにアクセスする場合は、root権限を持つMySQLユーザーが必要です。 すべてのサーバーのデフォルトのrootユーザーは、ローカルでのみログインできます。 これはrootユーザーに追加の権限を付与することで修正できますが、root権限を持つ別のユーザーを用意することをお勧めします。
root@mysql-1# mysql -u root -p -e "GRANT ALL PRIVILEGES ON *.* TO 'haproxy_root'@'10.0.0.100' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES"
haproxy_rootとpasswordを独自の安全な値に置き換えます。 変更は他のマスターに複製されるため、1つのMySQLマスターでこれらのクエリを実行するだけで十分です。
MySQLクライアントをインストールします
接続をテストするには、MySQLクライアントをHAProxyドロップレットにインストールする必要があります。
root@haproxy# apt-get install mysql-client
次に、マスターの1つでhaproxy_rootユーザーとしてクエリを実行してみます。
root@haproxy# mysql -h 10.0.0.1 -u haproxy_root -p -e "SHOW DATABASES"
これにより、MySQLデータベースのリストが表示されます。
HAProxyのインストール
HAProxyサーバーにパッケージをインストールします。
root@haproxy# apt-get install haproxy
initスクリプトによってHAProxyを開始できるようにします。
root@haproxy# sed -i "s/ENABLED=0/ENABLED=1/" /etc/default/haproxy
この変更が適切に行われたかどうかを確認するには、パラメータなしでHAProxyのinitスクリプトを実行します。
root@haproxy:~# service haproxy
Usage: /etc/init.d/haproxy {start|stop|reload|restart|status}
HAProxyの設定
元の構成ファイルの名前を変更します
mv /etc/haproxy/haproxy.cfg{,.original}
新しいものを作成して編集します
nano /etc/haproxy/haproxy.cfg
最初のブロックは、グローバルおよびデフォルトの構成ブロックです。
global
log 127.0.0.1 local0 notice
user haproxy
group haproxy
defaults
log global
retries 2
timeout connect 3000
timeout server 5000
timeout client 5000
これらの各オプションの詳細については、この記事を参照してください。 HAProxyにログメッセージを127.0.0.1に送信するように指示したので、それをリッスンするようにrsyslogを構成する必要があります。 これは、同じ記事のHAProxyのロギングの構成でも取り上げられています。
メイン構成部分に移動します。
listen mysql-cluster
bind 127.0.0.1:3306
mode tcp
option mysql-check user haproxy_check
balance roundrobin
server mysql-1 10.0.0.1:3306 check
server mysql-2 10.0.0.2:3306 check
HTTP負荷分散とは異なり、HAProxyにはMySQL用の特定の「モード」がないため、tcpを使用します。 HAProxyをループバックアドレスでのみリッスンするように設定しました(アプリケーションが同じサーバー上にあると想定)が、アプリケーションが別のドロップレットにある場合は、0.0.0.0またはプライベートIPアドレスでリッスンします。
負荷分散の統計を表示するには、もう1つの構成ブロックが必要です。 これは完全にオプションであり、統計が必要ない場合は省略できます。
listen 0.0.0.0:8080
mode http
stats enable
stats uri /
stats realm Strictly\ Private
stats auth A_Username:YourPassword
stats auth Another_User:passwd
「statsauth」のユーザー名とパスワードを置き換えます。 これにより、HAProxyはポート8080 でHTTP要求をリッスンし、統計はHTTP基本認証で保護されます。 だからあなたはで統計にアクセスすることができます
http://<Public IP of Load Balancer>:8080/
設定が完了したら、HAProxyサービスを開始します。
service haproxy start
mysqlクライアントを使用してHAProxyにクエリを実行します。
root@haproxy# mysql -h 127.0.0.1 -u haproxy_root -p -e "SHOW DATABASES"
「-h」オプションは、ループバックIPアドレスとともに存在する必要があります。 これを省略するか、 localhost を使用すると、MySQLクライアントが mysql.sock ファイルに接続し、失敗します。
負荷分散とフェイルオーバーのテスト
負荷分散が機能しているかどうかを確認するには、server_id変数を2回以上クエリします。
root@haproxy# mysql -h 127.0.0.1 -u haproxy_root -p -e "show variables like 'server_id'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 1 |
+---------------+-------+
root@haproxy# mysql -h 127.0.0.1 -u haproxy_root -p -e "show variables like 'server_id'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
これは、等しい重みでのラウンドロビン負荷分散を示しています。次に、 mysql-2 の重みを変更して、結果を確認します。
nano /etc/haproxy/haproxy.cfg
server mysql-2 10.0.0.2:3306 check weight 2
この変更を適用するには、リロードしてください。
service haproxy reload
server_idを複数回クエリします。
root@haproxy:~# for i in `seq 1 6`
do
mysql -h 127.0.0.1 -u haproxy_root -ppassword -e "show variables like 'server_id'"
done
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 1 |
+---------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 1 |
+---------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
現在、負荷分散は 1:2 の比率で機能し、リクエストの3分の1がmysql-1に送信され、3分の2がmysql-2に送信されます。
サービスを停止してMySQLサーバーに障害を発生させる
root@mysql-1# service mysql stop
またはインターフェイスを停止します。
root@mysql-1# ifconfig eth1 down
今すぐ「変数の表示」クエリを試して、結果を確認してください。 次のログエントリは、HAProxyがいつどのように障害を検出したかを示します。
tail /var/log/haproxy/haproxy.log
Nov 15 00:08:51 localhost haproxy[1671]: Server mysql-cluster/mysql-1 is DOWN, reason: Layer4 timeout, check duration: 2002ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
フェイルオーバー間隔の短縮
MySQLサーバーがダウンすると、HAProxyはこの障害を検出し、クラスターから削除するのに時間がかかります。 このセクションでは、今回の制御方法を説明します。 まず、この値を測定する方法を見ていきます。 1つの方法は、 iptables を使用してMySQLポートを一定時間ブロックしてから、ルールを削除してログを確認することです。
root@mysql-1:~# ifconfig eth1 down &&
date &&
sleep 20 &&
ifconfig eth1 up &&
date
Fri Nov 15 00:37:09 IST 2013
Fri Nov 15 00:37:29 IST 2013
ポート3306は20秒間ブロックされました。ここで、ログファイルを確認します。
root@haproxy:~# tail /var/log/haproxy.log
Nov 15 16:49:38 localhost haproxy[1275]: Server mysql-cluster/mysql-1 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
Nov 15 16:49:56 localhost haproxy[1275]: Server mysql-cluster/mysql-1 is UP, reason: Layer7 check passed, code: 0, info: "5.5.31-0+wheezy1-log", check duration: 1ms. 2 active and 0 backup servers online. 0 sessions requeued, 0 total in queue.
障害の検出には6秒(16:49:38と16:49:32の差)、サーバーに到達できることの検出には4秒(16:49:56と16:49:52の差)かかりました。 これは、サーバーパラメーターのrise、fall、およびinterによって決定されます。
rise パラメーターは、operationを宣言するためにサーバーが通過する必要のあるチェックの数を設定します。 デフォルトは2です。
fall パラメーターは、deadを宣言するためにサーバーが通過する必要のあるチェックの数を設定します。 デフォルトは3です。
inter パラメーターは、これらのチェックの間隔を設定します。 デフォルトは2000ミリ秒です。
この情報をまとめると、サーバーは 3 の継続的なチェックに失敗する必要があります。このチェックは、2秒の間隔で実行されて停止していると見なされます。 したがって、上記の例では、次のことが起こります。
16:49:32 - Port 3306 on mysql-1 was blocked
16:49:34 - Check - Failed - Failure No. 1
16:49:36 - Check - Failed - Failure No. 2
16:49:38 - Check - Failed - Failure No. 3 (server removed and event logged)
そして、ファイアウォールルールが削除されたとき。
16:49:52 - Firewall rule removed port 3306 accessible
16:49:54 - Check - Passed - Success No. 1
16:49:56 - Check - Passed - Success No. 2 (server added to cluster and event logged)
次の設定により、テスト間隔が1秒に短縮され、落下テストの数も削減されます。
nano /etc/haproxy/haproxy.cfg
server mysql-1 10.0.0.1:3306 check fall 2 inter 1000
server mysql-2 10.0.0.2:3306 check fall 2 inter 1000
特に大量のMySQLサーバーがある場合は、プライベートネットワークをあまりにも多くの「テスト」パケットで溢れさせたくない場合があります。 このような場合、fastinterおよびdowninterパラメーターが便利です。
fastinter パラメーターは、サーバーがUPまたはDOWNに移行している間のチェックの間隔を設定します。
downinter パラメーターは、サーバーがダウンしているときのテスト間隔を設定します。
その説明は紛らわしいかもしれないので、例を挙げて見ていきます。
nano /etc/haproxy/haproxy.cfg
server mysql-1 10.0.0.1:3306 check fastinter 1000
server mysql-2 10.0.0.2:3306 check fastinter 1000
「inter」パラメータを指定していないため、デフォルトで2000msに設定されています。 この構成で、HAProxyを再起動し、テストを再実行します。
root@mysql-1:~# iptables -A INPUT -p tcp --dport 3306 -j REJECT &&
date &&
sleep 20 &&
iptables -D INPUT -p tcp --dport 3306 -j REJECT &&
date
Fri Nov 15 17:18:48 IST 2013
Fri Nov 15 17:19:08 IST 2013
HAProxyログファイルを確認してください。
root@haproxy:~# tail /var/log/haproxy.log
Nov 15 17:18:52 localhost haproxy[1353]: Server mysql-cluster/mysql-1 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
Nov 15 17:19:11 localhost haproxy[1353]: Server mysql-cluster/mysql-1 is UP, reason: Layer7 check passed, code: 0, info: "5.5.31-0+wheezy1-log", check duration: 1ms. 2 active and 0 backup servers online. 0 sessions requeued, 0 total in queue.
これで、障害を検出するのに4秒(以前の6秒と比較して)、サーバーが稼働していることを検出するのに3秒(4秒と比較して)しかかかりませんでした。 舞台裏でこれが起こったことです。
17:18:48 - Port 3306 blocked
17:18:50 - Check - Failed - Failure No. 1
17:18:51 - Check - Failed - Failure No. 2
17:18:52 - Check - Failed - Failure No. 3 (server removed and event logged)
そして、ポートのブロックが解除されたとき。
17:19:08 - Firewall rule removed
17:19:10 - Check - Passed - Success No. 1
17:19:11 - Check - Passed - Success No. 2 (server added to cluster and event logged)
最初に、ポートブロックイベント(17:18:48)と最初のチェック(17:18:50)の間の間隔に注意してください。これは、2秒(「インター」間隔)です。 次に、テスト1<->テスト2とテスト2<->テスト3の間の間隔がわずか1秒(「fastinter」間隔)であることに注意してください。 サーバーがDOWNからUPに移動したときにも、同じ間隔に気付くことができます。 したがって、「fastinter」はこれらのチェックの間隔を制御します。
では、ダウンインターとは何ですか? サーバーが宣言されると、 DOWN HAProxyは2秒ごと(またはinterに記載されている間隔)にサーバーのチェックを続行します。 不要なネットワークリソースを使い果たしていると思われる場合は、 downinter を5000に設定すると、HAProxyは5秒に1回だけDOWNサーバーをチェックします。
重要
以前に行ったテストでは、パケットが拒否されました。つまり、HAProxyがSYNパケットを mysql-1 に送信して接続を開始すると、(SYN + ACKではなく)RSTパケットを受信しました。 これが、ログエントリに「接続が拒否されました」と記載されている理由です。 この場合、fall、inter、fastinterの値のみがシーンに入ります。
代わりに、SYNを送信した後にHAProxyが何も受信しなかった場合、接続がタイムアウトします。 この場合、上記のパラメータに加えて、「タイムアウト」期間がシーンに入ります。 この状況は、次の場合に発生する可能性があります
- iptablesはDROPに設定されています
- プライベートインターフェイスがダウンしています
- プライベートネットワークインフラストラクチャに問題があります
参考文献
公式ドキュメントhttp://cbonte.github.io/haproxy-dconv/configuration-1.4.html