問題の根本:実行中のマスターでスレーブを作成するためのすべての手順で、flush tables with read lock
が必要です。 MyISAMを使用しているため、単一のトランザクションを使用して一貫性のあるテーブルデータを取得することはできません。
スレーブは、あらゆる種類の「通常の」理由で失敗します。平均して、週に1回程度です。そのため、サイトを停止し、テーブルを読み取りロックでマスターデータベースをフラッシュし、mysqldump(単一トランザクション、マスターレコードを使用)、スレーブにプッシュ、マスターをリセット(ログ位置を使用)、スレーブを開始します。
マスターダウンタイムなしでこれを行うには、基本的に同じ手順を試し、次にSTART SLAVE UNTIL
を使用します。次に、SELECT MASTER_POS_WAIT();を実行している間、ライブデータベースを数秒間一時停止します。奴隷に。そうすれば、奴隷に追いつくようには思えない。
スレーブDBが再びマスターに追いつくようにするために、以下のステップに欠けている(または不要な)ものは何ですか?単純なstart slave
は機能しますか?
#!/bin/bash
##
mysqldump --allow-keywords --add-drop-table --comments --extended-insert --master-data \
--debug-info --single-transaction -u $LOCALDB_USER_NAME -p$LOCALDB_PASS $LOCALDB_NAME > $DBFILENAME
## get master position from file for use later
echo
echo "############# MASTER STATUS #############"
cat $DBFILENAME | grep "CHANGE MASTER"
echo
echo "compressing"
gzip $DBFILENAME
echo "sending to $REMOTE_SERVER"
[...]
echo "uncompresing remote db"
Sudo ssh $REMOTE_SERVER_USERNAME@$REMOTE_SERVER "cd /tmp && gunzip /tmp/$COMPRESSED_DBFILENAME "
echo "loading external db"
Sudo ssh $REMOTE_SERVER_USERNAME@$REMOTE_SERVER "mysql -u $REMOTEDB_USER_NAME -p$REMOTEDB_PASS $REMOTEDB_NAME -e \"STOP SLAVE;\" "
Sudo ssh $REMOTE_SERVER_USERNAME@$REMOTE_SERVER "mysql -u $REMOTEDB_USER_NAME -p$REMOTEDB_PASS $REMOTEDB_NAME -e \"RESET SLAVE;\" "
Sudo ssh $REMOTE_SERVER_USERNAME@$REMOTE_SERVER "mysql -u $REMOTEDB_USER_NAME -p$REMOTEDB_PASS $REMOTEDB_NAME -e \"FLUSH LOGS;\" "
Sudo ssh $REMOTE_SERVER_USERNAME@$REMOTE_SERVER "mysql -u $REMOTEDB_USER_NAME -p$REMOTEDB_PASS $REMOTEDB_NAME < /tmp/$DBFILENAME"
echo "remote import completed"
# CHANGE MASTER TO MASTER_Host=' ', MASTER_USER='', MASTER_PASSWORD='', MASTER_LOG_FILE='mysql-bin.042025', MASTER_LOG_POS=73160995;
# START SLAVE UNTIL MASTER_LOG_FILE='mysql-bin.042025', MASTER_LOG_POS=73160995;
## on master
## FLUSH TABLES WITH READ LOCK;
## SHOW MASTER STATUS;
## select from above
## on slave:
## SELECT MASTER_POS_WAIT('mysql-bin.042136', 165900463);
## on master
## UNLOCK TABLES;
2つの選択肢があります
代替#1:使用 XtraBackup
実行中のマスターにMyISAMとInnoDBをコピーできます。
代替#2:rsyncを複数回実行します
マスターの/ var/lib/mysqlに対してrsyncを実行し、スレーブの/ var/lib/mysqlにコピーすることができます。もちろん、rsyncを数回実行します。最後のrsyncまで、読み取りロック付きのFLUSHTABLESを実行する必要があります。コピーする前に、すべてのバイナリログをホースし、最初から始めることを確認してください。
何かを実行する前に、/ etc/my.cnfに次のようにして、マスターとスレーブの両方でバイナリログが/ var/lib/mysqlに書き込まれていることを確認してください。
[mysqld]
log-bin=mysql-bin
マスターでMySQLをシャットダウンしたくない場合は、次のスクリプトを実行してみてください。
mysql -u... -p... -e"SET GLOBAL innodb_max_dirty_pages_pct = 0; RESET MASTER;"
RSYNCSTOTRY=7
cd /var/lib/mysql
X=0
while [ ${X} -lt ${RSYNCSTOTRY} ]
do
X=`echo ${X}+1|bc`
rsync -r * slaveserver:/var/lib/mysql/.
sleep 60
done
mysql -u... -p... -e"FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400);"
sleep 60
SLEEPID=`mysql -u... -p... -e"SHOW PROCESSLIST;" | grep "SELECT SLEEP(86400)" | awk '{print $1}'`
rsync -r * slaveserver:/var/lib/mysql/.
mysql -u... -p... -e"KILL ${SLEEPID};"
これを行っている間、データとインデックスページがキャッシュされるという点で私はもう少し保守的です。個人的には、FLUSH TABLES WITH READ LOCKではなく、いくつかのrsyncの後にmysqlをシャットダウンすることを好みます。このスクリプトの別の代替手段は、最後のrsyncのためにmysqlをシャットダウンする次のスクリプトです。
mysql -u... -p... -e"RESET MASTER;"
RSYNCSTOTRY=7
cd /var/lib/mysql
X=0
while [ ${X} -lt ${RSYNCSTOTRY} ]
do
X=`echo ${X}+1|bc`
rsync -r * slaveserver:/var/lib/mysql/.
sleep 60
done
service mysql stop
rsync -r * slaveserver:/var/lib/mysql/.
service mysql start
マスターからのrsync部分は以上です。奴隷はどうですか?
スレーブでmysqlを起動する前に、マスターからログファイルとログ位置を取得する必要があります。コピーしたバイナリログ、特に最後のバイナリログが必要です。スレーブで取得する方法は次のとおりです。
cd /var/lib/mysql
for X in `ls -l mysql-bin.0* | awk '{print $9}'`
do
LOGFIL=${X}
done
LOGPOS=`ls -l ${LOGFIL} | awk '{print $5}'`
echo "Master Log File ${LOGFIL} Position ${LOGPOS}"
これらの番号は、マスターから個人的にコピーしたため、信頼できます。マスターログと位置がわかったので、スレーブでmysqlを起動し、報告されたばかりのログファイルとログ位置を使用してレプリケーションをセットアップできます。
試してみる !!!
警告
InnoDBデータがある場合は、rsyncを試行する約1時間前にこれを設定する必要があります。
SET GLOBAL innodb_max_dirty_pages_pct = 0;
これにより、InnoDBはコミットされていないデータをInnoDBバッファープールからより速くページアウトします。
スナップショットを許可するファイルシステム(ZFS OR LVMなど)にdatadirがある場合は、MySQLが「ダウン」しているときにスナップショットを作成し、マスター情報を取得してから、テーブルのロックを解除できます。スナップショットは通常、数秒しかかかりません。