Il arrive qu'un slave soit désynchronisé avec son master. Problème de procédure stocké, duplicate key, code qui écrit sur le slave alors qu'il n'est pas read-only... Bref, il faut re-synchroniser les tables, et pas forcément toute.
L'outil de Baron Schwartz, mk-table-checksum, permet de vérifier l'intégrité des données de multiples manières, mais partons du principe qu'on veut forcer une synchro.
Import depuis le master
C'est une des technique les plus simple: importer la table depuis le master, mais dans ce cas il faut le faire dans une seule transaction. J'ai fais un script pour ça, un peu bourrin mais simple et adapté à mon archi, qui stop la réplication, fais un dump avec la position du master, démarre la réplication jusqu'à cette position, puis import le dump :
master=$1
db=$2
table=$3
tmpfile="/tmp/tmp_dump.sql.gz"
if [ -z "$master" -o -z "$db" -o -z "$table" ]
then
exec $0 --help
fi
echo "Stop slave."
mysql -e "STOP SLAVE SQL_THREAD"
echo -e "\033[44;37;1mDumping $db.$table from $master ...\033[0m"
ssh $master "mysqldump --master-data=2 --single-transaction $db $table" | gzip -6 >$tmpfile
binlog=$( zcat $tmpfile | perl -nle "/CHANGE MASTER TO MASTER_LOG_FILE='(.+)', MASTER_LOG_POS=(\d+)/ and print \$1 and exit;" )
pos=$( zcat $tmpfile | perl -nle "/CHANGE MASTER TO MASTER_LOG_FILE='(.+)', MASTER_LOG_POS=(\d+)/ and print \$2 and exit;" )
mysql -e "START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE = '$binlog', MASTER_LOG_POS = $pos;"
echo -n "Waiting for slave to be on master's position ($binlog/$pos) "
while ! mysql --vertical -e 'show slave status' | grep Seconds_Behind_Master | grep -q NULL
do
echo -n "."
sleep 1
done
echo
echo "Inserting data ..."
zcat $tmpfile | mysql $db
echo "OK, starting slave."
while ! mysql --wait -e "START SLAVE"
do
echo "Retrying..."
sleep 1
done
rm -f $tmpfile
echo Done.
mysql --vertical -e 'show slave status' | grep Seconds_Behind_Master | tr -d " "
Ré-importer la même table sur le master
L'avantage de cette technique, c'est que la table va être re-synchroniser sur tous les slaves s'il y en a plusieurs.
L'inconvénient, c'est qu'elle oblige un lock de la table en question sur le master, le temps de l'opération. La technique consiste à re-créer la même table sous un autre nom, puis d'utiliser la fonction atomique RENAME pour remplacer l'ancienne table par la nouvelle :
CREATE TABLE t2 LIKE table_source;
START TRANSACTION;
INSERT INTO t2 SELECT * FROM table_source;
RENAME TABLE table_source TO table_back, t2 TO table_source;
COMMIT;
Si tout va bien, on peut supprimer la table table_back
.
Utiliser les scripts Maatkit - mk-table-sync
Encore un script de la suite Maatkit - devenue Percona Tools - mk-table-sync.
Là, on peut tout faire, mais il faut se farcir la doc, l'outil est puissant... Quand ça semble trop compliqué, je n'ai plus confiance, je n'ai donc jamais tenté cette technique... Il faudrait une occasion où les données ne sont pas critique, et une situation non-urgente, mais tout de même avec plusieurs transactions / seconde pour pouvoir la valider en prod, et ça ne m'est jamais arrivé !

