Сброс репликации подчиненного MySQL без основного простоя (с использованием MyISAM)
Корень проблемы: во всех инструкциях по созданию ведомого на работающем мастере требуется flush tables with read lock
, Мы используем MyISAM, поэтому мы не можем просто использовать одну транзакцию для получения согласованных данных таблицы.
Раб терпит неудачу по разным "нормальным" причинам - в среднем примерно раз в неделю. Поэтому я отключаю сайт, сбрасываю таблицу с блокировкой чтения master db, mysqldump (отдельная транзакция, с основной записью), push to slave, сбрасываю master (с позициями журнала), запускаю slave и т. Д.
Чтобы сделать это без простоя мастера, я попытался в основном те же шаги, а затем использовать 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;
2 ответа
Есть две альтернативы
АЛЬТЕРНАТИВА № 1: Используйте XtraBackup
Он способен копировать MyISAM, а также InnoDB на работающий мастер.
АЛЬТЕРНАТИВА №2: запускать rsync несколько раз
Вы можете запустить rsync для /var/lib/mysql на ведущем устройстве и скопировать его в /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};"
Я немного более консервативен в плане кэширования данных и страниц индекса при этом. Лично я предпочитаю выключать mysql после нескольких rsyncs вместо FLUSH TABLES WITH READ LOCK. Другой альтернативой этому сценарию будет следующий сценарий, который завершает работу mysql для окончательного rsync:
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, вы должны установить это примерно за 1 час до попытки rsync:
SET GLOBAL innodb_max_dirty_pages_pct = 0;
Это заставит InnoDB выгружать незафиксированные данные из пула буферов InnoDB быстрее.
Если у вас есть каталог данных в файловой системе, которая позволяет делать моментальные снимки (например, ZFS или LVM), тогда вы можете создать моментальный снимок, когда MySQL "выключен", получить основную информацию и затем разблокировать таблицы. Снимок обычно занимает всего несколько секунд.