MySQLでレプリケーション&フェイルオーバー

  • 投稿日:
  • by

MySQLでレプリケーション&フェイルオーバーについて簡単な手順
※一度この構成で試し(遊ぶ)たかったので。。。これはあくまでメモです!

○構成

*dbserver1(Master) と dbserver2(Slave)をMySQLでレプリケーション構成にし、監視ツール(MON)がMySQLの障害を察知すると、HA(LinuxHA)のMaster側をアクティブから停止状態にさせ、SlaveをMasterにさせる。
*OSはCentOS-4.3
*ダウンしたMaster側を再度Masterにしてレプリケーション構成にする場合の説明は省略
  (いろいろあるので説明がめんどい)

# クラスタノード
172.17.3.9 dbserver (eth0:0)

# 初期時のネットワークアドレス状態
# DBサーバ1(初期時マスター)
172.17.3.9 dbserver   (eth0:0) is up (クラスタノード名)
192.168.0.9 dbserver1-ha  (eth1:0) is up for heartbeat
172.17.3.10 dbserver1     (eth0)
192.168.0.10 dbserver1-int   (eth1) for レプリケーション

# DBサーバ2(初期時スレーブ)
172.17.3.9 dbserver    (eth0:0) is down (クラスタノード名)
192.168.0.9 dbserver2-ha  (eth1:0) is down for heartbeat
172.17.3.11 dbserver2     (eth0)
192.168.0.11 dbserver2-int   (eth1) for レプリケーション

* 192.168.0.* はサーバ直結か、VLANをはるかなど。

################################################################
MySQLのインストールと簡単な設定
################################################################
MySQLインストール(全サーバ)

# rpm -Uvh MySQL-server-standard-5.0.24-0.rhel4.i386.rpm
# rpm -Uvh MySQL-client-standard-5.0.24-0.rhel4.i386.rpm
# rpm -Uvh MySQL-devel-standard-5.0.24a-0.rhel4.i386.rpm
# rpm -Uvh MySQL-shared-standard-5.0.24a-0.rhel4.i386.rpm

○自動で起動されるので一旦停止(全サーバ)

# /etc/init.d/mysql stop

○設定ファイルをコピーする。(全サーバ)

# cp /usr/share/doc/MySQL-server-standard-5.0.24/my-small.cnf /etc/my.cnf

 
○DB領域を一旦削除 (全サーバ)(削除の責任は各個人で判断して下さい。・・・くれぐれも気をつけて!)
# cd /var/lib/mysql
# \rm -R *

○my.cnfを編集(全サーバ)

server-id = 10 ←サーバIDを設定する( dbserver1:10 / dbserver1 :11)
replicate-do-db = exampledb ←exampledb データベースをレプリケーション

# Uncomment the following if you want to log updates
log-bin=mysql-bin     ← もしくはディレクトリの指定可

# InnoDBを使うように設定(あくまで例)
# Uncomment the following if you are using InnoDB tables
innodb_data_home_dir = /var/lib/mysql/
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /var/lib/mysql/
innodb_log_arch_dir = /var/lib/mysql/
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
innodb_buffer_pool_size = 16M
innodb_additional_mem_pool_size = 2M
# Set .._log_file_size to 25 % of buffer pool size
innodb_log_file_size = 5M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50

○DBを初期化(全サーバ)


※ mysql の unixアカウントを作成(省略)

# /usr/bin/mysql_install_db
# cd /var/lib/mysql
# chown -R mysql:mysql *

○起動(全サーバ)

# /etc/init.d/mysql start

○Grantで'repl'(レプリケーション用)のロールを設定する。(一応全サーバ)(このあたりは場合により調整)

# mysql
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO repl@'192.168.0.0/255.255.255.0' IDENTIFIED BY 'password';
mysql> GRANT ALL ON *.* TO repl@localhost IDENTIFIED BY 'password';
mysql> FLUSH PRIVILEGES;

○必要に応じてUnixアカウントなどを設定する。(このあたりも場合により調整)

mysql> grant all privileges on *.* to 'blogkid'@'%';
mysql> GRANT ALL ON *.* TO blogkid@localhost IDENTIFIED BY 'password';
mysql> FLUSH PRIVILEGES;

○exampledb データベースとテスト用のテーブルの作成(全サーバ)

mysql> create database exampledb;
mysql> use exampledb;
mysql> CREATE TABLE example (
       id INT,
       data VARCHAR(100)
     );

○dbserver2 (dbserver2のslave側でMaster DBの設定をする。)

mysql> CHANGE MASTER TO MASTER_HOST='dbserver1-int',MASTER_PORT=3306,MASTER_USER='repl',MASTER_PASSWORD='password';

/var/lib/mysql/master.info に設定した情報が書き込まれます。

○Slaveを起動させる (dbserver2のslave側)

# mysql
mysql> slave start

○Masterのテーブルへ追加する。(dbserver1のmaster側)
mysql> use exampledb;
mysql> insert into example values(1,'test');

○Slaveのテーブルが更新されている事を確認する。(dbserver2のslave側)
mysql> use exampledb;
mysql> select * from example;

################################################################
LunuxHA(heartbeat)インストール設定
################################################################
○インストール(全サーバ)

# yum install heartbeat

○設定(全サーバ)

# cd /etc/ha.d
# cp /usr/share/doc/heartbeat-2.0.7/ha.cf .
# cp /usr/share/doc/heartbeat-2.0.7/haresources .
# cp /usr/share/doc/heartbeat-2.0.7/authkeys .
# chmod 600 authkeys

# vi /etc/ha.d/ha.cf (全サーバ)
----- 以下追加する。
debugfile /var/log/ha-debug
logfile /var/log/ha-log
logfacility local0
keepalive 2
deadtime 10
udpport 694
bcast eth1

# onにするとdownした側のHAを起動すると自動でactiveになるので一応off
auto_failback off
# hostnameコマンドで表示されるサーバ名
node dbserver1
node dbserver2

debugfile /var/log/ha-debug
logfile /var/log/ha-log

# vi /etc/ha.d/authkeys (全サーバ)
----- 以下追加する
auth 1
1 crc

# vi /etc/ha.d/haresources (全サーバ)
----- 以下追加
dbserver1 172.17.3.9 192.168.0.9 mysql mon ←(dbserver1のサーバのみ)
dbserver2 172.17.3.9 192.168.0.9 mysql_slave ←(dbserver2のサーバのみ)

* サーバ名はhostname コマンドで表示される名前を設定する。
* 最後のコマンドは/etc/init.d 配下のコマンド。(mysql_slaveとmonの追加は後述)


# /etc/init.d/mysql_slave を追加   (dbserver2のslave側のみ)

#!/bin/sh
mode=$1 # start or stop

case "$mode" in
'stop')
/usr/bin/mysql -u root -e "SLAVE STOP;"
;;
'start')
/usr/bin/mysql -u root -e "SLAVE STOP;"
/usr/bin/mysql -u root -e "RESET MASTER;"
/usr/bin/mysql -u root -e "RESET SLAVE;"
;;
*)
# usage
echo "Usage: $0 {start|stop} [ MySQL slave server options ]"
exit 1
;;
esac

○起動(Master → Slaveの順で・・・)


# /etc/init.d/heartbeat start

* ifconfig で dbserver1とdbserver2のupとdownしているインターフェイスを確認する。

################################################################
監視モジュール(MON)インストール設定  (dbserver1のMaster側のみ)
################################################################
○インストール

# wget http://www.jp.kernel.org/pub/software/admin/mon/mon-0.99.2.tar.gz
# gunzip < mon-0.99.2.tar.gz | tar xvf -
# mv mon-0.99.2 /usr/local/mon

○必要なCPANたち

# perl -MCPAN -e 'install Mon::SNMP'
# perl -MCPAN -e 'install Time::Period'
# perl -MCPAN -e 'install Time::HiRes'
# perl -MCPAN -e 'install Convert::BER'
# perl -MCPAN -e 'install DBI'
# perl -MCPAN -e 'install Proc::ProcessTable'
# perl -MCPAN -e 'force install DBD::mysql'

○/etc/init.d へこんな感じで追加

# vi /etc/init.d/mon
#! /bin/sh
DAEMON="/usr/bin/perl"

set -e

# Check for echo -n vs echo \c
if echo '\c' | grep -s c >/dev/null 2>&1 ; then
ECHO_N="echo -n" ECHO_C=""
else
ECHO_N="echo"
ECHO_C='\c'
fi

# Only start if we can find the postmaster.
test -x $DAEMON || exit 0

# Parse command line parameters.
case $1 in
start)
$ECHO_N "Starting MON: "$ECHO_C
su - root -c "$DAEMON /usr/local/mon/mon -b /usr/local/mon -B /usr/local/mon/etc &"
echo "ok"
;;
stop)
echo -n "Stopping MON:"
kill -9 `ps -ef | grep mon | grep perl | grep -v grep | awk '{print $2}'` 2> /dev/null
echo "ok"
;;
*)
# Print help
echo "Usage: $0 {start|stop}" 1>&2
exit 1
;;
esac
exit 0

○設定

# cd /usr/local/mon/etc
# vi mon.cf
以下のようにファイルを追加
maxprocs = 20
histlength = 100
randstart = 60s

hostgroup dbserver1

watch dbserver1
service mysql
interval 10s
    
monitor msql-mysql.monitor --mode=mysql --username=repl --password=password --database=exampledb localhost
allow_empty_group
period wd {Sun-Sat}
alertevery 45m
alert mail.alert <落ちたときに送信する管理者のメールアドレスなど>
upalert mail.alert -u <立ち上がったときに送信する管理者のメールアドレスなど>
alert stop-heartbeat.alert

# vi /usr/local/mon/mon.d/msql-mysql.monitor を修正
- @tables = $dbh->func( '_ListTables' );
+ @tables = map { $_ =~ s/.*\.//; $_ } $dbh->tables();

# cd /usr/local/mon/alert.d
...へstop-heartbeat.alertのファイル名で追加
#!/usr/bin/perl
#
use Getopt::Std;
use Text::Wrap;

getopts ("S:s:g:h:t:l:u");

$summary=<STDIN>;
chomp $summary;

$summary = $opt_S if (defined $opt_S);

$mailaddrs = join (',', @ARGV);

$ALERT = $opt_u ? "UPALERT" : "ALERT";

$t = localtime($opt_t);
($wday,$mon,$day,$tm) = split (/\s+/, $t);

open (HA, "| /etc/init.d/heartbeat stop") ||
die "could not open pipe to mail: $!\n";
print HA <<EOF;
To: $mailaddrs
Subject: $ALERT $opt_g/$opt_s: $summary ($wday $mon $day $tm)
X-Mailer: $0

EOF

print HA wrap ("", "", "Summary output : $summary"), "\n";

print HA <<EOF;

Group : $opt_g
Service : $opt_s
Time noticed : $t
Secs until next alert : $opt_l
EOF

print HA wrap ("", "\t\t\t", "Members : $opt_h"), "\n";

print HA <<EOF;

Detailed text (if any) follows:
-------------------------------
EOF

#
# The remaining lines normally contain more detailed information,
# but this is monitor-dependent.
#
while (<STDIN>) {
print HA;
}
close (HA);


# chmod 775 stop-heartbeat.alert

○起動(dbserver1のMaster側で起動)

# /etc/init.d/mon start &

○確認

試しにdbserver1のMaster側のMySQLを停止させ、クラスタノードのネットワークインターフェイスがdbserver2のslaveがMasterになっている事を確認。(SHOW SLAVE STATUS で Slave_IO_State にメッセージがない事で確認できるかな。)