mysqlfailoverとは?
mysqlfailover はOracle社が提供している MySQL Utilities というツール群の中の1つです。
下記の図のようにレプリケーション構成において、マスターに障害が発生した場合、スレーブをマスターに切り替えるフェイルオーバー処理を自動で行うツールです。
検証MySQL環境構築
今回の検証ではdockerを使って マスター1台(node1)、スレーブ2台(node2, node3)、mysqlfailoverを実行するマシン(admin)の4インスタンス構成で行います。
設定ファイル
docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
version: '3' services: node1: image: mysql/mysql-server:5.7 environment: - MYSQL_ROOT_PASSWORD=password volumes: - "./node1.cnf:/etc/my.cnf" - "./init.sql:/docker-entrypoint-initdb.d/init.sql" - "./repl-master.sql:/docker-entrypoint-initdb.d/repl-master.sql" node2: image: mysql/mysql-server:5.7 environment: - MYSQL_ROOT_PASSWORD=password volumes: - "./node2.cnf:/etc/my.cnf" - "./init.sql:/docker-entrypoint-initdb.d/init.sql" - "./repl-slave.sql:/docker-entrypoint-initdb.d/repl-slave.sql" node3: image: mysql/mysql-server:5.7 environment: - MYSQL_ROOT_PASSWORD=password volumes: - "./node3.cnf:/etc/my.cnf" - "./init.sql:/docker-entrypoint-initdb.d/init.sql" - "./repl-slave.sql:/docker-entrypoint-initdb.d/repl-slave.sql" admin: image: centos:7 command: ["/sbin/init"] |
init.sql (コンテナ作成時に実行されるSQL)
1 2 3 4 5 6 7 |
# レプリケーションユーザーの作成 CREATE USER 'repl'@'%' IDENTIFIED BY 'repl'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; # モニタリングユーザーの作成 CREATE USER 'mon'@'%' IDENTIFIED BY 'mon'; GRANT SUPER, GRANT OPTION, REPLICATION SLAVE, SELECT, RELOAD, DROP, CREATE, INSERT ON *.* TO 'mon'@'%'; |
mysqlfailover の管理用ユーザーは全てのノードで必要です。また権限もSUPER, GRANT OPTION, REPLICATION SLAVE, RELOAD, DROP, CREATE, INSERT, SELECT と多岐にわたるため、rootユーザーを使ってもいいかもしれません。
レプリケーションユーザーについては、フェイルオーバー時にmysqlfailoverが必要なユーザーを作成してくれるはずでしたが、実際に試したところうまくいかなかったため、事前に全てのノードにレプリケーションユーザーを作ることにしました。
node1.cnf (my.cnf)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[mysqld] skip-host-cache skip-name-resolve datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock secure-file-priv=/var/lib/mysql-files user=mysql symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid # レプリケーション設定 server-id=1 # ノードごとに値を変える gtid-mode=ON log-bin log-slave-updates enforce-gtid-consistency # mysqlfailoverで必要な設定 report-host=node1 # ノードごとにノード名を記載 report-port=3306 master-info-repository=TABLE |
残りの node2.cnf, node3.cnf も server-id と report-host が異なるだけで同じです。
mysqlfailoverでは、GTIDモードのレプリケーションのみ対応しています。
また、マスターからスレーブの情報を取得するため、report-host、report-port、master-info-repository=TABLEの設定が必要になります。
repl-master.sql
1 |
RESET MASTER; |
repl-slave.sql
1 2 3 |
RESET MASTER; CHANGE MASTER TO MASTER_HOST='node1', MASTER_USER='repl', MASTER_PASSWORD='repl', MASTER_AUTO_POSITION=1; START SLAVE; |
レプリケーション構築
まずはマスターのコンテナを起動します。
1 |
$ docker-compose up -d node1 |
ログは以下のコマンドで確認します。
1 |
$ docker-compose logs -f node1 |
マスタが起動したらスレーブも起動します。
1 |
$ docker-compose up -d node2 node3 |
MySQL Utilities のインストール
adminコンテナにログインします。
1 2 |
$ docker-compose up -d admin $ docker-compose exec admin /bin/bash |
MySQL Utilities をインストールするには、まず依存パッケージの mysql-connector-python をインストールします。
1 2 |
# curl -LO https://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-2.1.7-1.el7.x86_64.rpm # rpm -ivh mysql-connector-python-2.1.7-1.el7.x86_64.rpm |
mysql-utilities をインストールします。
1 2 |
# curl -LO https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-utilities-1.6.5-1.el7.noarch.rpm # rpm -ivh mysql-utilities-1.6.5-1.el7.noarch.rpm |
mysqlfailoverを実行する
admin ホストで以下のコマンドを実行してmysqlfailoverを実行します。
1 |
$ mysqlfailover --master=mon:mon@node1 --discover-slaves-login=mon:mon --force |
1 2 3 |
--master : マスターへの接続設定を記載します。 [ユーザー名]:[パスワード]@[ホスト名] --discover-slaves-login : 自動的にスレーブ情報を取得します [ユーザー名]:[パスワード] --force : 障害を検知したら自動でフェイルオーバーを実行する場合に設定します |
実行すると以下のような画面が表示され一定時間毎に更新されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
MySQL Replication Failover Utility Failover Mode = auto Next Interval = Thu Sep 21 09:08:42 2017 Master Information ------------------ Binary Log File Position Binlog_Do_DB Binlog_Ignore_DB 30e19899e21d-bin.000 154 GTID Executed Set None Replication Health Status +--------+-------+---------+--------+------------+---------+ | host | port | role | state | gtid_mode | health | +--------+-------+---------+--------+------------+---------+ | node1 | 3306 | MASTER | UP | ON | OK | | node2 | 3306 | SLAVE | UP | ON | OK | | node3 | 3306 | SLAVE | UP | ON | OK | +--------+-------+---------+--------+------------+---------+ Q-quit R-refresh H-health G-GTID Lists U-UUIDs |
マスターを停止してフェイルオーバーさせる
マスターノードを停止させます。
1 |
$ docker-compose kill node1 |
しばらくするとフェールオーバー処理が実行されます。
この時、複数スレーブの中から、マスターとの遅延が最も少ないスレーブがマスターとして選択されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Failover starting in 'auto' mode... # Candidate slave node2:3306 will become the new master. # Checking slaves status (before failover). # Preparing candidate for failover. # Creating replication user if it does not exist. # ERROR: ERROR: Cannot grant replication slave to replication user. # Stopping slaves. # Performing STOP on all slaves. # Switching slaves to new master. # Disconnecting new master as slave. # Starting slaves. # Performing START on all slaves. # Checking slaves for errors. # Failover complete. # Discovering slaves for master at node2:3306 Failover console will restart in 5 seconds. |
レプリケーションユーザーに権限が付与できなかったというエラーメッセージが表示されています。(詳細は後記)
1 |
# ERROR: ERROR: Cannot grant replication slave to replication user. |
でも、フェイルオーバーは成功しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
MySQL Replication Failover Utility Failover Mode = auto Next Interval = Mon Sep 25 07:01:49 2017 Master Information ------------------ Binary Log File Position Binlog_Do_DB Binlog_Ignore_DB 843fba139c8b-bin.000 403 GTID Executed Set 015422df-a1bf-11e7-be53-0242ac120003:1 Replication Health Status +--------+-------+---------+--------+------------+---------+ | host | port | role | state | gtid_mode | health | +--------+-------+---------+--------+------------+---------+ | node2 | 3306 | MASTER | UP | ON | OK | | node3 | 3306 | SLAVE | UP | ON | OK | +--------+-------+---------+--------+------------+---------+ Q-quit R-refresh H-health G-GTID Lists U-UUIDs |
node3 のスレーブステータスを見ると、node2 がマスターになるよう変更されています。
1 2 3 4 5 6 7 8 9 |
$ docker-compose exec node3 mysql -u root -ppassword -e "show slave status\G" mysql: [Warning] Using a password on the command line interface can be insecure. *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: node2 Master_User: repl Master_Port: 3306 Connect_Retry: 60 ...(省略)... |
デーモンモードで起動する
mysqlfailoverは –daemon オプションを付けるとデーモンモードで起動することができます。
1 |
$ mysqlfailover --master=mon:mon@node1 --discover-slaves-login=mon:mon --force --daemon=start --log=/tmp/mysqlfailover.log --pidfile=/tmp/mysqlfailover.pid |
1 2 3 |
--daemon=start : デーモンモードで起動する --log=ファイルパス : ログファイルパスを指定する(デーモンモードの場合は必須) --pidfile=ファイルパス : PIDファイルパス。指定しない場合は起動ディレクトリに作られる。 |
停止する場合は下記のコマンドになります。
1 |
$ mysqlfailover --daemon=stop |
「ERROR: ERROR: Cannot grant replication slave to replication user.」のエラーについて
エラーを出力しているのは下記のコードの部分のようです。
https://github.com/mysql/mysql-utilities/blob/08276b2258bf9739f53406b354b21195ff69a261/mysql/utilities/common/replication.py#L897-L901
1 2 3 4 5 |
try: self.exec_query(query_str) except UtilError: return (False, "ERROR: Cannot grant replication slave to " "replication user.") |
動作を確認すると、フェイルオーバー時に新しいマスターとなる node2 で以下のSQLを実行していました。
1 |
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'node2' IDENTIFIED WITH 'mysql_native_password' AS '<secret>' |
ちょっとよくわからないのが、node3 からレプリケーションを張るので、作るユーザーは repl@node3 が正しいと思われます。
また、mysqlfailoverから接続するユーザーの権限は付与しているので権限が付与できないことでエラーになっているのは理由がよくわかりません。
すでにレプリケーションユーザーが存在する場合はこの処理をスキップしてくれるようですが、ホスト名部分が % の場合は、別ユーザーとして認識しているようです。
mysqlfailover の制限事項
mysqlfailoverを使う上でいくつか制限事項があります。
- GTIDモードのレプリケーションのみ対応しています。
- mysqlfailover 自体の冗長化構成は取れません。
- フェイルオーバーを行う判断はマスターの状態のみのため、mysqlfailoverとマスターサーバー間のネットワークで問題があった場合、誤認する可能性があります。
まとめ
動作として若干疑問点があるため、本番環境に導入するのをためらってしまいますが、インストールも簡単なので、GTIDのレプリケーション構成であれば気軽に使い始めることができると思います。