MHA(MasterHighAvailabilityManager)の導入設定

MHA(MasterHighAvailabilityManager)の導入設定
使用バージョン:mha4mysql-manager-0.53-0、MySQL-5.5
mha-img1


①簡単な利点などの解説

MHAとはmysqlのマスタ障害時に最新のスレーブをマスタとして他のスレーブの差分を補完しマスタの向き先を変えてくれるプロダクト。
Heartbeat+mon+mysqlに比べるとreplicationの再構成も行ってくれるので切り替わってもDBがシングルにならないのが利点。(3台以上の構成の場合)

作者のスライド
公式サイト
MHAの制約:mysql5.0以上、SBR(ステートメントベースレプリケーション)の場合LOAD DATA INFILEを使えない
※マネージャはadminサーバ、ノードはDBサーバ(マスタ・スレーブ共通)

② マネージャにてインストール    ※以下、admサーバから実施

・インストール
[php]

wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53-0.noarch.rpm

wget http://mysql-master-ha.googlecode.com/files/mha4mysql-manager-0.53-0.noarch.rpm

yum –enablerepo=rpmforge install \

perl-Config-Tiny \
perl-Time-HiRes \
perl-Log-Dispatch \
perl-Parallel-ForkManager \
perl-Params-Validate

yum install perl-DBD-MySQL

rpm -ivh mha4mysql*

[/php]
入ってなかったら

[shell]yum install –enablerepo=remi mysql mysql-server perl-DBD-MySQL[/shell]
※マネージャはmysql-serverいらないかも

③ ノードにてインストール ※以下、dbサーバから実施
[shell]

wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53-0.noarch.rpm

rpm -ivh mha4mysql-node*

[/shell]
④ 設定変更(マネージャ)

・ssh公開鍵設定
マネジャからノードにrootで鍵なしログインできる必要がある
鍵を作成し(ssh-keygen -t rsa -N “”)
各ノードにて公開鍵(~.pub)を公開鍵リング(/root/.ssh/authorized_keys)に追記

・設定ファイルとスクリプトの設置
[shell]

# vi /etc/app1.cnf

[server default]

mysql user and password

user=root
password=
ssh_user=root

working directory on the manager

manager_workdir=/var/log/masterha/app1
manager_log=/var/log/masterha/app1/manager.log

working directory on MySQL servers

remote_workdir=/var/log/masterha/app1

master binlog dir

master_binlog_dir=/usr/local/mysql/var

master_ip_failover_script=/usr/local/bin/master_ip_failover
report_host=/usr/local/bin/send_report
ping_interval=3

[server1]
hostname=192.168.100.1
port=3306

[server2]
hostname=192.168.100.2
port=3306
candidate_master=1

[server3]
hostname=192.168.100.3
port=3306

no_master=1

[/shell]
メイン設定パラメータ詳細はこちら参照のこと

※他にあったほうがいいかもしれないパラメータ
secondary_check_script
 2つ目のインターフェースからもチェックしてくれるスクリプトとホストを指定。
ignore_fail
 2つ目のスレーブが落ちてもマスタが落ちたら切り替えたい場合に無視していいスレーブに指定
shutdown_script
 SplitBrainなどを防ぐ目的でmasterを完全に落としておきたいなどの場合にこのオプションでスクリプトを指定するといい模様

VIPを切り替えるスクリプト
[shell]

# vi /usr/local/bin/master_ip_failover

#!/usr/bin/env perl

use strict;
use warnings FATAL => ‘all’;

use Getopt::Long;

my (
$command, $ssh_user, $orig_master_host, $orig_master_ip,
$orig_master_port, $new_master_host, $new_master_ip, $new_master_port
);

my $vip = ‘192.168.100.5/24’; # Virtual IP
my $key = "1";
my $ssh_start_vip = "sudo /sbin/ifconfig eth1:$key $vip";
my $ssh_stop_vip = "sudo /sbin/ifconfig eth1:$key down";
my $ssh_stop_mysqld = "sudo /sbin/service mysqld stop";

GetOptions(
‘command=s’ => \$command,
‘ssh_user=s’ => \$ssh_user,
‘orig_master_host=s’ => \$orig_master_host,
‘orig_master_ip=s’ => \$orig_master_ip,
‘orig_master_port=i’ => \$orig_master_port,
‘new_master_host=s’ => \$new_master_host,
‘new_master_ip=s’ => \$new_master_ip,
‘new_master_port=i’ => \$new_master_port,
);

exit &main();

sub main {

print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";

if ( $command eq "stop" || $command eq "stopssh" ) {

$orig_master_host, $orig_master_ip, $orig_master_port are passed.

# If you manage master ip address at global catalog database,
# invalidate orig_master_ip here.
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
eval {
&stop_vip();
print "Stop mysqld on old master: $orig_master_host \n";
system("ssh $ssh_user\@$orig_master_host \" $ssh_stop_mysqld \"");
};
system("/usr/local/bin/mod_lvs_weight.sh");
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";

exit $exit_code;

}

exit $exit_code;

}
elsif ( $command eq "start" ) {

all arguments are passed.

# If you manage master ip address at global catalog database,
# activate new_master_ip here.
# You can also grant write access (create user, set read_only=0, etc) here.
my $exit_code = 10;
eval {
print "Enabling the VIP – $vip on the new master – $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";

ssh $ssh_user\@gentoo8 \" $ssh_start_vip \";

exit 0;
}
else {
&usage();
exit 1;
}
}

A simple system call that enable the VIP on the new master

sub start_vip() {
ssh $ssh_user\@$new_master_host \" $ssh_start_vip \";
}

A simple system call that disable the VIP on the old_master

sub stop_vip() {
ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \";
}

sub usage {
print
"Usage: master_ip_failover –command=start|stop|stopssh|status –orig_master_host=host –orig_master_ip=ip –orig_master_port=port –new_master_host=host –new_master_ip=ip –new_master_port=port\n";

}

[/shell]
※IPやIFとmysqlを落とす、LVSの重みを変更するなどの処理部分は必要に応じ変更のこと。
元のスクリプト

VIPを切替るスクリプトから呼ばれるLVSの重みを変えるスクリプト
[shell]

# vi /usr/local/bin/mod_lvs_weight.sh

#!/bin/bash
#

this script is kicked from master_ip_failover-script.

script-task: modify lvs-weight and backup-script-weight from admin-server.

isao-unyou 2012.11.5 – Creation

#

please modify.(and check the ldirectod.cf.failover!)

TITLE=TEST
READVIP=192.168.100.8
LVSSRV1=192.168.100.6
LVSSRV2=192.168.100.7
NIC=eth1
DB1=192.168.100.1
DB2=192.168.100.2
DB3=192.168.100.3
NETWORK=192.168.100
LVS_CF=/etc/ha.d/ldirectord.cf
MAILADDR=XXXX@isao.net
BKUPSRV=192.168.100.3
BKUP_SH=/opt/bin/mysql-back.sh
DB1_WEIGHT=0
DB2_WEIGHT=2
DB3_WEIGHT=4
BK_WEIGHT=4
MHA_LOG=/var/log/masterha/app1/manager.log

read vip server check

srv_chk()
{
RVIP_CHK=ssh $LVSSRV1 ip addr show $NIC|grep $READVIP|awk '{print $2}'|awk -F / '{print $1}'
if [ "$READVIP" = "$RVIP_CHK" ];then
LVSSRV=$LVSSRV1
LVSBKSRV=$LVSSRV2
RVIP_CHK2=ssh $LVSSRV2 ip addr show $NIC|grep $READVIP|awk '{print $2}'|awk -F / '{print $1}'
if [ "$READVIP" = "$RVIP_CHK2" ];then
echo "LANG=C;date: LVS read vip split-brain uname -n." \
| mail -s "NG_READ_VIP $READVIP" $MAILADDR
echo ‘ERROR: LVS read vip split-brain. ‘
exit 1
fi
else
RVIP_CHK2=ssh $LVSSRV2 ip addr show $NIC|grep $READVIP|awk '{print $2}'|awk -F / '{print $1}'
if [ "$READVIP" = "$RVIP_CHK2" ];then
LVSSRV=$LVSSRV2
LVSBKSRV=$LVSSRV1
else
echo "LANG=C;date: LVS read vip unknown uname -n." \
| mail -s "NG_READ_VIP $READVIP" $MAILADDR
echo ‘ERROR: LVS read vip unknown. ‘
exit 1
fi
fi
}

modify lvs-weight and mail to unyou.(lvs weight info)

mod_weight()
{
ssh $LVSSRV "ipvsadm -e -t $READVIP:3306 -r $DB1 -g -w $DB1_WEIGHT"
ssh $LVSSRV "ipvsadm -e -t $READVIP:3306 -r $DB2 -g -w $DB2_WEIGHT"
ssh $LVSSRV "ipvsadm -e -t $READVIP:3306 -r $DB3 -g -w $DB3_WEIGHT"
ssh $LVSSRV "cp -p $LVS_CF{,.date +%Y%m%d.%H%M} \
&& \cp -pf $LVS_CF.failover $LVS_CF \
&& service ldirectord force-reload" \
&& scp -Cp $LVSSRV:$LVS_CF /tmp/ \
&& scp -Cp /tmp/ldirectord.cf $LVSBKSRV:/etc/ha.d/
echo -e "LANG=C;date\nCurrent weights: \n\n ssh $LVSSRV ipvsadm -Ln" \
| mail -s "$TITLE mysql-master Failover. modify LVS and bkupscript weight." $MAILADDR

modify backup-script.

#ssh $BKUPSRV "cp -p $BKUP_SH{,.date +%Y%m%d.%H%M} && sed -i \"s/WEIGHT=[0-9]{1,100}/WEIGHT=$BK_WEIGHT/g\" $BKUP_SH"
}

main

exec >> $MHA_LOG
exec 2>&1
echo "START lvs weight modify. date '+%Y%m%d %T'"
srv_chk
mod_weight
echo "END lvs weight modify. date '+%Y%m%d %T'"

exit 0

chmod +x /usr/local/bin/mod_lvs_weight.sh

[/shell]

レポートメールを送るスクリプト

[shell]# vi /usr/local/bin/send_report

#!/usr/bin/perl

Note: This is a sample script and is not complete. Modify the script based on your environment.

use strict;
use warnings FATAL => ‘all’;

use Getopt::Long;

#new_master_host and new_slave_hosts are set only when recovering master succeeded
my ( $dead_master_host, $new_master_host, $new_slave_hosts, $subject, $body );
GetOptions(
‘orig_master_host=s’ => \$dead_master_host,
‘new_master_host=s’ => \$new_master_host,
‘new_slave_hosts=s’ => \$new_slave_hosts,
‘subject=s’ => \$subject,
‘body=s’ => \$body,
);

Do whatever you want here

#my $vip = /sbin/ip addr show eth0;
my $vip = /usr/bin/ssh $new_master_host /sbin/ip addr show eth0;
my $datetime = /bin/date +%Y%m%d_%H:%M:%S;
my $manager_cnf=’/etc/app1.cnf’;
my $manager_workdir=grep manager_workdir $manager_cnf|sed -e 's/[^=]*=//g';
my $remote_workdir=grep remote_workdir $manager_cnf|sed -e 's/[^=]*=//g';
my $sendmail = ‘/usr/sbin/sendmail’; # sendmailコマンドパス
my $from = ‘hoge@isao.net’; # 送信元メールアドレス
#my $to = ‘hoge@isao.co.jp’; # あて先メールアドレス
my $to = ‘hoge@isao.net’; # あて先メールアドレス
my $cc = ‘hoge@ezweb.ne.jp’; # Ccのあて先メールアドレス
#$subject = ‘test’; # メールの件名
#$msg = <<"TEXT"; # メールの本文(ヒアドキュメントで変数に代入)
#message
#_TEXT_

sendmail コマンド起動

open(SDML,"| $sendmail -t -i") || die ‘sendmail error’;

メールヘッダ出力

print SDML "From: $from\n";
print SDML "To: $to\n";
print SDML "Cc: $cc\n";
print SDML "Subject: $subject $datetime\n";
print SDML "Content-Transfer-Encoding: 7bit\n";
print SDML "Content-Type: text/plain;charset=\"ISO-2022-JP\"\n\n";

メール本文出力

#print SDML "$msg";
print SDML "$body";
print SDML "\n";
print SDML "ip addr show eth0:\n";
print SDML " $vip";
print SDML "\n";
print SDML " manager_workdir:\n";
print SDML /bin/ls -l $manager_workdir\n;
print SDML " remote_workdir:\n";
print SDML /bin/ls -l $remote_workdir\n;

sendmail コマンド閉じる

close(SDML);

exit 0;
——————————————[/shell]
※tarからダウンロードしてきたものに追記。
※適宜、sendmailのセットアップとレポートが送付されるか動作確認する。

⑤ 設定変更(ノード)
・sudo設定
[shell]

# visudo

Defaults requiretty

#Defaults requiretty

[/shell]
※ssh越しにsudoして以下のメッセージが出る場合の設定(master_ip_failoverスクリプトを利用する場合に必要)
sudo: sorry, you must have a tty to run sudo

・mysql的な初期ユーザ設定(ノード側)
rootでセグメント許可でgrantつけず(mysqlのユーザ名はrootでなくても大丈夫)
[sql]

mysql -u root -p

GRANT ALL PRIVILEGES ON . TO ‘root’@’192.168.100.%’ IDENTIFIED BY ‘****’;
select User,Host,Password from mysql.user;
[/sql]
・レプリケーション構築
masterのログファイルとポジションを確認
マスタ
[sql]
RESET MASTER;
show master status;
[/sql]
ログファイル名とポジションを念のため確認・記録しておく

slaveサーバ上でmasterの情報を指定、replicationの開始
スレーブ
[sql]
RESET MASTER;
show master status;

CHANGE MASTER TO MASTER_HOST=’マスタのIPアドレス’,
MASTER_USER=’repl’,
MASTER_PASSWORD=’******’,
MASTER_LOG_FILE=’mysql-bin.000001′,
MASTER_LOG_POS=106;
START SLAVE;
show slave status\G
set global read_only=1;
show global variables like ‘read_only’;
[/sql]
初期状態であればreset master; reset slave;してポジションをあわせるだけでよい。
データがあるならマスタでポジション記録後mysqldumpでデータを取り出し転送してmysqlでデータ投入してポジションをあわせてからslave開始。
Replicate_Ignore_DBなどフィルタリングルールは共通である必要がある

・リレーログの切り回し設定
purge_relay_logsはmha導入時にノードに設定したリレーログを消さなくする設定への補完コマンド。
マスタが切り替わったときにリレーログはマスタとの差分を補完するために利用されるので必要なため消さないようにする。
[shell]

mysql -u root -pcat /path_to_file

set global relay_log_purge=0;
show global variables like ‘relay_log%’;

ls -l /var/lib/mysql/mysqld-relay-bin.*

/usr/bin/perl /usr/bin/purge_relay_logs –user=root –password=cat /path_to_file –disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1

ls -l /var/lib/mysql/mysqld-relay-bin.*

tail /var/log/masterha/purge_relay_logs.log

crontab -e

———-slave1———-
30 2,4,6,10,14,16 * * * /usr/bin/perl /usr/bin/purge_relay_logs –user=root –password=cat /path_to_file –disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1
———-slave2———-

30 3,5,9,11,15,17 * * * /usr/bin/perl /usr/bin/purge_relay_logs –user=root –password=cat /path_to_file –disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1

[/shell]
※スレーブ間で異なる時間にcronを呼び出すことを推奨される。(すべてのスレーブが同時にpurge_relay_logsを起動した場合は、スレーブのいずれもクラッシュ時に必要なリレーログイベントを持っていないていない場合がある。)
※他の集計バッチなどとタイミングがかぶらないように要注意。(負荷的に)
もしリレーログがたまりすぎて問題が起きてしまうような場合、1時間おきに実施する方向とするなど。
※マスタをきり戻さない運用の場合はマスタにもコメントアウト状態で時間をずらして登録しておくとよい。
※ioDriveなどにマウントしてて/var/tmpのしたにハードリンクできない場合、–workdirオプションでマウントしてるディレクトリを指定する必要がある。

purge_relay_logsコマンドオプションや仕様の詳細はこちら参照のこと

リレーログの仕様
http://dev.mysql.com/doc/refman/5.1/ja/slave-logs-relaylog.html
http://open-groove.net/mysql/binlog-relay-log/

つづきは切り替えテストです。

・参考URL
mha-for-mysqldena
MHA for MySQL: Master High Availability Manager and tools for MySQL
MySQL-MHAの導入
MySQL-MHAを自社環境へ適用する際に考慮すること
MySQL-MHAを試してみる
MySQL-MHAを利用してMySQLの自動フェイルオーバーを実現してみた
NHNテクノロジーカンファレンスで見たDeNAのMySQL運用の話とAmazon RDSの比較など。
mysql-mhaを入れてみた! その2
MHA, Murakumo & Me
atomd / master_ip_failover
MySQLレプリケーションをMHAとHAProxyでフェイルオーバさせてみた
MySQL を MHA + HAProxy で冗長化してみよう
MHA(MasterHighAvailabilityManager)の導入設定
使用バージョン:mha4mysql-manager-0.53-0、MySQL-5.5
mha-img1


①簡単な利点などの解説

MHAとはmysqlのマスタ障害時に最新のスレーブをマスタとして他のスレーブの差分を補完しマスタの向き先を変えてくれるプロダクト。
Heartbeat+mon+mysqlに比べるとreplicationの再構成も行ってくれるので切り替わってもDBがシングルにならないのが利点。(3台以上の構成の場合)

作者のスライド
公式サイト
MHAの制約:mysql5.0以上、SBR(ステートメントベースレプリケーション)の場合LOAD DATA INFILEを使えない
※マネージャはadminサーバ、ノードはDBサーバ(マスタ・スレーブ共通)

② マネージャにてインストール    ※以下、admサーバから実施

・インストール
[php]

wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53-0.noarch.rpm

wget http://mysql-master-ha.googlecode.com/files/mha4mysql-manager-0.53-0.noarch.rpm

yum –enablerepo=rpmforge install \

perl-Config-Tiny \
perl-Time-HiRes \
perl-Log-Dispatch \
perl-Parallel-ForkManager \
perl-Params-Validate

yum install perl-DBD-MySQL

rpm -ivh mha4mysql*

[/php]
入ってなかったら

[shell]yum install –enablerepo=remi mysql mysql-server perl-DBD-MySQL[/shell]
※マネージャはmysql-serverいらないかも

③ ノードにてインストール ※以下、dbサーバから実施
[shell]

wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53-0.noarch.rpm

rpm -ivh mha4mysql-node*

[/shell]
④ 設定変更(マネージャ)

・ssh公開鍵設定
マネジャからノードにrootで鍵なしログインできる必要がある
鍵を作成し(ssh-keygen -t rsa -N “”)
各ノードにて公開鍵(~.pub)を公開鍵リング(/root/.ssh/authorized_keys)に追記

・設定ファイルとスクリプトの設置
[shell]

# vi /etc/app1.cnf

[server default]

mysql user and password

user=root
password=
ssh_user=root

working directory on the manager

manager_workdir=/var/log/masterha/app1
manager_log=/var/log/masterha/app1/manager.log

working directory on MySQL servers

remote_workdir=/var/log/masterha/app1

master binlog dir

master_binlog_dir=/usr/local/mysql/var

master_ip_failover_script=/usr/local/bin/master_ip_failover
report_host=/usr/local/bin/send_report
ping_interval=3

[server1]
hostname=192.168.100.1
port=3306

[server2]
hostname=192.168.100.2
port=3306
candidate_master=1

[server3]
hostname=192.168.100.3
port=3306

no_master=1

[/shell]
メイン設定パラメータ詳細はこちら参照のこと

※他にあったほうがいいかもしれないパラメータ
secondary_check_script
 2つ目のインターフェースからもチェックしてくれるスクリプトとホストを指定
ignore_fail
 2つ目のスレーブが落ちてもマスタが落ちたら切り替えたい場合に無視していいスレーブに指定

VIPを切り替えるスクリプト
[shell]

# vi /usr/local/bin/master_ip_failover

#!/usr/bin/env perl

use strict;
use warnings FATAL => ‘all’;

use Getopt::Long;

my (
$command, $ssh_user, $orig_master_host, $orig_master_ip,
$orig_master_port, $new_master_host, $new_master_ip, $new_master_port
);

my $vip = ‘192.168.100.5/24’; # Virtual IP
my $key = "1";
my $ssh_start_vip = "sudo /sbin/ifconfig eth1:$key $vip";
my $ssh_stop_vip = "sudo /sbin/ifconfig eth1:$key down";
my $ssh_stop_mysqld = "sudo /sbin/service mysqld stop";

GetOptions(
‘command=s’ => \$command,
‘ssh_user=s’ => \$ssh_user,
‘orig_master_host=s’ => \$orig_master_host,
‘orig_master_ip=s’ => \$orig_master_ip,
‘orig_master_port=i’ => \$orig_master_port,
‘new_master_host=s’ => \$new_master_host,
‘new_master_ip=s’ => \$new_master_ip,
‘new_master_port=i’ => \$new_master_port,
);

exit &main();

sub main {

print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";

if ( $command eq "stop" || $command eq "stopssh" ) {

$orig_master_host, $orig_master_ip, $orig_master_port are passed.

# If you manage master ip address at global catalog database,
# invalidate orig_master_ip here.
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
eval {
&stop_vip();
print "Stop mysqld on old master: $orig_master_host \n";
system("ssh $ssh_user\@$orig_master_host \" $ssh_stop_mysqld \"");
};
system("/usr/local/bin/mod_lvs_weight.sh");
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";

exit $exit_code;

}

exit $exit_code;

}
elsif ( $command eq "start" ) {

all arguments are passed.

# If you manage master ip address at global catalog database,
# activate new_master_ip here.
# You can also grant write access (create user, set read_only=0, etc) here.
my $exit_code = 10;
eval {
print "Enabling the VIP – $vip on the new master – $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";

ssh $ssh_user\@gentoo8 \&quot; $ssh_start_vip \&quot;;

exit 0;
}
else {
&usage();
exit 1;
}
}

A simple system call that enable the VIP on the new master

sub start_vip() {
ssh $ssh_user\@$new_master_host \&quot; $ssh_start_vip \&quot;;
}

A simple system call that disable the VIP on the old_master

sub stop_vip() {
ssh $ssh_user\@$orig_master_host \&quot; $ssh_stop_vip \&quot;;
}

sub usage {
print
"Usage: master_ip_failover –command=start|stop|stopssh|status –orig_master_host=host –orig_master_ip=ip –orig_master_port=port –new_master_host=host –new_master_ip=ip –new_master_port=port\n";

}

[/shell]
※IPやIFとmysqlを落とす、LVSの重みを変更するなどの処理部分は必要に応じ変更のこと。
元のスクリプト

VIPを切替るスクリプトから呼ばれるLVSの重みを変えるスクリプト
[shell]

# vi /usr/local/bin/mod_lvs_weight.sh

#!/bin/bash
#

this script is kicked from master_ip_failover-script.

script-task: modify lvs-weight and backup-script-weight from admin-server.

isao-unyou 2012.11.5 – Creation

#

please modify.(and check the ldirectod.cf.failover!)

TITLE=TEST
READVIP=192.168.100.8
LVSSRV1=192.168.100.6
LVSSRV2=192.168.100.7
NIC=eth1
DB1=192.168.100.1
DB2=192.168.100.2
DB3=192.168.100.3
NETWORK=192.168.100
LVS_CF=/etc/ha.d/ldirectord.cf
MAILADDR=XXXX@isao.net
BKUPSRV=192.168.100.3
BKUP_SH=/opt/bin/mysql-back.sh
DB1_WEIGHT=0
DB2_WEIGHT=2
DB3_WEIGHT=4
BK_WEIGHT=4
MHA_LOG=/var/log/masterha/app1/manager.log

read vip server check

srv_chk()
{
RVIP_CHK=ssh $LVSSRV1 ip addr show $NIC|grep $READVIP|awk '{print $2}'|awk -F / '{print $1}'
if [ "$READVIP" = "$RVIP_CHK" ];then
LVSSRV=$LVSSRV1
LVSBKSRV=$LVSSRV2
RVIP_CHK2=ssh $LVSSRV2 ip addr show $NIC|grep $READVIP|awk '{print $2}'|awk -F / '{print $1}'
if [ "$READVIP" = "$RVIP_CHK2" ];then
echo "LANG=C;date: LVS read vip split-brain uname -n." \
| mail -s "NG_READ_VIP $READVIP" $MAILADDR
echo ‘ERROR: LVS read vip split-brain. ‘
exit 1
fi
else
RVIP_CHK2=ssh $LVSSRV2 ip addr show $NIC|grep $READVIP|awk '{print $2}'|awk -F / '{print $1}'
if [ "$READVIP" = "$RVIP_CHK2" ];then
LVSSRV=$LVSSRV2
LVSBKSRV=$LVSSRV1
else
echo "LANG=C;date: LVS read vip unknown uname -n." \
| mail -s "NG_READ_VIP $READVIP" $MAILADDR
echo ‘ERROR: LVS read vip unknown. ‘
exit 1
fi
fi
}

modify lvs-weight and mail to unyou.(lvs weight info)

mod_weight()
{
ssh $LVSSRV "ipvsadm -e -t $READVIP:3306 -r $DB1 -g -w $DB1_WEIGHT"
ssh $LVSSRV "ipvsadm -e -t $READVIP:3306 -r $DB2 -g -w $DB2_WEIGHT"
ssh $LVSSRV "ipvsadm -e -t $READVIP:3306 -r $DB3 -g -w $DB3_WEIGHT"
ssh $LVSSRV "cp -p $LVS_CF{,.date +%Y%m%d.%H%M} \
&& \cp -pf $LVS_CF.failover $LVS_CF \
&& service ldirectord force-reload" \
&& scp -Cp $LVSSRV:$LVS_CF /tmp/ \
&& scp -Cp /tmp/ldirectord.cf $LVSBKSRV:/etc/ha.d/
echo -e "LANG=C;date\nCurrent weights: \n\n ssh $LVSSRV ipvsadm -Ln" \
| mail -s "$TITLE mysql-master Failover. modify LVS and bkupscript weight." $MAILADDR

modify backup-script.

#ssh $BKUPSRV "cp -p $BKUP_SH{,.date +%Y%m%d.%H%M} && sed -i \"s/WEIGHT=[0-9]{1,100}/WEIGHT=$BK_WEIGHT/g\" $BKUP_SH"
}

main

exec >> $MHA_LOG
exec 2>&1
echo "START lvs weight modify. date '+%Y%m%d %T'"
srv_chk
mod_weight
echo "END lvs weight modify. date '+%Y%m%d %T'"

exit 0

chmod +x /usr/local/bin/mod_lvs_weight.sh

[/shell]

レポートメールを送るスクリプト

[shell]# vi /usr/local/bin/send_report

#!/usr/bin/perl

Note: This is a sample script and is not complete. Modify the script based on your environment.

use strict;
use warnings FATAL => ‘all’;

use Getopt::Long;

#new_master_host and new_slave_hosts are set only when recovering master succeeded
my ( $dead_master_host, $new_master_host, $new_slave_hosts, $subject, $body );
GetOptions(
‘orig_master_host=s’ => \$dead_master_host,
‘new_master_host=s’ => \$new_master_host,
‘new_slave_hosts=s’ => \$new_slave_hosts,
‘subject=s’ => \$subject,
‘body=s’ => \$body,
);

Do whatever you want here

#my $vip = /sbin/ip addr show eth0;
my $vip = /usr/bin/ssh $new_master_host /sbin/ip addr show eth0;
my $datetime = /bin/date +%Y%m%d_%H:%M:%S;
my $manager_cnf=’/etc/app1.cnf’;
my $manager_workdir=grep manager_workdir $manager_cnf|sed -e 's/[^=]*=//g';
my $remote_workdir=grep remote_workdir $manager_cnf|sed -e 's/[^=]*=//g';
my $sendmail = ‘/usr/sbin/sendmail’; # sendmailコマンドパス
my $from = ‘unyou-all@isao.net’; # 送信元メールアドレス
#my $to = ‘komiyay@isao.co.jp’; # あて先メールアドレス
my $to = ‘unyou-all@isao.net’; # あて先メールアドレス
my $cc = ‘komi325_y@ezweb.ne.jp’; # Ccのあて先メールアドレス
#$subject = ‘test’; # メールの件名
#$msg = <<"TEXT"; # メールの本文(ヒアドキュメントで変数に代入)
#message
#_TEXT_

sendmail コマンド起動

open(SDML,"| $sendmail -t -i") || die ‘sendmail error’;

メールヘッダ出力

print SDML "From: $from\n";
print SDML "To: $to\n";
print SDML "Cc: $cc\n";
print SDML "Subject: $subject $datetime\n";
print SDML "Content-Transfer-Encoding: 7bit\n";
print SDML "Content-Type: text/plain;charset=\"ISO-2022-JP\"\n\n";

メール本文出力

#print SDML "$msg";
print SDML "$body";
print SDML "\n";
print SDML "ip addr show eth0:\n";
print SDML " $vip";
print SDML "\n";
print SDML " manager_workdir:\n";
print SDML /bin/ls -l $manager_workdir\n;
print SDML " remote_workdir:\n";
print SDML /bin/ls -l $remote_workdir\n;

sendmail コマンド閉じる

close(SDML);

exit 0;
——————————————[/shell]
※tarからダウンロードしてきたものに追記。
※適宜、sendmailのセットアップとレポートが送付されるか動作確認する。

⑤ 設定変更(ノード)
・sudo設定
[shell]

# visudo

Defaults requiretty

#Defaults requiretty

[/shell]
※ssh越しにsudoして以下のメッセージが出る場合の設定(master_ip_failoverスクリプトを利用する場合に必要)
sudo: sorry, you must have a tty to run sudo

・mysql的な初期ユーザ設定(ノード側)
rootでセグメント許可でgrantつけず(mysqlのユーザ名はrootでなくても大丈夫)
[sql]

mysql -u root -p

GRANT ALL PRIVILEGES ON . TO ‘root’@’192.168.100.%’ IDENTIFIED BY ‘****’;
select User,Host,Password from mysql.user;
[/sql]
・レプリケーション構築
masterのログファイルとポジションを確認
マスタ
[sql]
RESET MASTER;
show master status;
[/sql]
ログファイル名とポジションを念のため確認・記録しておく

slaveサーバ上でmasterの情報を指定、replicationの開始
スレーブ
[sql]
RESET MASTER;
show master status;

CHANGE MASTER TO MASTER_HOST=’マスタのIPアドレス’,
MASTER_USER=’repl’,
MASTER_PASSWORD=’******’,
MASTER_LOG_FILE=’mysql-bin.000001′,
MASTER_LOG_POS=106;
START SLAVE;
show slave status\G
set global read_only=1;
show global variables like ‘read_only’;
[/sql]
初期状態であればreset master; reset slave;してポジションをあわせるだけでよい。
データがあるならマスタでポジション記録後mysqldumpでデータを取り出し転送してmysqlでデータ投入してポジションをあわせてからslave開始。
Replicate_Ignore_DBなどフィルタリングルールは共通である必要がある

・リレーログの切り回し設定
purge_relay_logsはmha導入時にノードに設定したリレーログを消さなくする設定への補完コマンド。
マスタが切り替わったときにリレーログはマスタとの差分を補完するために利用されるので必要なため消さないようにする。
[shell]

mysql -u root -pcat /path_to_file

set global relay_log_purge=0;
show global variables like ‘relay_log%’;

ls -l /var/lib/mysql/mysqld-relay-bin.*

/usr/bin/perl /usr/bin/purge_relay_logs –user=root –password=cat /path_to_file –disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1

ls -l /var/lib/mysql/mysqld-relay-bin.*

tail /var/log/masterha/purge_relay_logs.log

crontab -e

———-slave1———-
30 2,4,6,10,14,16 * * * /usr/bin/perl /usr/bin/purge_relay_logs –user=root –password=cat /path_to_file –disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1
———-slave2———-

30 3,5,9,11,15,17 * * * /usr/bin/perl /usr/bin/purge_relay_logs –user=root –password=cat /path_to_file –disable_relay_log_purge >> /var/log/masterha/purge_relay_logs.log 2>&1

[/shell]
※スレーブ間で異なる時間にcronを呼び出すことを推奨される。(すべてのスレーブが同時にpurge_relay_logsを起動した場合は、スレーブのいずれもクラッシュ時に必要なリレーログイベントを持っていないていない場合がある。)
※他の集計バッチなどとタイミングがかぶらないように要注意。(負荷的に)
もしリレーログがたまりすぎて問題が起きてしまうような場合、1時間おきに実施する方向とするなど。
※マスタをきり戻さない運用の場合はマスタにもコメントアウト状態で時間をずらして登録しておくとよい。
※ioDriveなどにマウントしてて/var/tmpのしたにハードリンクできない場合、–workdirオプションでマウントしてるディレクトリを指定する必要がある。

purge_relay_logsコマンドオプションや仕様の詳細はこちら参照のこと

リレーログの仕様
http://dev.mysql.com/doc/refman/5.1/ja/slave-logs-relaylog.html
http://open-groove.net/mysql/binlog-relay-log/

つづきは切り替えテストです。

・参考URL
mha-for-mysqldena
MHA for MySQL: Master High Availability Manager and tools for MySQL
MySQL-MHAの導入
MySQL-MHAを自社環境へ適用する際に考慮すること
MySQL-MHAを試してみる
MySQL-MHAを利用してMySQLの自動フェイルオーバーを実現してみた
NHNテクノロジーカンファレンスで見たDeNAのMySQL運用の話とAmazon RDSの比較など。
mysql-mhaを入れてみた! その2
MHA, Murakumo & Me
atomd / master_ip_failover
MySQLレプリケーションをMHAとHAProxyでフェイルオーバさせてみた
MySQL を MHA + HAProxy で冗長化してみよう

おすすめ記事