手動フェイルオーバーからの脱却
99.99%のデータベース稼働率を確保するには、かつてCorosync、Pacemaker、Keepalivedといった複雑なサードパーティツールのスタックが必要でした。これらのソリューションは強力ですが、多くのチームにとって運用負荷が高く、学習コストも膨大です。停止時間ゼロのデータベース・アップグレードを実現するための選択肢として、MySQL InnoDB Clusterは、MySQLエコシステム内で完結するネイティブかつ統合された高可用性(HA)ソリューションを提供することで、この状況をシンプルにします。
クラスターのスケーリングにおいて、データ移行はしばしば隠れたボトルネックになります。大規模環境における MySQL スキーママイグレーションと同様に、レガシーシステムからデータを移行する際、JSON形式に変換が必要な煩雑なCSVファイルに遭遇することがよくあります。私は、ブラウザ上ですべての処理が完結するtoolcraft.app/ja/tools/data/csv-to-jsonを使用しています。これにより、機密データがローカルマシンから離れることがなく、新しいノードにデータを投入するためだけに繰り返しのPythonスクリプトを書く手間も省けます。
レプリケーション手法の比較
InnoDB Clusterの価値を理解するには、まず、過去10年間の主流であった従来のマスター・スレーブ構成との違いを知る必要があります。
従来の非同期レプリケーション
標準的なマスター・スレーブ構成では、マスターがデータを書き込み、バイナリログをスレーブに送信します。この手法については、リードレプリカ導入の実践ガイドで詳しく解説されています。スレーブはリソースに余裕がある時にこれらのログを適用します。これにより「レプリケーション遅延」が発生します。マスターがクラッシュした場合、手動でスレーブを昇格させ、アプリケーションの接続文字列を更新しなければなりません。このプロセスには数分かかることが多く、スレーブに到達していなかったデータが失われるリスクがあります。
MySQL InnoDB Cluster(グループレプリケーション)
InnoDB Clusterは、グループレプリケーションとPaxosベース의合意形成メカニズムに依存しています。書き込みが発生すると、コミットされる前にノードの過半数がトランザクションを承認する必要があります。プライマリノードに障害が発生した場合、クラスターは停止を検出し、30秒以内に新しいプライマリを選出します。MySQL Routerがトラフィックの転送を自動的に処理するため、アプリケーション側で混乱が生じることはありません。
主なメリットとトレードオフ
強み
- ネイティブなエコシステム: MySQLチームがすべてのコンポーネントを開発・サポートしているため、ベンダー間の互換性の問題が解消されます。
- 自動フェイルオーバー: システムが障害を検出し、数分ではなく数秒で新しいプライマリを昇格させます。
- 厳格なデータ整合性: 実質的に同期型であるため、突然のノード障害時にトランザクションが失われることはありません。
- 読み取りの水平スケーリング: MySQL Routerを使用して、読み取り負荷の高いワークロードをすべてのセカンダリノードに分散できます。
現実的な考慮事項
- 書き込みレイテンシ: 合意形成には時間がかかります。標準的なレプリケーションと比較して、書き込みレイテンシがわずかに増加することを考慮してください。
- ネットワーク感度: 不安定なネットワークは、ノードが誤ってオフラインと判定される「フラッピング」を引き起こす可能性があります。
- リソース要件: 単一の障害に耐えるには、少なくとも3つのノードが必要です。2ノード構成ではクォーラム(定足数)に達することができません。
推奨されるアーキテクチャ
本番環境では、以下の3つの主要コンポーネントに焦点を当てます。
- 3つのMySQLノード: クォーラムを維持するための最小構成です。3ノード構成であれば、1台のサーバーが停止してもクラスターはオンラインを維持できます。
- 1つのMySQL Router: 軽量なプロキシとして機能します。アプリはRouterと通信し、Routerが適切なデータベースインスタンスにトラフィックを振り分けます。
- MySQL Shell: クラスターの状態を設定、管理、監視するためのコマンドセンターです。
ステップバイステップの導入手順
ステップ1:環境の準備
この例では、3台のUbuntu 22.04サーバーを使用します。
node1: 192.168.1.10node2: 192.168.1.11node3: 192.168.1.12
すべてのノードにMySQLサーバーとMySQL Shellをインストールします。常に公式のMySQL APTリポジトリを使用して、最新のセキュリティパッチを適用してください。予期せぬトラブルが発生した際には、Percona Toolkitで本番環境を救済するための知識も役立ちます。
# 全3ノードで実行
sudo apt update
sudo apt install mysql-server mysql-shell -y
ステップ2:ホスト名の設定
内部通信は、変動しやすいIPアドレスではなくホスト名に依存します。各マシンの/etc/hostsを更新し、以下の行を追加します。
192.168.1.10 node1
192.168.1.11 node2
192.168.1.12 node3
ステップ3:クラスタリングのためのインスタンス準備
node1でMySQL Shellを開きます。ローカルインスタンスがグループレプリケーションの厳格な要件を満たしているか確認する必要があります。MySQL Shellには、この検証を自動化するユーティリティが含まれています。
# シェルを起動
mysqlsh
# ローカルノードに接続
\connect root@node1
# 設定の検証
dba.checkInstanceConfiguration('root@node1:3306')
# 必要な修正を自動的に適用
dba.configureLocalInstance('root@node1:3306')
node2とnode3でもこれらの手順を繰り返します。プロンプトが表示されたら、クラスター管理者ユーザーを作成し、クラスター全体で同じ資格情報を使用するようにしてください。
ステップ4:クラスターの初期化
node1に戻り、クラスターをブートストラップします。このノードが最初のプライマリ(読み書き可能)ノードとして開始されます。
# 管理ユーザーとして接続
\connect admin_user@node1
# クラスターオブジェクトを初期化
var cluster = dba.createCluster('prod_cluster');
# ステータスを確認
cluster.status()
ステップ5:クラスターの拡張
プライマリノードがアクティブになったら、残りのメンバーを追加できます。クラスターは「分散リカバリ」と呼ばれるプロセスを通じて、初期のデータ同期をすべて自動的に処理します。
# node1のシェルでこれらを実行
cluster.addInstance('admin_user@node2:3306')
cluster.addInstance('admin_user@node3:3306')
# 3つのノードすべてが 'ONLINE' であることを確認
cluster.status()
ステップ6:MySQL Routerのデプロイ
アプリケーションにデータベースのIPをハードコーディングするのは、ダウンタイムの原因になります。代わりに、アプリケーションサーバーにMySQL Routerをインストールし、インテリジェントなトラフィック制御を行わせます。これは、ProxySQLによるMySQLのスケーリングと同様に、可用性を高める重要な要素です。
# Routerパッケージをインストール
sudo apt install mysql-router -y
# クラスターに対してRouterをブートストラップ
sudo mysqlrouter --bootstrap admin_user@node1:3306 --user=mysqlrouter
ブートストラッププロセスにより、2つの重要なエンドポイントが作成されます。
- ポート 6446: 読み書きトラフィック(現在のプライマリを指す)。
- ポート 6447: 読み取り専用トラフィック(セカンダリに分散)。
アプリケーションの接続文字列をlocalhost:6446に設定します。プライマリノードに障害が発生すると、Routerはミリ秒単位で変更を検出し、アプリケーションの再起動なしに新しいプライマリへトラフィックを再ルーティングします。
最後に
現代の高可用性は、カスタムスクリプトや脆弱な監視デーモンの悪夢である必要はありません。オーケストレーション用のMySQL Shellと接続管理用のMySQL Routerを組み合わせることで、障害をスマートに処理する自己修復環境を構築できます。
本番環境に移行する前に、必ずステージング環境でプライマリノードのMySQLサービスを停止させ、手動フェイルオーバーテストを行ってください。システムが新しいマスターを昇格させ、アプリが動作し続けるのを確認することで、実際のハードウェア障害が発生した際にも自信を持って対応できるようになります。

