问题的根源:在正在运行的主服务器上创建从服务器的所有说明都需要flush tables with read lock
。我们使用 MyISAM,因此我们不能仅使用 --single transaction 来获取一致的表数据。
由于各种“正常”原因,从服务器会失败 - 平均每周一次。因此,我关闭网站,刷新表并使用读锁定主数据库,mysqldump(单个事务,带有主记录),推送到从服务器,重置主服务器(带有日志位置),然后启动从服务器,等等。
为了在主服务器不停机的情况下完成此操作,我尝试了基本相同的步骤,然后使用START SLAVE UNTIL
- 然后暂停实时数据库几秒钟,同时在从服务器上运行 SELECT MASTER_POS_WAIT();。然后我似乎无法让从服务器恢复运行。
以下步骤中缺少(或不需要)什么来让从属数据库再次赶上主数据库?简单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;
答案1
有两种选择
替代方案 #1:使用超级备份
它能够在正在运行的主服务器上复制 MyISAM 以及 InnoDB。
替代方案 #2:多次运行 rsync
您可以在主服务器上对 /var/lib/mysql 运行 rsync,然后将其复制到从服务器上的 /var/lib/mysql。当然,我会多次运行 rsync。在最后一次 rsync 之前,您应该运行 FLUSH TABLES WITH READ LOCK。复制之前,请确保清除所有二进制日志并从头开始。
在运行任何操作之前,请确保二进制日志已写入主服务器和从服务器的 /var/lib/mysql 中,方法是在 /etc/my.cnf 中包含以下内容:
[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};"
在执行此操作时,我对缓存数据和索引页的态度比较保守。就我个人而言,我更喜欢在几次 rsync 之后关闭 mysql,而不是使用 FLUSH TABLES WITH READ LOCK。此脚本的另一种替代方案是以下脚本,它会在最后一次 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 缓冲池中分页出未提交的数据。
答案2
如果您的数据目录位于允许快照的文件系统上(例如 ZFS 或 LVM),那么您可以在 MySQL“关闭”时创建快照,获取主信息,然后解锁表。快照通常只需几秒钟。