スマートスタイル TECH BLOG

データベース&クラウド技術情報

HAProxy のバックエンド接続ルーティングを動的に変更する方法

はじめに

今回は軽量・高性能で現在でも人気のあるプロキシソフトウェア HAProxy に関する話題です。

HAProxy – The Reliable, High Performance TCP/HTTP Load Balancer

データベースを運用していると、システムメンテナンスや問題・障害が発生した時に、特定のデータベースへのアクセスを行わないように制御する必要性が出てくる場合があると思います。

この時、プロキシソフトウェアを使用しているのであれば、当然ながらアプリケーションやデータベースを変更せずにプロキシソフトウェアのみでルーティングの切替え(アクセス制御)を行うことが期待されます。

その際の HAProxy での制御方法について、簡単に紹介したいと思います。

今回確認に用いた環境やバージョンなど

HAProxy サーバ

  • Rocky Linux release 8.6 (Green Obsidian)
  • HAProxy version 2.6.6-274d1a4 2022/09/22 – https://haproxy.org/
    • ソースビルド

MySQL

  • Rocky Linux release 8.6 (Green Obsidian)
  • MySQL Ver 8.0.30 for Linux on x86_64 (MySQL Community Server – GPL)
    • 公式 Yum リポジトリからインストール

バックエンドの変更可能な3つの状態と設定コマンド

HAProxy では、待ち受けおよび接続先グループの設定を frontend で、接続先サーバの設定を backend というディレクティブで設定できます。

MySQL レプリケーション(ソース:1台,レプリカ:2台)構成の例となりますが、下記の設定の場合、

  • HAProxy 導入サーバの 3306 ポート宛通信はソースサーバへルーティング
  • HAProxy 導入サーバの 3307 ポート宛通信は全サーバへルーティング

という制御となります。

実際に HAProxy を稼働させた状態で統計情報からバックエンドの状態を確認してみます。

正常稼働中ですので、status:UP になっていますね。

HAProxy で変更可能なバックエンドステータスは DOWN を除くと3つ存在します。

公式ドキュメントの設定コマンドの説明に各ステータスについて記載ありますので引用します。

HAProxy version 2.6.6-35 – Management Guide | 9.3. Unix Socket commands | set server

set server <backend>/<server> state [ ready | drain | maint ]

Force a server’s administrative state to a new state. This can be useful to disable load balancing and/or any traffic to a server.
Setting the state to "ready" puts the server in normal mode, and the command is the equivalent of the "enable server" command.
Setting the state to "maint" disables any traffic to the server as well as any health checks.
This is the equivalent of the "disable server" command.
Setting the mode to "drain" only removes the server from load balancing but still allows it to be checked and to accept new persistent connections.
Changes are propagated to tracking servers if any.

  • ready は UP ステータスにすることができ、enable server と同義です。
  • maint はすべてのトラフィックとヘルスチェックを無効にし、disable server と同義です。
    • 意図的な DOWN 状態となります。
  • drain はルーティング対象から外されますが、ヘルスチェックや既存のTCP持続的接続はそのまま許可します。

バックエンドの特定のサーバをルーティング対象外に変更するには、ステータスを maint または drain に変更することで実現可能となります。

どちらを使うのかは、目的や状況次第で使い分けることになります。

それぞれの挙動を確認してみましょう。

maint(メンテナンス)状態に移行する場合

レプリカサーバ mysql-80-r3 へのルーティングを行わないようにしたいと思います。

(表示が前後しますが) 読み取り専用のトランザクション実行中に MAINT ステータスへの変更を発行しました。

SELECT を実行中の処理では、HAProxy 側で MAINT ステータスに変更した直後にコネクション切断エラーが発生しました。

MAINT ステータスへ変更時、HAProxy ログには以下のように記録されます。

元の通常状態に復帰させるには、set server ... state ready または enable server(以下例)を実行します。

復帰時は HAProxy ログには以下のように記録されます。

メンテナンス作業開始前に、既存接続は強制的に切断してもよい、実行中のトランザクションは中断して問題ないという場合は maint を使用するのがよいでしょう。

drain(ドレイン)状態に移行する場合

今度は mysql-80-r2 をルーティング除外対象としてみます。

前述と同じ読み取り専用トランザクションを実行中に DRAIN ステータスに変更しました。

DRAIN ステータス変更後も接続断となることなく、結果既存接続のトランザクション処理は正常に完了しました。

このとき新規接続を行ってみると、想定通り以下のエラーで接続失敗します。(アクセス拒否で制御しているのですね)

DRAIN ステータス変更時、HAProxy ログには以下のメッセージが記録されます。

ステータスの戻しは maint の時と同一です。

復帰すると HAProxy ログには以下のメッセージが記録されます。

今回の例では標準のレプリケーション構成におけるレプリカサーバのルーティングが対象でしたが、
グループレプリケーションのマルチプライマリーモードや Galera Cluster/Percona XtraDB Cluster、NDB Cluster といった、更新処理を複数ノードで分散実行している環境だったり、実行中のトランザクションの完了を待ってから新規接続を受け付けないようにする際に使用するステータスと言えます。

なお、DRAIN のあとに MAINT に移行することも可能です。

注意点としては、手動でステータスを変更している状態で、HAProxy のコンフィグリロードを行ってしまうと元の UP の状態に戻ってしまうということです。
一時的な設定変更をジョブや構成管理ツールなどで自動設定するようにしている場合、ルーティングされないはずのサーバへ接続が行われてしまい一大事になりかねませんので、そのような処理が裏で行われないように気を付けてください。

weight を 0 にする方法

その他の方法として、バックエンドへの接続ロードバランシングの重み(weight)設定を 0 にすると、DRAIN ステータスと同じ効果を得ることができます。

HAProxy version 2.6.6-35 – Configuration Manual | 5.2. Server and default-server options | weight

(…)
The default weight is 1, and the maximal value is 256. A value of 0 means the server will not participate in load-balancing but will still accept persistent connections.
(…)

weight は CLI コマンド(set server ... weight 0 または set weight ... 0)で動的に設定変更できますが、
設定ファイル内の backend ディレクティブで、特定のサーバのオプションとしても静的に設定することができます。

HAProxy 1.8 以降は シームレスリロード、つまり接続断やダウンタイムを発生させずに設定の更新を反映させることができます。
systemd ベースで起動させる(USE_SYSTEMD=1でビルドしている)場合、-Ws オプション付与で起動されるのでデフォルトで有効になっています。

シームレスリロードの詳細については以下の公式ブログ記事をご参照ください。

Announcing HAProxy 2.6 – HAProxy Technologies
Hitless Reloads with HAProxy – HOWTO – HAProxy Technologies

つまり任意の接続先サーバに対してweight 0 と設定ファイルを更新し HAProxy をリロードすることで、DRAIN ステータス同等のルーティング制御を行い、かつ、前述の注意点の回避策として不慮のコンフィグリロードによるステータスのクリアを防ぐことができます。

  1. 設定ファイルを更新します。(例:mysql-80-r2 の weight を 0 に変更)

  2. HAProxy のリロードを実行します。

まとめ

HAProxy のバックエンド接続のステータスを手動変更することでルーティング制御(遮断)を行う方法を紹介しました。

maint(メンテナンス)またはdrain(ドレイン)、それぞれのステータスで既存接続の扱いが異なりますので、メンテナンスや切替え作業時の状況に応じて使い分けていただければと思います。

Return Top