FAT47の底辺インフラ議事録

学んだことのメモ帳です

MySQL-MHAを利用してMySQLの自動フェイルオーバーを実現してみた

MySQL-MHA(MySQL Master High Availability)は、MySQLがダウンした時に自動的に他のMySQLサーバへ処理を引き継ぐことが可能になる、自動フェイルオーバー機能を実現したプロダクトです。
DeNAの松信嘉範氏が開発しており、オープンソースソフトウェアとして公開されています。
http://code.google.com/p/mysql-master-ha/

今回は以下の図のような構成で作成してみたいと思います。


このMySQL-MHAを利用することで[サーバA]に障害が発生してしまった場合は、以下のように自動的にフェイルオーバーを行ってくれます。

構築作業

まずは4台のサーバにMySQLをインストールしてください。
上図の通り各サーバは[サーバA][サーバB][サーバC][サーバZ]とします。

参考:
CentOS5.6にMySQL5.5.15をインストール

今回の手順では、CentOS5.7+MySQL5.5.16で検証しています。


[サーバA][サーバB][サーバC]での作業

ノード側MySQL-MHAの準備

私の環境ではncftpが入っていなかったので下記のメッセージが表示されました。


Where is your ncftpget program?

ncftpをインストールします。


wget ftp://ftp.ncftp.com/ncftp/ncftp-3.2.5-src.tar.gz
tar zxxvf ncftp-3.2.5-src.tar.gz
cd ncftp-3.2.5
./configure
make
make install
which ncftp
/usr/local/bin/ncftp

先ほどのメッセージの部分に上記のパスを入力します。


Where is your ncftpget program? /usr/local/bin/ncftp

  • DBI ...missing.
  • DBD::mysql ...missing.

次はDBIとDBD::mysqlが入ってないエラーが表示されました。
CPANからインストールします。


perl -MCPAN -e shell
cpan > install DBI
cpan > install DBD::mysql

入れ終わったらnodeインストール再開しましょう


perl Makefile.PL
make
make install

[サーバZ]での作業
マネージャ側MySQL-MHAの準備
マネージャには、NodeとManagerの両方をインストールする必要があります。
先にNodeをインストールします。
手順は先ほどと同じなのでNodeをインストールしてください

managerのインストール


wget http://mysql-master-ha.googlecode.com/files/mha4mysql-manager-0.52.tar.gz
tar zxvf mha4mysql-manager-0.52.tar.gz
cd mha4mysql-manager-0.52
perl Makefile.PL

Module::AutoInstall version 1.03
Checking for Perl dependencies...

[Core Features]

  • DBI ...loaded. (1.616)
  • DBD::mysql ...loaded. (4.020)
  • Time::HiRes ...loaded. (1.9717)
  • Config::Tiny ...missing.
  • Log::Dispatch ...missing.
  • Parallel::ForkManager ...missing.
  • MHA::NodeConst ...loaded. (0.52)

missingになっている3つをインストールしましょう。


perl -MCPAN -e shell
cpan> install Config::Tiny
cpan> install Log::Dispatch
cpan> install Parallel::ForkManager

入れ終わったらmanagerインストール再開しましょう


perl Makefile.PL
make
make install

レプリケーション

レプリケーション用ユーザの作成します


mysql -uroot -p
mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%' IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;

マスタのDBをバックアップとります。


mysqldump -uroot -p --all-databases --master-data=2 > /tmp/dump.sql

    • all-databasesは全てのデータベースからデータをダンプします。
    • master-data=2はスレーブで利用するバイナリログのファイル名と開始位置を出力します。

マスターのバックアップデータをスレーブに転送


scp /tmp/dump.sql サーバBのIPアドレス:/tmp
scp /tmp/dump.sql サーバCのIPアドレス:/tmp

[サーバB][サーバC](スレーブ)での作業

マスターデータをスレーブにリストア


mysql -uroot -p < /tmp/dump.sql

my.cnfを編集してserver-idの値を変更します。マスターより大きい値を指定してください。サーバCはサーバBのidより大きい数字を指定してください。


vim /etc/my.cnf
server-id = 20
※サーバCの場合

server-id = 30

MySQLの起動


/etc/init.d/mysqld start

先ほどダンプしたデータにレプリケーション用の情報があるので確認します。


head -100 /tmp/dump.sql | grep CHANGE
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=409;

このMASTER_LOG_FILEとMASTER_LOG_POSの値をメモします。

スレーブの設定を変更します。


mysql -uroot -p
mysql> STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST = 'サーバAのIP',
MASTER_USER = 'repl',
MASTER_PASSWORD = 'replpass',
MASTER_LOG_FILE = 'mysqld-bin.000004',
MASTER_LOG_POS = 409;

ここまでの作業を[サーバB][サーバC]で行います。

2台のスレーブ設定が完了したら両方でスレーブを開始します。


mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G;

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

この二つがYesになっていることを確認しましょう。
レプリケーションの確認を行います。

[サーバA]での作業


mysql -uroot -p
mysql> CREATE DATABASE apple;
mysql> SHOW DATABASES;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| apple              |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.16 sec)

[サーバB][サーバC]で確認


mysql> SHOW DATABASES;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| apple              |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.16 sec)

レプリケーションに成功しているようです。

MySQL-MHAの設定
先に各サーバ間を公開鍵認証でsshログインできるようにしましょう。

[サーバZ]の作業
公開鍵を作成します。入力が求められたら全てそのままEnterで大丈夫です。


ssh-keygen -b 1024 -t rsa

authorized_keysに記録しておきます。


cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys

[サーバA][サーバB][サーバC]の作業


ssh-keygen -b 1024 -t rsa

先ほどコピーした公開鍵の内容を貼り付けます。


vim /root/.ssh/authorized_keys2

ssh-rsa AAAAB***********************************************************************

サーバA,B,Cの公開鍵を確認します。それぞれメモしておきます。


cat /root/.ssh/id_rsa.pub

ssh-rsa AAAAB3N********************************************************************

[サーバZ]の作業
それぞれメモしたサーバA,B,Cの公開鍵の内容をauthorized_keysに追記します。


vim /root/.ssh/authorized_keys2

ssh-rsa AAAAB***************************************************************************= root@Manager
ssh-rsa AAAAB***************************************************************************= root@Master
ssh-rsa AAAAB***************************************************************************= root@slave1
ssh-rsa AAAAB***************************************************************************= root@slave2

このような感じになるはずです。このauthorized_keysをそれぞれサーバA,B,Cにも転送します。

scp /root/.ssh/authorized_keys サーバAのIPアドレス:/root/.ssh/authorized_keys
scp /root/.ssh/authorized_keys サーバBのIPアドレス:/root/.ssh/authorized_keys
scp /root/.ssh/authorized_keys サーバCのIPアドレス:/root/.ssh/authorized_keys

各サーバからsshでのログインがパスワードなしでできることを確認してみてください。


ssh サーバBのIPアドレス

[サーバZ]での作業

app1.cnfファイルを作成します。


vim /etc/app1.cnf

[server default]
# mysql user and password
user=repl
password=replpass
ssh_user=root
# working directory on the manager
manager_workdir=/var/log/masterha/app1
# working directory on MySQL servers
remote_workdir=/var/log/masterha/app1

[server1]
hostname=サーバAのIPアドレス

[server2]
hostname=サーバBのIPアドレス

[server3]
hostname=サーバCのIPアドレス

SSHの接続チェック


masterha_check_ssh --conf=/etc/app1.cnf

Thu Sep 29 01:41:41 2011 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Thu Sep 29 01:41:41 2011 - [info] Reading application default configurations from /etc/app1.cnf..
Thu Sep 29 01:41:41 2011 - [info] Reading server configurations from /etc/app1.cnf..
Thu Sep 29 01:41:41 2011 - [info] Starting SSH connection tests..
Thu Sep 29 01:41:42 2011 - [debug]
Thu Sep 29 01:41:41 2011 - [debug] Connecting via SSH from root@192.168.44.135(192.168.44.135) to root@192.168.44.138(192.168.44.138)..
Thu Sep 29 01:41:42 2011 - [debug] ok.
Thu Sep 29 01:41:42 2011 - [debug]
Thu Sep 29 01:41:41 2011 - [debug] Connecting via SSH from root@192.168.44.138(192.168.44.138) to root@192.168.44.135(192.168.44.135)..
Thu Sep 29 01:41:42 2011 - [debug] ok.
Thu Sep 29 01:41:42 2011 - [info] All SSH connection tests passed successfully.

All SSH connection tests passed successfully.が最後に表示されていることを確認しましょう。


レプリケーションの接続チェック


masterha_check_repl --conf=/etc/app1.cnf

Thu Sep 29 01:45:16 2011 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Thu Sep 29 01:45:16 2011 - [info] Reading application default configurations from /etc/app1.cnf..
Thu Sep 29 01:45:16 2011 - [info] Reading server configurations from /etc/app1.cnf..
Thu Sep 29 01:45:16 2011 - [info] MHA::MasterMonitor version 0.52.
Thu Sep 29 01:45:16 2011 - [error][/usr/lib/perl5/site_perl/5.8.8/MHA/Server.pm, ln236] Checking slave status failed on 192.168.44.135(192.168.44.135:3306). err=Got error when executing SHOW SLAVE STATUS. Access denied; you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation
Thu Sep 29 01:45:16 2011 - [error][/usr/lib/perl5/site_perl/5.8.8/MHA/MasterMonitor.pm, ln315] Error happend on checking configurations. at /usr/lib/perl5/site_perl/5.8.8/MHA/ServerManager.pm line 268
Thu Sep 29 01:45:16 2011 - [error][/usr/lib/perl5/site_perl/5.8.8/MHA/MasterMonitor.pm, ln396] Error happened on monitoring servers.
Thu Sep 29 01:45:16 2011 - [info] Got exit code 1 (Not master dead).

MySQL Replication Health is NOT OK!

エラーがでました。
replユーザの情報を変更します。


mysql -uroot -p
select user,host from mysql.user;
GRANT ALL PRIVILEGES ON *.* TO repl WITH GRANT OPTION;
FLUSH PRIVILEGES;
select user,host from mysql.user;

再実行


masterha_check_repl --conf=/etc/app1.cnf


Failed to save binary log: Binlog not found from /var/lib/mysql,/var/log/mysql! If you got this error at MHA Manager, please set "master_binlog_dir=/path/to/binlog_directory_of_the_master" correctly in the MHA Manager's configuration file and try again.
at /usr/bin/save_binary_logs line 95
eval {...} called at /usr/bin/save_binary_logs line 59
main::main() called at /usr/bin/save_binary_logs line 55

binlogを探している場所が違うので設定を追加します。


vim /etc/app1.cnf

master_binlog_dir=/usr/local/mysql/data

もう一回実行。が、またしてもエラー…。


Fri Sep 30 00:25:58 2011 - [info] Connecting to root@192.168.44.138(192.168.44.138)..
Can't exec "mysqlbinlog": No such file or directory at /usr/lib/perl5/site_perl/5.8.8/MHA/BinlogManager.pm line 99.
mysqlbinlog version not found!


とりあえず今日はここまで。
BinlogManager.pmの該当行周辺を少し読んでみたけど、mysqlbinlogのバージョンを格納しているのかな。
ためしにノード側のマシンでmysqlbinlog --versionコマンドを発行してみたら
mysqlbinlog --version
mysqlbinlog Ver 3.3 for linux2.6 at x86_64
と情報はでてきた。3.3であれば大丈夫のような気がするんだけどなぁ…。


うーん、なんだろうかこのエラーは…。



--[11/09/30]追記--
作者の方からコメントを頂きました。ありがとうございます。


エラーメッセージを見ると、192.168.44.138でmysqlbinlogを見つけられていないようです。このホストでmysqlbinlogは入ってるでしょうか? また「ssh 192.168.44.138 "mysqlbinlog --version"」で正しく返るかどうかも確認してみてください。

.138のマシンでmysqlbinlogを試したところ実行できましたが、他のマシンから


ssh 192.168.44.138 "mysqlbinlog --version"
を実行したらcommand not foundでした。おぉこれが原因だ!

ということで下記の記事に調査をまとめました。

sshでコマンドのリモート実行がうまくいかなかった時の調査


今回はシンボリックリンクで問題を回避したいと思います。

[サーバA][サーバB][サーバC]の作業


ln -s /usr/local/mysql/bin/mysql /usr/local/bin/mysql
ln -s /usr/local/mysql/bin/mysqlbinlog /usr/local/bin/mysqlbinlog

[サーバZ]の作業


master_binlog_dir=/usr/local/mysql/data

Fri Sep 30 04:13:17 2011 - [info] Checking replication health on 192.168.44.138..
Fri Sep 30 04:13:17 2011 - [info] ok.
Fri Sep 30 04:13:17 2011 - [info] Checking replication health on 192.168.44.135..
Fri Sep 30 04:13:17 2011 - [info] ok.
Fri Sep 30 04:13:17 2011 - [warning] master_ip_failover_script is not defined.
Fri Sep 30 04:13:17 2011 - [warning] shutdown_script is not defined.
Fri Sep 30 04:13:17 2011 - [info] Got exit code 0 (Not master dead).

MySQL Replication Health is OK.

テスト通った!やったー!


マネージャを起動します。


masterha_manager --conf=/etc/app1.cnf


192.168.44.140 (current master)
+--192.168.44.138
+--192.168.44.135

Fri Sep 30 04:56:57 2011 - [warning] master_ip_failover_script is not defined.
Fri Sep 30 04:56:57 2011 - [warning] shutdown_script is not defined.
Fri Sep 30 04:56:57 2011 - [info] Set master ping interval 3 seconds.
Fri Sep 30 04:56:57 2011 - [warning] secondary_check_script is not defined. It is highly recommended setting it to check master reachability from two or more routes.
Fri Sep 30 04:56:57 2011 - [info] Starting ping health check on 192.168.44.140(192.168.44.140:3306)..
Fri Sep 30 04:56:57 2011 - [info] Ping succeeded, sleeping until it doesn't respond..

起動したらもう一つ端末を開いて以下のコマンド実行しましょう。


masterha_check_status --conf=/etc/app1.cnf

マネージャ起動中であれば以下のようなメッセージが表示されます。


app1 (pid:6937) is running(0:PING_OK), master:192.168.44.140

マネージャの停止確認で以下のコマンドを実行します。


masterha_stop --conf=/etc/app1.cnf

Stopped app1 successfully.

マネージャを実行しなおしましょう。


masterha_manager --conf=/etc/app1.cnf


MySQL-MHA稼働確認

[サーバB][サーバC](スレーブ)で作業


mysql -uroot -p

mysql> show slave status \G;

 ************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.44.140
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 190
Relay_Log_File: localhost-relay-bin.000005
Relay_Log_Pos: 253
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes


[サーバA](マスター)で作業

マスタの電源を落としてみます。


shutdown -h now


[サーバZ]で作業

しばらくするとマネージャの画面に以下のようなメッセージが出力されます。

          • Failover Report -----

app1: MySQL Master failover 192.168.44.140 to 192.168.44.138 succeeded

Master 192.168.44.140 is down!

Check MHA Manager logs at localhost.localdomain for details.

Started automated(non-interactive) failover.
The latest slave 192.168.44.138(192.168.44.138:3306) has all relay logs for recovery.
Selected 192.168.44.138 as a new master.
192.168.44.138: OK: Applying all logs succeeded.
192.168.44.135: This host has the latest relay log events.
Generating relay diff files from the latest slave succeeded.
192.168.44.135: OK: Applying all logs succeeded. Slave started, replicating from 192.168.44.138.
192.168.44.138: Resetting slave info succeeded.
Master failover to 192.168.44.138(192.168.44.138:3306) completed successfully.

140から138にマスターが変わったようです。


[サーバB](新マスター)で作業


mysql> show master status \G;
 ************************** 1. row ***************************
File: mysql-bin.000001
Position: 107
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)


[サーバC](スレーブ)で作業


mysql> show slave status \G;
 ************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.44.138
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 107
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 253
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes


マスターがちゃんと[サーバB]に変わっています。


[サーバB](新マスター)で作業


mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| ipod               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.02 sec)

ためしにipodDBを消してみます。


mysql> drop database ipod;
Query OK, 0 rows affected (0.20 sec)


mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)


[サーバC](スレーブ)で作業


mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.64 sec)

ちゃんとレプリケーションされてますね。


備考
masterha_managerはデーモンではなくフロントで動くのでバックグラウンドで動かすといいかも知れないです。


masterha_check_repl --conf=/etc/app1.cnf >> /tmp/mha.log 2>&1

このような感じで標準出力と標準エラー出力をログに残しておくといいかも知れないです。
このあたりの運用情報がどこかにないかなぁ。


そのうち、更新処理走ってる状態でマスター落としたらどうなるのか検証してみたいです。


参考リンク
http://myhome.munetika.mydns.jp/ossdbwiki/index.php/MySQL-MHA%E3%81%AE%E5%B0%8E%E5%85%A5
http://d.hatena.ne.jp/ke-16/20110912/1315824419
http://www.publickey1.jp/blog/11/denamysql_1.html
http://code.google.com/p/mysql-master-ha/
http://d.hatena.ne.jp/kaze-kaoru/20110830/1314677120