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の設定
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秒)に設定することが肝です。
- /etc/named.conf
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"; };
- /var/named/zone/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も短めに設定しておきましょう。
- /etc/resolve-conf
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種類のデーモンプロセスが動作します。
設定ファイル
ずらずらと設定ファイルを並べておきます。
- mmm_common.conf
# 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
- mmm_agent.conf
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
- mmm_mon.conf
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
- mmm_ns_agent.conf
[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のホストも時々は落ちることがある、という話はよく聞きますので、少なくともシングルマスターの場合よりは安心できると思います。
もし、よりよい方法があったら、是非教えてください!!