Friday, January 24, 2014

MHA for MySQLをセットアップして、お手軽にMySQLのフェイルオーバーを実現する方法

著作者:Jlhopgood

言わずと知れた、MySQLのフェイルオーバーツール、MHA for MySQL(https://code.google.com/p/mysql-master-ha/)をお手軽に使う方法を紹介します。


フェイルオーバー時に、アプリサーバからMySQLへの接続先を変更する方法として、”アプリサーバへ /etc/hosts を rsync で配布する” といった方法をとります。
いままでは、MySQLサーバのIPアドレスの付け替えや、HAProxyの設定変更を自動で行う、などといった方法がありましたが、これは、敷居低めで実装できるのが嬉しいです。

動作イメージは下のようになります。
mysql1が壊れたとき、mysql2が自動でマスターに昇格してサービスを継続します。


詳しく説明します。
app1、app2の /etc/hosts には、MySQLマスターのホスト名 mysql-master.myservice.com と mysql1 のIPアドレスを紐づける記述しておきます。
app1、app2のアプリケーションは、このホスト名 mysql-master.myservice.com 宛にMySQL接続をします。
フェイルオーバー時には、mysql-master.myservice.com の IPアドレスを mysql2 のものに変更した /etc/hosts を rsync で差し替えます。

サーバIDとIPアドレスはこのようになっているとします。
app1(100.100.100.1) :アプリケーション1 + MHAマネージャ
app2(100.100.100.2) :アプリケーション2
mysql1(200.200.200.1) :MySQLマスタ
mysql2(200.200.200.2) :MySQLスレーブ

試験環境は、CentOS 6.5、MySQL 5.6です。
MySQLは、既にインストールされている状態ではじめます。
MHAマネージャは、app1サーバにセットアップします。


◆ 事前準備

1) sshのrootユーザで各サーバにログインできるようにしておく。
app1 -> app1, app2, mysql1, mysql2
mysql1 -> mysql2
mysql2 -> mysql1

2) MySQLの設定を編集(mysql1, mysql2)
/etc/my.cnfの[mysqld]に、log-bin、server-idを設定

3) MySQL接続ユーザ、レプリケーション用ユーザを作る(mysql1)
MHAマネージャから、rootユーザでMySQLアクセスできるようにしておく。
mysql1 -> mysql2 レプリケーションの為のユーザを作る。

4) MySQLマスタ -> スレーブのレプリケーションを構築しておく。(mysql1, mysql2)
※ 準同期レプリケーションを設定しておくと、レプリケーションの安全性が高まります。
参考)準同期レプリケーションの実装方法 - サーバサイドWiki - Confluence
※ MySQL 5.6では、mysql2の/var/lib/mysql/auto.cnfを削除してrestartしておく。
(masterとslaveとで、server-uuidがかぶっていなければOK。)
※ 今回は、スレーブにread_onlyは付けないでおきました。

5) MySQLホスト名を /etc/hosts に記述する。(app1, app2)
# vim /etc/hosts
---
200.200.200.1 mysql-master.myservice.com
---

アプリケーションからは、mysql-master.myservice.com 宛に接続するようにしておきましょう。



◆ MHAのインストール

1) mysql1, mysql2サーバに、MHAノード(mha4mysql-node)をインストール

# cd /usr/local/src
# wget https://72003f4c60f5cc941cd1c7d448fc3c99e0aebaa8.googledrive.com/host/0B1lu97m8-haWeHdGWXp0YVVUSlk/mha4mysql-node-0.56-0.el6.noarch.rpm
# yum localinstall mha4mysql-node-0.56-0.el6.noarch.rpm
# rpm -ql mha4mysql-node

2) app1サーバに、MHAマネージャ(mha4mysql-manager)をインストール
※ 依存ライブラリを先にインストールする必要があります。先にMHAノードのインストールをします。

# cd /usr/local/src
# wget https://72003f4c60f5cc941cd1c7d448fc3c99e0aebaa8.googledrive.com/host/0B1lu97m8-haWeHdGWXp0YVVUSlk/mha4mysql-node-0.56-0.el6.noarch.rpm
# wget https://72003f4c60f5cc941cd1c7d448fc3c99e0aebaa8.googledrive.com/host/0B1lu97m8-haWeHdGWXp0YVVUSlk/mha4mysql-manager-0.56-0.el6.noarch.rpm
# yum localinstall mha4mysql-node-0.56-0.el6.noarch.rpm
# yum localinstall mha4mysql-manager-0.56-0.el6.noarch.rpm
# rpm -ql mha4mysql-manager

◆ MHAの設定ファイルを用意

app1サーバで用意します。

設定ファイル類を置くディレクトリを作成
# mkdir /usr/share/masterha

ログファイル用のディレクトリを作成
# mkdir -p /var/log/masterha/mysql/

MHA設定ファイルを書く。
# vim /usr/share/masterha/masterha_default.cnf
---
[server default]

# mysql user and password
user=root
password=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
ssh_user=root

# working directory on the manager
manager_workdir=/var/log/masterha/mysql

# working directory on MySQL servers
remote_workdir=/var/log/masterha/mysql

# MySQL TCP connection check
ping_type=CONNECT

# failover script
master_ip_failover_script=/usr/share/masterha/master_ip_failover.sh
master_ip_online_change_script=/usr/share/masterha/master_ip_failover.sh

[server1]
hostname=200.200.200.1

[server2]
hostname=200.200.200.2
candidate_master=1
---


◆ フェイルオーバー時に実行するスクリプトを用意

app1サーバで用意します。
※ rootによるssh疎通を要チェックしておきましょう。

rsyncで /etc/hosts を配布するスクリプトを設置します。
このスクリプトが、フェイルオーバー時に実行されます。
# vim /usr/share/masterha/master_ip_failover.sh
---
#!/bin/bash
DIR=/usr/share/masterha
if [ "$1" = "--command=start" ]; then
  # app1
  rsync -avz ${DIR}/hosts 100.100.100.1:/etc/hosts
  # app2
  rsync -avz ${DIR}/hosts 100.100.100.2:/etc/hosts
fi
---
# chmod 755 /usr/share/masterha/master_ip_failover.sh

フェイルオーバー時に app1,app2 サーバへ配布する /etc/hosts ファイルを設置します。
mysql-master.myservice.com のIPアドレスを mysql2のモノにします。
# vim hosts
---
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
200.200.200.2 mysql-master.myservice.com
---


◆ MHAをスタート

app1サーバでMHAを実行します。

sshコネクションをチェック
# masterha_check_ssh --conf=/usr/share/masterha/masterha_default.cnf

MySQLコネクションをチェック
# masterha_check_repl --conf=/usr/share/masterha/masterha_default.cnf

MHAマネージャの起動を試す(フォアグランド)
# masterha_manager --conf=/usr/share/masterha/masterha_default.cnf
[Ctrl + c]で抜けます。

MHAマネージャの起動(バックグランド)
# nohup masterha_manager --conf=/usr/share/masterha/masterha_default.cnf < /dev/null > /var/log/masterha/mysql/manager.log 2>&1 &
# ps aux | grep masterha_manager
# tail -f /var/log/masterha/mysql/manager.log
---
FriJan 24 23:35:09 2014 - [info] Ping(CONNECT) succeeded, waiting until MySQL doesn't respond..
---
上記のように出ているでしょうか?出ていたらおkです。
mysql1のmysqlをストップしたり、アクセス制限を掛けたりしてフェイルオーバーできるかチェックしてみましょう。


※ MHAマネージャを停止したいときは?以下のコマンドを叩きます。
#  masterha_stop --conf=/usr/share/masterha/masterha_default.cnf

※ フェイルオーバーを実行した後は下記のファイルを削除してから、MHAを立ち上げる必要があります。
成功していた場合
# rm /var/log/masterha/mysql/masterha_default.failover.complete
失敗していた場合
# rm /var/log/masterha/mysql/masterha_default.failover.error


◆ MHAマネージャをデーモン化

Upstartを使って、MHAマネージャをデーモン化してみます。
なにかしらの原因で、MHAマネージャが落ちたときに自動で立ち上げ直してくれます。
一般的には、daemontoolsが使われていますが、Upstartの方がデフォルトで入っているし、らくちんです。

ここでは "respawn limit"によりプロセスの再起動回数を制限します。
5分間に10回以上再起動が起きた場合には、自動的に停止され、再起動されなくなります。

設定ファイルを用意
# vim /etc/init/mha.conf
---
description "MySQL-MHA"
author "Takeshi Yako <yako.takeshi@googlemail.com>"

start on runlevel [2345]
stop on runlevel [016]

chdir /usr/share/masterha/
respawn
respawn limit 10 5
exec  /usr/bin/masterha_manager --conf=/usr/share/masterha/masterha_default.cnf >> /var/log/masterha/mysql/manager.log 2>&1
---

設定を反映します。
# initctl reload-configuration
# initctl list | grep mha

起動します。
# initctl start mha

確認。
# initctl list | grep mha
# ps auxf | grep mha
# tail -f /var/log/masterha/mysql/manager.log

停止するときは?
# initctl stop mha

参考)Upstart を使ってお手軽 daemon 化
http://heartbeats.jp/hbblog/2013/02/upstart-daemon.html


◆ まとめ

MySQL for MHAをセットアップして、/etc/hostsや、rsyncなどの枯れたモノを使ってMySQLをフェイルオーバできるようにしました。
インフラ構成が比較的ちいさなサービスなどで、”MySQLのHA構成が欲しい”という要望があったときに、使えたりしそうです。
試してみてください。