Aller au contenu | Aller au menu

/var/log/greg.log

Re-synchroniser une table sur un slave MySQL

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é !

Réplication MySQL multiple sources

Trop de données, trop d'écritures, la solution la plus rapide et facile à mettre en place consiste à déplacer des tables sur d'autres serveurs. Ainsi, on s'est retrouvé avec plusieurs "bulles" composées d'un master et de N slaves. Ce qui complique un peu quand même.

Déjà, les backups. Maintenant, il faut un slave supplémentaire par bulle pour le backup. Rappel: il faut arrêter la réplication pour avoir un bon backup capable de repartir, de reconfigurer un slave from scratch.

Autre problème, bien plus complexe: souvent, notamment pour les statistiques, il faut faire de grosses requêtes avec des JOINs inter tables et inter base de donnée.

Il existe des solutions à ces problèmes, rajouter des slaves, faire de la consolidation de donnée par batch pour les stats... et le multiple source replication. Cette fonctionnalité est hyper demandé chez MySQL, comme on peut le voir sur le worklog, il est d'ailleur en 1ère position !

Ca fait quelques semaines que je suis sur un script pour émuler le multiple source. En fait, plutôt que de me taper le protocole, j'utilise directement le binaire mysqlbinlog fournit avec mysql, qui permet de se connecter à un master, de lui demander les logs. On peut même lui demander les logs à partir d'un fichier précis, d'une position précise, et jusqu'à ce qu'il en ai plus !! Ce script utilise une base de donnée MySQL pour stocker les informations relatives à la réplication: position en cours, position suivante, fichier de log, erreurs... Il est capable de répliquer depuis plusieurs master (pas vraiment de limite, si ce n'est les performances du slave), mais attention, il se contente de lire les logs et de les executer, il est donc super préférable d'avoir des noms de base de données distinctes sur chaque master !

slave A ------- db a, b, c -------> \
slave B ------- db d, e ---------->  > msr slave
slave C ------- all db -----------> /

Vous trouverez les sources sur Rubyforge. Ce script tourne en environnement de production répliquant 3 slaves et 5 bases de données. J'ai fais quelques tests d'intégrité de données et n'ai pas constaté d'erreurs !

Ca bouge chez MySQL !

Ces 2 dernières semaines ont été bien mouvementées chez MySQL !

Sortie de la 5.1.31

Cette version est importante car elle corrige de nombreux bugs critiques de la version GA 5.1.30, qui n'était tout simplement... pas stable. Cette nouvelle version est sortie le 19 janvier mais n'est apparu sur le site que bien plus tard... Il faut mieux surveiller les mirroirs FTP. En prod sur 6 serveurs depuis fin janvier, pour l'instant aucun crash à signaler, le bug semble donc bien corrigé.

Le père de MySQL, Monty, quitte SUN

Monty quitte SUN en bon terme, et monte sa société Monty Program AB, basée sur un modèle idéaliste ou tous les employés sont actionnaire (voir le détail), et surtout, ou l'open-source a toute son importance. Monty n'abandonne pas MySQL et va se consacrer à son moteur crash safe MariaDB. Mixer MariaDB, le moteur XtraDB de Percona, le tout dans Drizzle, et on a la base de donnée la plus performante du monde :)

Marten Mikos aussi !

Marten Mikos, directeur de MySQL, vice president de la section base de donnée chez SUN, quitte SUN à son tour.

Un an après le rachat par Sun de MySQL, les départs commencent... Avaient-ils un contrat leur obligeant de rester 1 an ? Une rumeur (à prendre comme tel) parle d'un départ d'une 20ène de développeurs MySQL pour Monty Program AB.

Les gestionnaires de sessions PHP

Actuellement, pour les sessions, nous utilisons un gros serveur et MySQL avec des tables en HEAP pour stocker les sessions. Problème, ces tables ne supportent pas les types BLOB et TEXT, ce qui implique d'utilise un champ VARCHAR, limité à 255 caractères, on atteint très vite cette limite.

Je suis donc à la recherche d'alternatives, sachant qu'on va stocker plus d'informations pour éviter au maximum les cookies, et que les performances requises sont importantes: aujourd'hui environ 2000 requêtes de sessions / secondes, demain ce sera bien pire à cause du web 2.0.

MySQL Cluster

MySQL n'est pas encore sortie en version stable en 5.1, version nécéssaire pour avoir un MySQL Cluster. Avec tous les problèmes que l'on rencontre avec 5.1 (enfin, uniquement les nouvelles fonctionnalités), le temps de mise en oeuvre, le coût des serveurs, cette solution est fortement compromise. D'autant plus que MySQL n'utilise pas sa propre solution pour ses propres besoins...

Zend Cluster

Alléchant sur le papier, mais beaucoup trop cher ! Ils vont devoir s'aligner pour espérer continuer à en vendre...

memcached

http://www.danga.com/memcached/

Comme stipulé à plusieurs endroits dans la doc, memcached est un serveur de cache avant tout. Ce qui veut dire perte de données en cas d'arrêt du démon. Il a été prévu pour faire du cache, et le fait d'ailleurs très bien. Son modèle cluster est orienté scalability et pas du tout redondance ni failover. Admettons que nous avons 3 serveurs memcached en cluster, A B et C. A chaque requête PHP en écriture (ajout, remplacement d'une session), le client se connecte à tous les serveurs, créé une clef en fonction de ces serveurs, et choisis un des serveurs: B. Seul B aura la valeur pour cette clef. La requête suivante, en lecture, veut lire cette clef, le client PHP se connecte aux 3 serveurs, génère la clef, et va chercher la valeur sur B. Très bien, on répartie la charge sur ces 3 serveurs, et la mémoire n'est pas gaspillé car les données ne sont pas duppliqué. Ainsi, si B tombe, on perd uniquement les données de sessions de ce serveur, on déconnecte donc seulement 1/3 des utilisateurs. Seulement voilà, c'est pas aussi beau. Si un noeud tombe, la liste des serveurs dans le pool change, et le client va regénérer toutes les clefs !! En d'autre terme, si un noeud tombe, on perd tout le cache ! On se retrouve donc avec autant de POF (Point Of Failure) que de serveurs. Dropped.

memcachedb

http://memcachedb.org/

Reprenant le moteur de memcached, le principe est différent, et cette fois le but n'est pas de faire du cache mais de stocker des données persistentes. En mode cluster, on a un fonctionnement identique à MySQL: un noeud est maitre, les autres noeuds répliquent et peuvent être accédé en lecture. Les performances sont là, leur benchmark indique atteindre 20000 écritures / secondes, et 45000 lectures / secondes, ce qui est amplement suffisant. Mais le principe du single master to many slaves est genant: il m'arrive régulièrement de retirer un serveur de la production, pour le mettre à jour, le restaurer, ou en cas de problèmes hardware... et si c'est le master qui a un problème ? on doit créer un autre master, et changer la config des slaves afin qu'ils répliquent leurs données depuis un autre master ! Dropped.

Sharedance

http://sharedance.pureftpd.org/

Ce logiciel a été créé pour cet usage et uniquement pour cet usage. Tout comme memcached, il excèle dans son travail. Tous les commentaires que j'ai pu trouvé sur le net en font l'éloge, et surtout on retrouve tout le temps "Ca n'a jamais planté". Un utilisateur atteint 200Mbps x 2 sur un seul serveur, époustouflant ! C'est la solution quasiment idéal... et oui, le soucis, c'est que c'est un SPOF ! Si ce serveur tombe, on n'a plus de sessions. Alors on pourrait implémenter un 2ème serveur avec Heartbeat, mais ce 2ème serveur n'aurait pas les données, en cas de crash on déconnecte alors tout le monde. Sharedance reste pour l'instant la meilleur solution, même si je ne l'ai pas encore testée, ça ne saurait tardé. Il manquerait une réplication type DRBD sur une partition tmpfs, pour allier performance et failover.

mcache

http://www.mohawksoft.org/?q=node/8

mcache semble le produit idéal, sur le papier. Il stock les données en ram et les copie (si besoin) sur disque régulièrement, possède un garbage collector pour supprimer les sessions périmées, et fonctionne en environnement distribué: un mcache par serveur PHP. Il faut que je le mette en place avec plusieurs noeuds, et vérifier les points suivants : si un noeud tombe, que se passe t'il ? Il faut aussi valider les performances.

Je vais donc créer plusieurs images Xen 32bits afin de tester mcache, et en parallèle tester sharedance. La suite aux prochains billets !