MariaDB : maître maître
MariaDB : maître maître jppJ'ai décidé d'installer deux serveurs MariaDB (cela ne change que peu de Mysql) pour tester une configuration multi-maîtres. Pour cela il faut d'abord installer deux machines (virtuelles) identiques. J'ai choisi d'installer une Debian "Stretch" qui devrait prochainement passer en "stable".
Description des machines :
- CPU 2
- RAM 4096GB
- Disque système 16GB ext4
- Disque DATA 32GB LVM, partition "VGDATA/MYSQL" de 24GB montée sur /DATA/mysql.
Il restera ainsi 8GB pour effectuer des "snapshots" destinés à la sauvegarde (article à suivre).
Pour faciliter l'installation (IP et nom viennent "automagiquement) j'ai créé ces machines dans le serveur dhcp et je les ai insérées dans mon serveur DNS.
Installation des machines à partir d'une image de cd "debian-testing-amd64-xfce-CD-1.iso".
Pas de serveur WEB, serveur SSH plus quelques paquets indispensables.
apt-get install system-config-lvm iproute2 net-tools vim-gtk
et enlevé "network-manager" que je n'apprécie pas, je préfère le bon vieux fichier "/etc/network/interfaces" et gérer moi même /"etc/resolv.conf".
Ensuite j'ai installé MariaDB client et serveur en "standard" (je précise la version 10.1) :
apt-get install mariadb-client-10.1 mariadb-server-10.1
Quelques modifications dans le fichier /etc/mysql/mysqld.conf.d/50-server.cnf :
Mettre la BDD "en ligne" :
bind-address = 0.0.0.0
Dans le "bloc" InnoDB (par exemple) ajout de :
innodb-buffer-pool-size = 1024M
innodb_buffer_pool_instances = 2
innodb-file-per-table = 1
innodb_additional_mem_pool_size = 8M
innodb_log_file_size = 512M
innodb_log_buffer_size = 8M
innodb_read_io_threads = 2
innodb_write_io_threads = 2
innodb_stats_persistent = 1
innodb_stats_persistent_sample_pages = 512
Positionner la variable "server-id" à 1 pour le premier serveur et = 2 pour le second.
Ajouter dans le bloc "[mariadb-10.1]" :
innodb_flush_log_at_trx_commit = 2
event_scheduler = on
local_infile = 0
plugin-load=validate_password.so
skip-symbolic-links = 1
innodb_flush_method = O_DIRECT
binlog_row_image = minimal
#
concurrent_insert = AUTO
sync_binlog = 1
innodb_use_native_aio = 1
# Sans oublier d'activer le "bin-log" nécessaire au maître
log_bin = /var/log/mysql/mysql-bin.log
# et le format de log, je préfère "mixed" à "row" ou "statement"
binlog_format = mixed
Et pour terminer et éviter des problèmes dus aux tables avec identifiant en "auto-increment" :
Mettre chacune des deux machines (ou plus) sur des séries différentes. Ici l'une générera des identifiants pairs, l'autre des identifiants impairs réduisant ainsi à zéro les risques de collision.
Sur le serveur 1 :
auto_increment_increment = 1
Sur le serveur 2 :
auto_increment_increment = 2
et sur les deux machines :
auto_increment_offset = 2
La machine 1 génère ainsi la série 1,3,5,7 ....
la machine 2 la série 2,4,6,8 ....
Après ces quelques modifications on redémarre Mariadb pour valider nos modifications.
Il faut ensuite configurer le volume destiné aux données (LVM).
C'est pour cela que j'ai installé le peu gourmand "system-config-lvm",
Créer un volume "MARIADBDATA1" (partition 1 du second disque "/dev/xvdb1"), dans ce volume créer un LV "DATA" de 24GB conservant ainsi 8GB pour des snapshots.
Ce LV est créé en "ext4" et monté sur /DATA/mysql que l'on aura créé auparavant sans oublier un "chmod mysql:mysql /DATA/mysql".
Ensuite arrêter MariaDB et copier le contenu cd /var/lib/mysql dans le répertoire /DATA/mysql (après montage du disque bien sûr !) et remplacer le répertoire (renommé par sécurité !) d'origine par un lien /var/lib/mysql --> /DATA/mysql on peut alors redémarrer MariaDB.
Les deux machines ont été installées "à la main" (pas en copiant l'image disque) afin de bien vérifier la procédure d'installation.
Ces deux machines ont une structure identique, le report des données présentes dans le S1 est facilité :
- On arrête les deux services "mysql"
- On copie "bêtement les fichiers du répertoire /DATA/mysql de S1 dans celui de S2 (tar)
- On relance le service et on resynchronise les deux "masters" entre eux.
MariaDB : maître maître : sauvegarde
MariaDB : maître maître : sauvegarde drupadminOn a un beau système, performant, efficace, je vous laisse imaginer différentes manières de s'en servir mais on peut, par exemple :
- Spécialiser un serveur dans l'écriture, L'autre dans la lecture, par exemple pour la création de ces gros rapports dont raffolent certaines personnes et qui "écroulent" le serveur principal.
- Spécialiser une des machines en écriture, l'autre en lecture. On peu faire ce type d'utilisation à l'aide d'adresses IP virtuelles (1 pour l'écriture, l'autre pour la lecture), un système de fail-over permet en cas d'incident sur l'un des serveurs bascule les 2 VIP sur le serveur valide..
Une Sauvegarde quasi "ON LINE".
Sauvegarde non testée --> DANGER, n'oubliez de tester une restauration ...
MariaDB : maître/maître mise en place
MariaDB : maître/maître mise en place jppPassons maintenant à la pratique du passage en "maître / maître" !
Le principe du maître / maître est très simple, chaque machine est à la fois le maître et l'esclave de l'autre.
Cela impose quelques contraintes déjà connues telles que d'utiliser différentes valeurs de "server-id" et, comme précisé dans le précédent article, d'utiliser des valeurs correctes de "auto-increment-increment" et "auto-increment-offset" afin de limiter les risques de doublons.
Il est par ailleurs déconseillé d'utiliser les deux machines en écriture simultanément car un risque de corruption existe. Il est par contre intéressant au niveau de la performance globale d'utiliser une machine en écriture et de diriger vers l'autre les applications en lecture seule, particulièrement des applications grosses consommatrices de lecture : états et statistiques diverses. Le retard entre les deux machines est en général à peu près négligeable.
Ce type de redondance permet par contre un basculement extrêmement rapide en car d'incident sur le serveur "écriture". Les adresses IP virtuelles permettent de réaliser la basculement sans délai ni manipulation complexe et cela peut être automatisé à l'aide de divers outils.
Pour simplifier nous nommerons S1 et S2 les deux machines. Les deux opérations à réaliser sont extrêmement simples :
- Rendre S2 "esclave" de S1, et lorsque cela est réalisé passer à la phase suivante
- Rendre S1 "esclave" de S2.
1) Rendre S2 esclave de S1.
Les commandes suivantes permettent :
d'autoriser S2 à se connecter comme esclave :
/* /* |
/* start SLAVE; |
Lorsque cette opération est réalisée, on teste un peu en redémarrant chacun des deux serveurs et en vérifiant la synchro à l'aide des commandes :
SHOW MASTER STATUS;
et
SHOW SLAVE STATUS\G
(le \G permet un affichage plus agréable .... pour les quelques malheureux qui l'ignorent encore).
Il est alors possible d'effectuer les tests habituels de création de table et d'insertion de rangs en vérifiant bien que les séries des identifiants attribués diffèrent bien entre les deux machines. Cela marche aussi avec trois machines en utilisant les "bons" paramètres d'incrément pour créer les séries 1,4,7,10; 2,5,8,11 et 3.6.9.12 ...
Le maître/maître ... mais c'est très simple !
A partir de là, tout ce qui se passe dans un des deux serveurs est reproduit sur l'autre.
Si vous recopiez vos données par export (d'un autre système) + import dans le groupe maître/maître (vidé de préférence) cela fonctionne bien. Il faut, là encore, bien synchroniser vos deux serveurs avant le début de l'import des données.
L'import dans l'un des serveurs sera reproduit fidèlement dans le second.
A ce propos, si vous utilisez des "events" ils seront en état "ENABLED" dans le serveur dans lequel a été réalisé l'import et en l'état "SLAVE_DISABLED" dans l'autre. Ainsi pas de risque de déclenchement de deux traitements en parallèle.
Maitre / esclave : petits inconvénients
Maitre / esclave : petits inconvénients jppVous trouverez vite quelques inconvénients à cette réplication car certains ordres SQL ne fonctionnent pas (ou plus).
Par exemple "create table as select * from ... where AA = '3' ", bien commode pourtant, vous jettera à la figure un message :
ERROR 1786 (HY000): CREATE TABLE ... SELECT is forbidden when @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
En effet cette construction est un concentré de deux ordres SQL : CREATE TABLE + INSERT et comme il s'agit d'une seule transaction elle n'aura qu'un "Transaction ID" et le slave recevra deux ordres différents le CREATE et l'INSERT avec un même TID, or un bon esclave n'exécute pas deux fois le même ID de transaction, il ferait le CREATE mais pas l'INSERT !
C'est un peu stupide, mais on arrive à s'y faire.
D'autres inconvénients existent lors d'un mélange de tables MyISAM et InnoDB car InnoDB supporte les transactions mais pas MyISAM d'où d'autres messages parfois sybillins, mais je pense que vous n'avez plus de tables MyIsam ! C'est si facile de les convertir ...
C'est peut-être un bon motif pour abandonner le MyISAM au profit de InnoDB pour vivre dans un monde transactionnel et maître/esclave sans erreurs superflues et sans "CREATE TABLE ... AS SELECT" (sniff).
Ah, aussi, on ne peut pas créer de tables temporaires dans une transaction, il faut les créer en dehors de tout contexte transactionnel pour que cela se passe bien.
Il semble d'ailleurs que le problème du "CREATE AS SELECT" soit résolu dans les dernières versions en choisissant bien le bon mode pour le binlog_mode.