Redefinição de replicação de escravo do MySQL sem tempo de inatividade mestre (usando MyISAM)

6

Raiz do problema: Em todas as instruções para criar um escravo em um mestre em execução, é necessário flush tables with read lock . Usamos o MyISAM, portanto, não podemos simplesmente usar a transação única para obter dados de tabela consistentes.

Um escravo falha por todos os tipos de razões "normais" - em média, cerca de uma vez por semana. Então eu derrubo o site, flush table with read lock o master db, mysqldump (transação única, com registro mestre), push para slave, reset o master (com posições de log), e start slave, etc.

Para fazer isso sem o tempo de inatividade, tentei basicamente as mesmas etapas, depois use START SLAVE UNTIL - depois pausando o banco de dados ao vivo por alguns segundos enquanto executo SELECT MASTER_POS_WAIT (); no escravo. Eu não posso, então, conseguir que o escravo alcance novamente.

O que está faltando (ou desnecessário) nas etapas abaixo para fazer com que o banco de dados escravo alcance o mestre novamente? Um simples start slave funcionaria?

#!/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;
    
por Jonathan Hendler 08.07.2011 / 05:33

2 respostas

5

Existem duas alternativas

ALTERNATIVA # 1: Use o XtraBackup

É capaz de copiar o MyISAM, assim como o InnoDB, em um mestre em execução.

ALTERNATIVA # 2: Execute várias vezes o rsync

Você pode executar o rsync em / var / lib / mysql em um master e copiá-lo para / var / lib / mysql em um escravo. Claro, eu rodaria o rsync várias vezes. Até o último rsync você deve executar o FLUSH TABLES WITH READ LOCK. Antes de copiar, certifique-se de colocar todos os registros binários e começar do zero.

Antes de executar qualquer coisa, por favor, certifique-se de que os logs binários estão escritos em / var / lib / mysql no master e slave, tendo algo como o seguinte em /etc/my.cnf:

[mysqld]
log-bin=mysql-bin

Por favor, tente executar este script no caso de você não querer desligar o MySQL no master:

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};"

Sou um pouco mais conservador em termos de dados e páginas de índice armazenadas em cache ao fazer isso. Pessoalmente, eu prefiro desligar o mysql após vários rsyncs ao invés das tabelas FLUSH WITH READ LOCK. Outra alternativa para este script seria o seguinte script que desliga o mysql para o rsync final:

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

Isso é tudo para a parte do rsync do mestre. E quanto ao escravo ???

Antes de iniciar o mysql no escravo, você precisa ter o arquivo de log e a posição de log do mestre. Os registros binários que você copiou precisam, particularmente o último log binário. Aqui está como você consegue isso no escravo:

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}"

Você pode confiar nesses números porque os copiou pessoalmente do mestre. Agora que você tem o registro principal e a posição, você pode iniciar o mysql no escravo e configurar a replicação usando o arquivo de log e a posição de registro que acabou de ser reportada.

Experimente !!!

CAVEAT

Se você tiver algum dado do InnoDB, você deve definir isto cerca de 1 hora antes de tentar o rsync:

SET GLOBAL innodb_max_dirty_pages_pct = 0;

Isso fará com que o InnoDB pague dados não-consolidados do InnoDB Buffer Pool mais rápido.

    
por 08.07.2011 / 23:28
3

Se você tem seu datadir em um sistema de arquivos que permite snapshot (como ZFS ou LVM), então você pode criar um snapshot enquanto o MySQL está "inativo", pegar as informações mestras e depois desbloquear as tabelas. O instantâneo geralmente leva apenas alguns segundos.

    
por 23.12.2011 / 19:19