MySQL 从属复制重置且无主服务器停机时间(使用 MyISAM)

MySQL 从属复制重置且无主服务器停机时间(使用 MyISAM)

问题的根源:在正在运行的主服务器上创建从服务器的所有说明都需要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“关闭”时创建快照,获取主信息,然后解锁表。快照通常只需几秒钟。

相关内容