KeepalivedとHAProxyによるMySQL高可用性(HA)環境の構築手順:Virtual IP(VIP)の自動フェイルオーバー

MySQL tutorial - IT technology blog
MySQL tutorial - IT technology blog

1. MySQLの高可用性(HA)構成パターンの比較

本番環境でデータベースサーバーを1台のみ運用することは、いわば時限爆弾を抱えているようなものです。ディスクの高負荷やネットワークの輻輳、OSパッチ適用のための再起動だけでも、サービス全体が即座に停止してしまいます。99.9%のSLA(稼働率)を維持するため、インフラチームは通常、以下の4つのアプローチから選択します。

  • DNSフェイルオーバー: 1つのDNSレコードに複数のIPを紐付け、障害時にIPを切り替える手法。
  • 単一HAProxy(Single LB): MySQLクラスタの前面に1台のHAProxyを配置し、接続のバランシングやヘルスチェックを行う手法。
  • Keepalived + HAProxy(Virtual IPを用いたActive-Passive構成): VRRP(Virtual Router Redundancy Protocol)プロトコルを介して2台のHAProxyノードを並行稼働させ、Virtual IP(VIP)を共有する手法。Activeノードがダウンすると、VIPが自動的にPassiveノードへフェイルオーバーします。
  • MySQL InnoDB Cluster / Galera Cluster: マルチマスターの同期クラスタであり、データベースエンジン層で新しいノードを自動選出する手法。

2. 各ソリューションのメリット・デメリット

万能なソリューションは存在しません。要件やシステム規模に適した手法を選択することが重要です。

DNSフェイルオーバー

  • メリット: 設定が非常に容易で、複雑なクラスタ管理ツールの追加導入が不要。
  • デメリット: クライアント側のTTLやDNSキャッシュに完全に依存します。サーバー停止時、クライアントが新しいIPを認識するまでに通常5〜15分(ISPによっては数時間)かかり、長時間のダウンタイムが発生します。

単一HAProxy

  • メリット: インテリジェントなルーティングが可能で、TCP層(レイヤー4)での正確なMySQLヘルスチェックを実行できます。
  • デメリット: 単一障害点(SPOF)となります。背後のMySQLクラスタが正常に稼働していても、HAProxyがダウンするとアプリケーション全体の接続が切断されます。

MySQL InnoDB Cluster / Galera Cluster

  • メリット: リアルタイムでデータを同期し、ノード間の完全な整合性を保証します。
  • デメリット: 運用が非常に複雑でリソース消費も大きくなります。書き込みトラフィックが高い環境ではデッドロックが発生しやすくなります。また、スプリットブレイン対策として最低3ノードが必要です。

Keepalived + HAProxy(Virtual IP)

  • メリット: フェイルオーバーが極めて高速(1〜2秒未満)。HAProxyの単一障害点問題を完全に解消します。非常に軽量で、従来のMySQL Master-Replica構成とも相性抜群です。
  • デメリット: VRRPプロトコルを正常に機能させるため、内部ネットワーク環境がマルチキャストまたはユニキャストのパケット転送をサポートしている必要があります。

3. 中小規模システムにKeepalived + HAProxyが最適な理由

中小規模のシステムにおいて、Keepalived + HAProxy構成はコストパフォーマンスに極めて優れています。3〜5ノードの大規模なクラスタを管理・維持する必要はありません。バックエンドアプリケーションは単一の接続先であるVirtual IP(VIP)のみを指定すれば十分です。

ノードの監視、クエリのルーティング、障害サーバーの切り離しはシステムが自動的に処理します。実際、約1,500 QPSを処理するMySQL環境において、このアーキテクチャではメインノードの障害時に約800msでフェイルオーバーを完了し、ユーザー側の502/504エラーを完全に防ぐことができました。

4. ステップバイステップ導入手順

今回は、同一LAN内にある2台のUbuntu/Debianサーバーを使用した実践例を紹介します。

  • Node 1(Primary LB / MySQL Master): IP 192.168.1.10
  • Node 2(Backup LB / MySQL Replica): IP 192.168.1.11
  • Virtual IP(共有VIP): 192.168.1.100(アプリケーションはこのIPに接続)

ステップ1:MySQLヘルスチェック用ユーザーの作成

両方のノードでMySQLにログインし、HAProxyのヘルスチェック専用ユーザーを作成します。このユーザーにデータアクセスの権限は不要です。

mysql -u root -p -e "CREATE USER 'haproxy_check'@'%' IDENTIFIED BY ''; FLUSH PRIVILEGES;"

ステップ2:HAProxy、Keepalivedおよびユーティリティツールのインストール

両方のサーバーでインストールコマンドを実行します。

sudo apt update
sudo apt install -y haproxy keepalived psmisc

ステップ3:HAProxyの設定

両ノードの /etc/haproxy/haproxy.cfg を開き、ポート3306のプロキシ設定を追加します。

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon

defaults
    log global
    mode tcp
    option tcplog
    option dontlognull
    retries 3
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend mysql_front
    bind *:3306
    mode tcp
    default_backend mysql_back

backend mysql_back
    mode tcp
    option mysql-check user haproxy_check
    server db01 192.168.1.10:3306 check inter 2000 rise 2 fall 3
    server db02 192.168.1.11:3306 check backup inter 2000 rise 2 fall 3

HAProxyを再起動し、自動起動を有効化します。

sudo systemctl restart haproxy
sudo systemctl enable haproxy

ステップ4:Virtual IPを管理するKeepalivedの設定

まず、ネットワークインターフェースがまだそのIPを保持していなくても、カーネルがVIPにバインドできるように設定します。

echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

両サーバーの /usr/local/bin/check_haproxy.sh にHAProxyプロセスの監視スクリプトを作成します。

cat << 'EOF' | sudo tee /usr/local/bin/check_haproxy.sh
#!/bin/bash
killall -0 haproxy
EOF

sudo chmod +x /usr/local/bin/check_haproxy.sh

Node 1(Master) の /etc/keepalived/keepalived.conf を設定します。

vrrp_script check_haproxy {
    script "/usr/local/bin/check_haproxy.sh"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 101
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass SecretHAProxyPass123
    }

    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }

    track_script {
        check_haproxy
    }
}

Node 2(Backup) の /etc/keepalived/keepalived.conf を設定します(priorityを100に下げます)。

vrrp_script check_haproxy {
    script "/usr/local/bin/check_haproxy.sh"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass SecretHAProxyPass123
    }

    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }

    track_script {
        check_haproxy
    }
}

両サーバーでKeepalivedサービスを起動・有効化します。

sudo systemctl restart keepalived
sudo systemctl enable keepalived

ステップ5:実際のフェイルオーバー動作確認

Node 1で現在のIP割り当てを確認します。

ip addr show eth0

Virtual IP 192.168.1.100 がNode 1の eth0 インターフェースに割り当てられていることが確認できます。ここで障害をシミュレートするため、Node 1のHAProxyサービスを停止してみます。

sudo systemctl stop haproxy

Node 2のターミナルを開き、再度IPを確認します。

ip addr show eth0

Virtual IP 192.168.1.100 が瞬時にNode 2へと引き継がれました。192.168.1.100:3306 に接続しているアプリケーションは、手動での対応やソースコードの設定変更を行うことなく、クエリの送受信を継続できます。

Share: