EC2上では、仮想IPアドレスなどのIPレベルの機能が制限されているため、仮想IPアドレスを使用した冗長化は基本的には使用できません。が、DNSを使用することで、VIPほどの精度は高くないもののMySQL Multi-master構成を構築することができました。
今回は、MySQL Multi-masterの切り替え用の支援ツールとして、Multi-Master Replication Manager for MySQLを使用します。このツールでは、MySQLの死活監視と仮想IPアドレスの切り替えを行ってくれます。
もちろん、EC2上では仮想IPアドレスは使えないので、そのままではうまく動作しません。ここで、このツールに含まれるns_agentを使用することで仮想IPアドレスではなく、DNSによる切り替えができるようになり、EC2上でMulti-masterを構築することができます。
今回は、このMulti-Master Replication Manager for MySQLとns_agentを使って、DNSによるMulti-masterのフェイルオーバーを実現してみます。
概要について、AWS UGのLTで使ったスライドを貼っておきます。
準備編
環境設定
Amazon EC2 API Toolsを使えるようにしましょう。ドキュメントを参照するか、ググってください。
次に、インスタンスを2台起動します。個人的な趣味で、RightScaleのCentOS 5.2 32bitのイメージを使用しています。セキュリティグループ(mmm_test)は、内部通信は可能にしておきます。
ec2-run-instances ami-ab2071ee -g mmm_test -k mmm_test
ec2-run-instances ami-ab2071ee -g mmm_test -k mmm_test
立ち上がったインスタンスを、host1とhost2とします。
それぞれのホストで、必要なツールをざくざくインストールします。
rpm -Uhv http://apt.sw.be/redhat/el5/en/i386/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
yum -y install perl-Proc-Daemon perl-Algorithm-Diff perl-Log-Log4perl perl-MailTools perl-Log-Dispatch perl-Class-Singleton
yum -y install mysql-server mysql
yum -y install php libnet
MySQLのMulti-master replicationを構築します。Multi-master replicationの構築方法は、Googleで検索するか、実践ハイパフォーマンスMySQLの第8章を参照してください。
次にMulti-master replication manager用の権限を設定します。パスワードは適当の変更してください。
GRANT REPLICATION CLIENT ON *.* TO 'mmm_monitor'@'%' IDENTIFIED BY 'monitor_password';
GRANT SUPER, REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'%' IDENTIFIED BY 'agent_password';
GRANT SUPER, REPLICATION CLIENT, PROCESS,REPLICATION SLAVE ON *.* TO 'replication'@'%' IDENTIFIED BY 'replication_password';
bindの設定
適切なサーバ(例えば、host1)にbindの設定を行います。参考にほぼ最小構成のbindの設定を書いておきます。ここでは、db.testdomainという名前を使用しています。DNSでフェイルオーバーしますのでTTLを短め(ここでは10秒)に設定することが肝です。
options
{
directory "/var/named"; // the default
dump-file "data/cache_dump.db";
statistics-file "data/named_stats.txt";
memstatistics-file "data/named_mem_stats.txt";
recursion no;
};
zone "testdomain" IN {
type master;
file "zones/mmm.zone";
};
$ORIGIN testdomain.
$TTL 10 ; 10 seconds
@ IN SOA testdomain. postmaster.testdomain. (
1002044230 ; serial
3600 ; refresh (1 hour)
1200 ; retry (20 min.)
1209600 ; expire (2 weeks)
900 ; minimum (15 min.)
)
@ IN NS ns1.testdomain.
ns1 IN A 10.xx.yy.zz
db IN A 10.xx.yy.zz
また各ホストのresolv.confにhost1のIPアドレスを追加しておきます。一応、timeoutも短めに設定しておきましょう。
search us-west-1.compute.internal
timeout 3
nameserver 10.xx.yy.zz
nameserver 172.16.0.23
DNSによるMySQL Multi-master フェイルオーバー
Multi-Master Replication Manager for MySQL
Multi-Master Replication Manager for MySQLをチェックアウトして、初期設定を行います。
svn checkout http://mysql-master-master.googlecode.com/svn/trunk/ mysql-master-master-read-only
ln -s mysql-master-master-readonly /usr/local/mmm
ln -s /usr/local/mmm/scripts/init.d/mmm_mon /etc/init.d
ln -s /usr/local/mmm/scripts/init.d/mmm_agent /etc/init.d
ns_agentを使用するために、ifconfig.pmを書換えておきます。
mv /usr/local/mmm/lib/ifconfig.pm /usr/local/mmm/lib/ifconfig.original.pm
ln -s /usr/local/mmm/contrib/ns_agent/ifconfig.pm /usr/local/mmm/lib
MySQL Multi-master Manager + ns_agent
MySQL Multi-master Managerとns_agentによる構成は以下の3種類のデーモンプロセスが動作します。
- 各データベースに同居させるmmmd_agent
- 監視・切り替え制御を行うmmmd_mon
- 各サーバの状態を管理し、mmmd_agentを通じて、各サーバの監視・制御を行う
- DNSサーバに同居させるns_agent
設定ファイル
ずらずらと設定ファイルを並べておきます。
# Cluster interface
cluster_interface eth0
# Debug mode
debug yes
# Paths
bin_path /usr/local/mmm/bin
# Logging setup
log mydebug
file /usr/local/mmm/var/mmm-debug.log
level debug
log mytraps
file /usr/local/mmm/var/mmm-traps.log
level trap
email root@localhost
# Email notification settings
email notify
from_address stanaka@hatena.ne.jp
from_name MMM Control
# Define roles
active_master_role writer
# MMMD command socket tcp-port
agent_port 9989
monitor_ip 127.0.0.1
# Cluster hosts addresses and access params
host db1
ip 10.xx.yy.zz
port 3306
user replication
password replication_password
mode master
peer db2
host db2
ip 10.xx.yy.zzz
port 3306
user replication
password replication_password
mode master
peer db1
# Mysql Writer role
role writer
mode exclusive
servers db1, db2
ip db.testdomain
# Replication credentials used by slaves to connect to the master
replication_user replication
replication_password replication_password
# Checks parameters
# Ping checker
check ping
check_period 1
trap_period 5
timeout 2
# Mysql checker
# (restarts after 10000 checks to prevent memory leaks)
check mysql
check_period 1
trap_period 2
timeout 2
restart_after 10000
# Mysql replication backlog checker
# (restarts after 10000 checks to prevent memory leaks)
check rep_backlog
check_period 5
trap_period 10
max_backlog 60
timeout 2
restart_after 10000
# Mysql replication threads checker
# (restarts after 10000 checks to prevent memory leaks)
check rep_threads
check_period 1
trap_period 5
timeout 2
restart_after 10000
include mmm_common.conf
# Paths
pid_path /usr/local/mmm/var/mmmd_agent.pid
# MMMD command socket tcp-port and ip
bind_port 9989
# Define current server id
this db1
# Cluster hosts addresses and access params
host db1
user mmm_agent
password agent_password
host db2
user mmm_agent
password agent_password
nameserver ns1
ip 10.160.47.21
port 9994
include mmm_common.conf
# Paths
pid_path /usr/local/mmm/var/mmmd.pid
status_path /usr/local/mmm/var/mmmd.status
# MMMD command socket tcp-port
bind_port 9988
# Choose the default failover method [manual|wait|auto]
failover_method wait
# How many seconds to wait for both masters to become ONLINE
# before switching from WAIT to AUTO failover method, 0 = wait indefinitely
wait_for_other_master 60
# How many seconds to wait before switching node status from AWAITING_RECOVERY to ONLINE
# 0 = disabled
auto_set_online 10
monitor_user mmm_monitor
monitor_password monitor_password
[nameserver_agent]
port = 9994
zoneFile = /var/named/zones/mmm.zone
起動
あとは各デーモンプロセスを起動するのみです。まず、各データベースサーバで、mmm_agentを起動します。
/etc/init.d/mmm_agent start
Starting MMM Agent daemon: MySQL Multi-Master Replication Manager
Version: 1.2.6
[2010-02-22 22:15:59]: Scanning network interfaces for the existing roles...
[2010-02-22 22:15:59]: Core: Execute_bin('/usr/local/mmm/bin/mysql_deny_write 'mmm_agent.conf'')
[2010-02-22 22:15:59]: Listener: Waiting for connection...
[2010-02-22 22:16:00]: Listener: Connect!
[2010-02-22 22:16:00]: SET_STATUS 0, ONLINE, , db1
...
次に、監視サーバでmmm_monを起動します。
# /etc/init.d/mmm_mon start
Daemon bin: '/usr/local/mmm/sbin/mmmd_mon'
Daemon pid: '/usr/local/mmm/var/mmmd.pid'
Starting MMM Monitor daemon: MySQL Multi-Master Replication Manager
Version: 1.2.6
Reading config file: 'mmm_mon.conf'
[2010-02-22 22:16:24]: Spawning checker 'rep_backlog'...
[2010-02-22 22:16:24]: Spawning checker 'mysql'...
[2010-02-22 22:16:24]: Spawning checker 'ping'...
[2010-02-22 22:16:24]: Spawning checker 'rep_threads'...
[2010-02-22 22:16:25]: Trying initial check 'rep_backlog' on host 'db2'...
[2010-02-22 22:16:25]: rep_backlog('db2') = 'OK'
[2010-02-22 22:16:25]: Trying initial check 'mysql' on host 'db2'...
[2010-02-22 22:16:25]: mysql('db2') = 'OK'
...
最後にDNSサーバでns_agentを起動します。
# php /usr/local/mmm/contrib/ns_agent/ns_agent.php
Daemon started, listening on 9994
動作確認
ここでアクティブ側のdb1(host1)のmysqldを落してみます。
/etc/init.d/mysqld stop
そうするとmmm_monの監視が動いて、ns_agentに情報が伝わり、zoneファイルが書換えられます。
Command Received: ADDIP:db.testdomain:10.160.47.21
Executing: sed -i.last '/db.*/d' /var/named/zones/mmm.zone
Executing: echo 'db IN A 10.xx.yy.zzz' >> /var/named/zones/mmm.zone
Updating /var/named/zones/mmm.zone with new serial:1002044230
その後、zoneファイルが再読み込みされ、DNS情報が更新されフェイルオーバーが実現されます。
フェイルオーバーの様子を、監視していると、以下のように数秒で切り替わったことが確認できます。
# while /bin/true; do date; mysqladmin -ummm_agent -pagent_password -hdb.testdomain variables | grep server_id; sleep 2; done
....
Mon Feb 22 22:20:53 EST 2010
| server_id | 1 |
Mon Feb 22 22:20:55 EST 2010
| server_id | 1 |
Mon Feb 22 22:20:57 EST 2010
mysqladmin: connect to server at 'db.testdomain' failed
error: 'Lost connection to MySQL server at 'reading initial communication packet', system error: 111'
Mon Feb 22 22:20:59 EST 2010
mysqladmin: connect to server at 'db.testdomain' failed
error: 'Lost connection to MySQL server at 'reading initial communication packet', system error: 111'
Mon Feb 22 22:21:01 EST 2010
| server_id | 2 |
Mon Feb 22 22:21:03 EST 2010
| server_id | 2 |
...
おわり
MySQLのMulti-masterのフェイルオーバーに数秒かかってしまいますが、用途によっては、なんとか我慢できるところもあると思います。EC2のホストも時々は落ちることがある、という話はよく聞きますので、少なくともシングルマスターの場合よりは安心できると思います。
もし、よりよい方法があったら、是非教えてください!!