MariaDB Galera Cluster : la réplication multi maitres

From Deimos.fr / Bloc Notes Informatique
Jump to: navigation, search
MariaDB

Software version 5.5
Operating System Debian 7
Website MariaDB Website
Last Update 19/04/2014
Others Galera 23.2.4(r147)

1 Introduction

Si vous avez déjà fait de la réplication MySQL, vous avez que vous êtes limités à 2 nœuds maitre maximum. Que beaucoup d'actions se font à la main et qu'il est donc difficile d'avoir quelque chose de scalable et surtout accessible en écriture en simultané, du fait que par défaut les écritures soient synchrones.

Note: Si vous avez besoin de conseil ou de support sur MySQL/MariaDB/Galera, je vous recommande la société OceanDBA

Il existe donc un outil appelé Galera qui s'intègre à MariaDB ou MySQL (via recompilation dans les 2 cas) et qui permet de faire du multi maitres (3 nœuds minimum). Il existe plusieurs produits qui utilisent Galera :

  • MariaDB Galera Cluster
  • Percona Cluster
  • MySQL Galera Cluster

Pour ceux qui se posent la question, c'est vraiment différent de MySQL Cluster qui sait scaler les écritures. Ici c'est multi threadé uniquement. Et contrairement à MHA qui est une solution asynchrone, Galera est synchrone.
Galera ne fonctionne que pour le moteur InnoDB et permet :

  • Les réplications synchrones
  • Des réplications multi maitres actifs
  • Lecture/Écriture sur plusieurs nœuds simultané
  • Détection automatique lorsqu'un nœud tombe
  • Réintégration d'un nœud automatiquement
  • Pas de lag au niveau des slaves
  • Aucunes transactions perdues
  • Latences clientes plus faible

Bien que cela semble parfait sur le papier, il y a quelques limitations :

  • Supporte uniquement InnoDB
  • Il faut qu'il y est des clés primaires sur toutes les tables
  • DELETE ne fonctionne que sur les tables munies de clefs primaires
  • LOCK/UNLOCK/GET_LOCK/RELEASE_LOCK ne fonctionne pas en multi maitre
  • Les query logs ne peuvent être envoyés sur des tables, mais uniquement sur des fichiers
  • Les transactions XA ne sont pas supportées

Pour vous aider à comprendre une architecture type :

Galera.png[1]

Sachez également qu'un outil en ligne aide à la construction de ce genre d'infrastructures : Galera Configurator[2]

2 Installation

To install MariaDB, it's unfortunately not embedded in Debian, so we'll add a repository. First of all, install a python tool to get aptkey :

Command aptitude
aptitude install python-software-properties

Then let's add this repository (https://downloads.mariadb.org/mariadb/repositories/) :

Command
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
add-apt-repository 'deb http://mirrors.linsrv.net/mariadb/repo/10.0/debian wheezy main'

We're now going to change apt pinning to prioritize MariaDB's repository :

Configuration File /etc/apt/preferences.d/mariadb
Package: *
Pin: release o=MariaDB
Pin-Priority: 1000

Notes Notes
A l'heure ou j'écris ces lignes, il y a un petit problème de dépendances avec certains packages. Il faudra donc les télécharger au préalable et les installer. Vous n'avez pas besoin de suivre la fin de cette installation si vous n'avez pas rencontré d'erreurs avec les étapes précédentes

Command
wget http://ftp.fr.debian.org/debian/pool/main/o/openssl/libssl0.9.8_0.9.8o-4squeeze14_amd64.deb
dpkg -i libssl0.9.8_0.9.8o-4squeeze14_amd64.deb

Maintenant, nous allons installer MariaDB et Galera :

Command aptitude
aptitude update
aptitude install mariadb-galera-server galera rsync openntpd

Notes Notes
Le package rsync n'est pas obligatoire, mais nécessaire si vous allez utiliser cette méthode de transfert par la suite

3 Configuration

3.1 MariaDB

Avant de commencer à toucher à la configuration, nous allons devoir supprimer des fichiers de logs sous peine que MariaDB ne démarre plus. Il va donc falloir couper le service mariadb :

Command service
service mysql stop

Puis nous mettons cette configuration MariaDB :

Configuration File /etc/mysql/my.cnf
# MariaDB database server configuration file.
# Pierre Mavro / Deimosfr
#
# You can copy this file to one of:
# - "/etc/mysql/my.cnf" to set global options,
# - "~/.my.cnf" to set user-specific options.
# 
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
 
# This will be passed to all mysql clients
# It has been reported that passwords should be enclosed with ticks/quotes
# escpecially if they contain "#" chars...
# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
[client]
port		= 3306
socket		= /var/run/mysqld/mysqld.sock
 
# Here is entries for some specific programs
# The following values assume you have at least 32M ram
 
# This was formally known as [safe_mysqld]. Both versions are currently parsed.
[mysqld_safe]
socket		= /var/run/mysqld/mysqld.sock
nice		= 0
 
[mysqld]
#
# * Basic Settings
#
user		= mysql
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
port		= 3306
basedir		= /usr
datadir		= /var/lib/mysql
innodb_log_group_home_dir = /var/lib/mysql
tmpdir		= /tmp
lc_messages_dir	= /usr/share/mysql
lc_messages	= en_US
skip-external-locking
 
character_set_server = utf8
collation_server = utf8_general_ci
 
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address		= 0.0.0.0
#
# * Fine Tuning
#
max_connections		= 500
connect_timeout		= 5
wait_timeout		= 600
max_allowed_packet	= 16M
thread_cache_size       = 128
sort_buffer_size	= 16M
bulk_insert_buffer_size	= 16M
tmp_table_size		= 32M
max_heap_table_size	= 64M
net_buffer_length	= 4k
 
#
# * MyISAM
#
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched. On error, make copy and try a repair.
myisam_recover          = BACKUP
key_buffer_size		= 128M
#open-files-limit	= 2000
table_open_cache	= 400
myisam_sort_buffer_size	= 512M
concurrent_insert	= 2
read_buffer_size	= 2M
read_rnd_buffer_size	= 1M
#
# * Query Cache Configuration
#
# Cache only tiny result sets, so we can fit more in the query cache.
query_cache_limit		= 128K
query_cache_size		= 64M
# for more write intensive setups, set to DEMAND or OFF
#query_cache_type		= DEMAND
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# As of 5.1 you can enable the log at runtime!
#general_log_file        = /var/log/mysql/mysql.log
#general_log             = 1
#
# Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
#
# we do want to know about network errors and such
log_warnings		= 2
#
# Enable the slow query log to see queries with especially long duration
#slow_query_log[={0|1}]
slow_query_log_file	= /var/log/mysql/mariadb-slow.log
long_query_time = 10
#log_slow_rate_limit	= 1000
log_slow_verbosity	= query_plan
 
#log-queries-not-using-indexes
#log_slow_admin_statements
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
#server-id		= 1
#report_host		= master1
#auto_increment_increment = 2
#auto_increment_offset	= 1
log_bin			= /var/log/mysql/mariadb-bin
log_bin_index		= /var/log/mysql/mariadb-bin.index
# not fab for performance, but safer
#sync_binlog		= 1
expire_logs_days	= 10
max_binlog_size         = 100M
# slaves
#relay_log		= /var/log/mysql/relay-bin
#relay_log_index	= /var/log/mysql/relay-bin.index
#relay_log_info_file	= /var/log/mysql/relay-bin.info
#log_slave_updates
#read_only
#
# If applications support it, this stricter sql_mode prevents some
# mistakes like inserting invalid dates etc.
#sql_mode		= NO_ENGINE_SUBSTITUTION,TRADITIONAL
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
default_storage_engine	= InnoDB
# you can't just change log file size, requires special procedure
#innodb_log_file_size			= 50M
innodb_buffer_pool_size			= 256M
innodb_log_buffer_size			= 8M
innodb_log_file_size			= 256M
thread_concurrency			= 64
innodb_thread_concurrency		= 64
innodb_read_io_threads			= 16
innodb_write_io_threads			= 16
innodb_flush_log_at_trx_commit 		= 2
innodb_file_per_table			= 1
innodb_open_files			= 400
innodb_io_capacity			= 600
innodb_lock_wait_timeout 		= 60
innodb_flush_method			= O_DIRECT
innodb_doublewrite 			= 0
innodb_additional_mem_pool_size		= 20M
innodb_buffer_pool_restore_at_startup	= 500
innodb_file_per_table
#
# * Security Features
#
# Read the manual, too, if you want chroot!
# chroot = /var/lib/mysql/
#
# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
#
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem
 
[mysqldump]
quick
quote-names
max_allowed_packet	= 16M
 
[mysql]
#no-auto-rehash	# faster start of mysql but no tab completition
 
[isamchk]
key_buffer		= 16M
 
[mysqlhotcopy]
interactive-timeout
 
#
# * IMPORTANT: Additional settings that can override those from this file!
#   The files must end with '.cnf', otherwise they'll be ignored.
#
!includedir /etc/mysql/conf.d/

Nous allons maintenant supprimer les fichiers de logs car nous venons de toucher à leurs confs (sous peine de ne pas pouvoir démarrer d'instances) et pouvoir démarrer notre service MariaDB :

Command
rm /var/lib/mysql/ib_logfile*
service mysql start

3.2 Galera

Voici la configuration à appliquer pour un cluster sur le même site :

Configuration File /etc/mysql/conf.d/mariadb.cnf
# MariaDB-specific config file.
# Read by /etc/mysql/my.cnf
 
[client]
# Default is Latin1, if you need UTF-8 set this (also in server section)
#default-character-set = utf8
 
[mysqld]
#
# * Character sets
#
# Default is Latin1, if you need UTF-8 set all this (also in client section)
#
#character-set-server  = utf8
#collation-server      = utf8_general_ci
#character_set_server   = utf8
#collation_server       = utf8_general_ci
 
# Load Galera Clusterwsrep_provider = /usr/lib/galera/libgalera_smm.sowsrep_cluster_name='mariadb_cluster'wsrep_node_name=node2wsrep_node_address="10.0.0.2"wsrep_cluster_address = 'gcomm://10.0.0.1,10.0.0.2,10.0.0.3,10.0.0.4'wsrep_retry_autocommit = 0wsrep_sst_method = rsyncwsrep_provider_options="gcache.size = 1G; gcache.name = /tmp/galera.cache"#wsrep_replication_myisam = 1
#wsrep_sst_receive_address = <x.x.x.x>
#wsrep_notify_cmd="script.sh"
 
# Other mysqld options
binlog_format = ROW
innodb_autoinc_lock_mode = 2
innodb_flush_log_at_trx_commit = 2
innodb_locks_unsafe_for_binlog = 1

  • wsrep_cluster_name : le nom du cluster Galera. A utiliser, surtout si vous disposez de plusieurs cluster Galera dans le même subnet, afin d'éviter que certains noeuds entrent dans le mauvais cluster.
  • wsrep_node_name : le nom de la machine sur laquelle se trouve ce fichier de configuration. Vous l'aurez compris, il faut a tout prix éviter les doublons (surtout pour le debug ;-))
  • wsrep_node_address : adresse ip du noeud actuel (même avertissement que la ligne précédente)
  • wsrep_cluster_address : liste des membres du cluster pouvant être maitre (séparé par des virgules).
  • wsrep_provider_options : permet d'activer des options supplémentaires.
    • gcache permet de stocker les données à transférer aux autres noeuds. Par défaut à 128M, il est conseillé d'augmenter cette valeur.[3]
  • wsrep_retry_autocommit : permet de définir le nombre de tentatives une requête doit être réexécutée en cas de conflit.
  • wsrep_sst_method : la méthode d'échange des données. Rsync est la plus rapide à l'heure actuelle.[4]
  • wsrep_replication_myisam : permet d'activer la réplication des données MyISAM (pas de gestion des transactions...a éviter donc !)
  • wsrep_sst_receive_address : permet de forcer l'utilisation d'une certaine adresse pour que les hôtes distants puissent se connecter (résous les problèmes de VIP)
  • wsrep_notify_cmd : permet d’exécuter un script à chaque évènement de Galera (changement d'état d'un nœud)
  • binlog_format : permet de définir le format des logs en mode ROW
  • innodb_autoinc_lock_mode : modifie le comportement des verrous
  • innodb_flush_log_at_trx_commit : optimisation des performances
Notes Notes
Adaptez les lignes wsrep_node_name et wsrep_cluster_address à vos machines respectives.

La configuration ci dessus est applicable pour tous les nœuds, sauf pour le maitre (celui qui doit démarrer le premier). Celui ci doit avoir la configuration identique, à la seule différence de cette ligne :

Configuration File /etc/mysql/conf.d/mariadb.cnf
wsrep_cluster_address = 'gcomm://'

Warning WARNING
Il est important qu'une seule machine ai la configuration 'gcomm://', car c'est l'initialisation du cluster

3.3 Géo cluster

Il est possible de faire du Géo cluster, l'inconvénient c'est que lorsqu'il y a une coupure suppérieure aux timeouts indiqués, un des clusters va devoir se resynchroniser entièrement. Voici la ligne à configurer pour modifier ces timeouts :

Configuration File /etc/mysql/conf.d/mariadb.cnf
[...]
wsrep_provider_options = "evs.keepalive_period = PT3S; evs.inactive_check_period = PT10S; evs.suspect_timeout = PT30S; evs.inactive_timeout = PT1M; evs.install_timeout = PT1M"
[...]

Si vous utilisez l'option 'wsrep_sst_receive_address', il faudra rajouter un paramètre sur cette ligne (ist.recv_addr) et mettre la même ip que l'option 'wsrep_sst_receive_address' :

Configuration File /etc/mysql/conf.d/mariadb.cnf
[...]
wsrep_provider_options = "evs.keepalive_period = PT3S; evs.inactive_check_period = PT10S; evs.suspect_timeout = PT30S; evs.inactive_timeout = PT1M; evs.install_timeout = PT1M; ist.recv_addr = <x.x.x.x>"
[...]

3.4 Méthodes de réplications

Il existe plusieurs solutions pour les transferts de données entre noeuds. Dans l'exemple plus haut, nous avons utilisé rsync. Lorsqu'une machine demande à un donor (une autre machine) de recevoir les données, les transactions sont bloqués pour le donneur durant la période d'échange de données avec le receveur !!!

Warning WARNING
Si vous utilisez un load balancer, il faudra sortir le noeud donneur pendant cette période là

Ce blocage peut être toutefois limité en utilisant la méthode xtrabackup.

3.4.1 mysqldump

SST (State Snapshot Transfert) va permettre de faire des échanges complets (uniquement, pas d'incrémentale). Il faut donc créer un utilisateur sur toutes les machines :

Command mysql
grant all on *.* to 'sst_user'@'%' identified by 'sst_password';

Puis modifier la configuration pour que le user et le password concordent :

Configuration File /etc/mysql/conf.d/mariadb.cnf
[...]
wsrep_sst_auth = 'sst_user:sst_password'
[...]

Du coup, lorsque l'on intègre un nouveau noeud, on peut constater qu'un nœud est passé en donneur :

Command mysql
MariaDB [(NONE)]> SHOW global STATUS LIKE 'wsrep%stat%';
+---------------------------+--------------------------------------+
| Variable_name             | VALUE                                |
+---------------------------+--------------------------------------+
| wsrep_local_state_uuid    | 3e10ea72-f2b9-11e2-0800-4b821a7d26d5 |
| wsrep_local_state         | 2                                    |
| wsrep_local_state_comment | Donor/Desynced                       || wsrep_cluster_state_uuid  | 3e10ea72-f2b9-11e2-0800-4b821a7d26d5 |
| wsrep_cluster_status      | PRIMARY                              |
+---------------------------+--------------------------------------+
5 ROWS IN SET (0.00 sec)

On voit également que la valeur du wsrep_local_state change à 4 pour que le process soit terminé.[5]

Notes Notes
Le problème de cette méthode est qu'elle ne gère pas les IST (Incremental State Transfert). Tout doit être transféré en cas de problème et pas seulement l'incrémentale. Il faut regarder les méthodes rsync ou xtrabackup pour pouvoir faire de l'IST

3.4.2 Rsync

C'est une méthode très efficace ! L'inconvénient majeur est qu'elle ne permet pas de faire des transferts à chaud. Voici comment configurer le SST :

Configuration File /etc/mysql/conf.d/mariadb.cnf
[...]
wsrep_sst_method = rsync
[...]

Il faut que les données ne soient plus accédées par MariaDB pour que cela fonctionne correctement. Un autre prérequis est la présence d'rsync sur les serveurs.

3.4.3 XtraBackup

XtraBackup est la meilleure méthode aujourd'hui. Elle permet de faire des transferts en minimisant le temps de lock qui n'est que de quelques secondes. Pour que l'on puisse utiliser cette méthode, il faut installer XtraBackup.

Pour l'installer sur une Debian, c'est très simple, nous allons rajouter son repository :

Command gpg
apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A

Créez ce fichier pour ajouter le repository :

Configuration File /etc/apt/sources.list.d/percona.list
deb http://repo.percona.com/apt VERSION main
deb-src http://repo.percona.com/apt VERSION main

On update et on installe :

Command aptitude
aptitude update
aptitude install xtrabackup

Puis on peut configurer nos noeuds pour qu'ils utilisent cette méthode :

Configuration File /etc/mysql/conf.d/mariadb.cnf
[...]
wsrep_sst_method = xtrabackup
[...]

3.4.4 Spécifier un donor

Pour ce qui est de la réplication, si vous souhaitez à tout moment dédier une machine en donor (et éventuellement pour les backups) depuis un serveur :

Command mysql
SET global wsrep_sst_donor=<node3>

Ceci résous la problématique du load balancer cité plus haut et évite les blocages durant un backup.

Sinon vous pouvez le spécifier directement pour l'intégration d'un noeud :

Command mysqld
mysqld --wsrep_cluster_address='gcomm://<node1>' --wsrep_sst_donor='<node1>'

Notes Notes
Si vous démarrez 2 fois de suite MariaDB sans lancer au moins une fois une synchro Galera, la 2ème fois, il fera une synchro complète

4 Utilisation

Avant de passer à l'utilisation, il faut comprendre le principe. Lorsque nous allons démarrer nos instances MariaDB, nous allons nous retrouver dans ce cas de configuration (je n'ai volontairement pas fait toutes les flèches de communication pour éviter que ça devienne trop fouillis, mais tous les nodes discutent entre eux) :

Galera1.png

  • Le node 1 initialise le cluster avec la valeur du gcomm vide.
  • Les autres nodes se connectent sur le node 1 et échangent leurs données pour avoir le même niveau de données partout

4.1 Création du cluster

Mettez vous sur le node 1 afin de créer le cluster. Nous allons l'allumer avec une adresse de cluster vide, qui va indiquer sa création :

Command mysqld
service mysql start --wsrep_cluster_address='gcomm://'

ou

mysqld --wsrep_cluster_address='gcomm://'

4.2 Ajouter des noeuds dans le cluster

Pour joindre des nodes au cluster qui vient d'être créer, c'est simple :

Command mysqld
service mysql start --wsrep_cluster_address='gcomm://<ip_du_node_1>'

ou

mysqld --wsrep_cluster_address='gcomm://<ip_du_node_1>'

Mettez donc l'IP du node 1 pour se connecter à lui. Vous pouvez également simplement démarrer le service MariaDB, car nous avons une configuration qui est fonctionnelle :

Command
service mysql start

Si vous n'arrivez pas à joindre le master, lancez cette commande sur dans mysql sur le master pour être sur qu'il est bien démarré :

Command mysql
SET global wsrep_cluster_address='gcomm://'

Notes Notes
Vous pouvez utilisez les IP ou des noms DNS

4.3 Vérifier l'état du cluster

Pour vérifier l'état du cluster, voici la commande à exécuter dans MariaDB :

Command mysql -uroot -p
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_%';
+--------------------------+----------------------+
| Variable_name            | Value                |
+--------------------------+----------------------+
| wsrep_cluster_conf_id    | 18446744073709551615 |
| wsrep_cluster_size       | 0                    || wsrep_cluster_state_uuid |                      |
| wsrep_cluster_status     | Disconnected         |
| wsrep_connected          | OFF                  |
| wsrep_local_index        | 18446744073709551615 |
| wsrep_provider_name      |                      |
| wsrep_provider_vendor    |                      |
| wsrep_provider_version   |                      |
| wsrep_ready              | ON                   |+--------------------------+----------------------+
10 rows in set (0.01 sec)

Ici je n'ai que mon serveur principale qui tourne. Aucun autre node n'a encore joint le cluster. Mais lorsque j'en ajoute :

Command mysql
> mysql -uroot -p -e "SHOW STATUS LIKE 'wsrep_%';"
+----------------------------+----------------------------------------------------------------------------+
| Variable_name              | Value                                                                      |
+----------------------------+----------------------------------------------------------------------------+
| wsrep_local_state_uuid     | 9e9f8568-a025-11e2-0800-be0dc874ac98                                       |
| wsrep_protocol_version     | 4                                                                          |
| wsrep_last_committed       | 0                                                                          |
| wsrep_replicated           | 0                                                                          |
| wsrep_replicated_bytes     | 0                                                                          |
| wsrep_received             | 12                                                                         |
| wsrep_received_bytes       | 639                                                                        |
| wsrep_local_commits        | 0                                                                          |
| wsrep_local_cert_failures  | 0                                                                          |
| wsrep_local_bf_aborts      | 0                                                                          |
| wsrep_local_replays        | 0                                                                          |
| wsrep_local_send_queue     | 0                                                                          |
| wsrep_local_send_queue_avg | 0.000000                                                                   |
| wsrep_local_recv_queue     | 0                                                                          |
| wsrep_local_recv_queue_avg | 0.000000                                                                   |
| wsrep_flow_control_paused  | 0.000000                                                                   |
| wsrep_flow_control_sent    | 0                                                                          |
| wsrep_flow_control_recv    | 0                                                                          |
| wsrep_cert_deps_distance   | 0.000000                                                                   |
| wsrep_apply_oooe           | 0.000000                                                                   |
| wsrep_apply_oool           | 0.000000                                                                   |
| wsrep_apply_window         | 0.000000                                                                   |
| wsrep_commit_oooe          | 0.000000                                                                   |
| wsrep_commit_oool          | 0.000000                                                                   |
| wsrep_commit_window        | 0.000000                                                                   |
| wsrep_local_state          | 4                                                                          |
| wsrep_local_state_comment  | Synced                                                                     |
| wsrep_cert_index_size      | 0                                                                          |
| wsrep_causal_reads         | 0                                                                          |
| wsrep_incoming_addresses   | 10.0.0.1:3306,10.0.0.2:3306,10.0.0.3:3306,10.0.0.4:3306                    |
| wsrep_cluster_conf_id      | 2                                                                          |
| wsrep_cluster_size         | 4                                                                          || wsrep_cluster_state_uuid   | 9e9f8568-a025-11e2-0800-be0dc874ac98                                       |
| wsrep_cluster_status       | Primary                                                                    |
| wsrep_connected            | ON                                                                         |
| wsrep_local_index          | 0                                                                          |
| wsrep_provider_name        | Galera                                                                     |
| wsrep_provider_vendor      | Codership Oy <info@codership.com>                                          |
| wsrep_provider_version     | 23.2.4(r147)                                                               |
| wsrep_ready                | ON                                                                         |+----------------------------+----------------------------------------------------------------------------+

Je vois bien ici mes 4 noeuds master :-)

5 Garbd (quorum)

Afin d'éviter les split brains (inconsistances cluster), il est conseillé d'utiliser un outil fournit avec le cluster Galera qui agira comme un quorum cluster, surtout si vous êtes en mode 2 noeuds (et c'est généralement là le principale avantage). Voici un cas d'utilisation[6] :

                    ,---------.
                    |  garbd  |
                    `---------'
         ,---------.     |     ,---------.
         | clients |     |     | clients |
         `---------'     |     `---------'
                    \    |    /
                     \ ,---. /
                     ('     `)
                    (   WAN   )
                     (.     ,)
                     / `---' \
                    /         \
         ,---------.           ,---------.
         |  node1  |           |  node2  |
         |  node3  |           |  node4  |
         `---------'           `---------'
        Data Center 1         Data Center 2

Il faudra alors utiliser le service garbd. Il est installé de base, mais n'est tout simplement pas activé. Pour le configurer, nous allons éditer sa configuration :

Configuration File /etc/default/garb
# Copyright (C) 2012 Coedership Oy
# This config file is to be sourced by garb service script.
 
# A space-separated list of node addresses (address[:port]) in the cluster
GALERA_NODES="10.0.0.1:4567 10.0.0.2:4567 10.0.0.3:4567 10.0.0.4:4567" 
# Galera cluster name, should be the same as on the rest of the nodes.
GALERA_GROUP="mariadb_cluster" 
# Optional Galera internal options string (e.g. SSL settings)
# see http://www.codership.com/wiki/doku.php?id=galera_parameters
# GALERA_OPTIONS=""
 
# Log file for garbd. Optional, by default logs to syslog
# LOG_FILE=""

Adaptez le GALERA_NODES avec la liste de tous vos nodes et le GALERA_GROUP avec le nom du cluster Galera. Il ne reste plus qu'à l'activer au démarrage de la machine et démarrer le service :

Command
update-rc.d -f garb defaults
service garb start

Maintenant, sur un de vos noeuds, vous pourrez voir qu'il y a un nouveau node, qui n'est en fait que le quorum :

Command mysql
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 5     |
+--------------------+-------+

6 Sauvegardes et restaurations

Pour la sauvegarde, il existe plusieurs méthodes et Xtrabackup est encore une fois l'une des favoris.

Notes Notes
Tout comme lorsqu'un nouveau nœud s'ajoute au cluster et bloque les transactions du donor, c'est pareil pour les backups, mais uniquement pour MyISAM !

Si vous utilisez que de l'InnoDB et utilisez Xtrabackup, il n'y aura pas de locks de transactions et donc pas de nœud spécial à prévoir pour les backups !

6.1 Installation

Pour l'installer sur une Debian, c'est très simple, nous allons rajouter son repository :

Command gpg
apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A

Créez ce fichier pour ajouter le repository :

Configuration File /etc/apt/sources.list.d/percona.list
deb http://repo.percona.com/apt VERSION main
deb-src http://repo.percona.com/apt VERSION main

On update et on installe :

Command aptitude
aptitude update
aptitude install xtrabackup

6.2 Utilisation

6.2.1 Sauvegarde

Pour sauvegarder un Galera et permettre une sauvegarde incrémentielle en bloquant le nœud qui va effectuer les sauvegardes, uniquement quelques secondes :

Command innobackupex
innobackupex --galera-info --user=xxxxx --password=xxxx <repertoire_ou_stocker_le_backup>

L'option 'galera-info' permet de ne pas avoir de problèmes durant la demande d'uuid (qui retournera tout le temps 0). Si on ne spécifie pas cette option, on ne pourra pas faire de restaurations incrémentiels.

Notes Notes
Pour les bases de données ne contenant que des tables uniquement en InnoDB, il est possible de ne pas du tout avoir de blocage lors du lock en ajoutant l'option '--no-lock'

6.2.2 Restauration

Durant la restauration, un des nœuds aura des transactions bloquées après la restauration d'Xtrabackup, le temps d'effectuer le différentiel. Pour restaurer on copie les fichiers de sauvegarde dans le répertoire de MariaDB :

Command
cp -Rf <repertoire_du_backup> /var/lib/mysql/
chown -Rf mysql. /var/lib/mysql/

On peut spécifier le donor (optionnel), puis on va vérifier la position du backup :

Command cat
> cat <repertoire_du_backup>/xtrabackup_galera_info 
cfa9b8f1-f37b-11e2-0800-b37f8ac5092c:1

Et on intègre le nœud au cluster en lui spécifiant la position pour éviter qu'il récupère une sauvegarde complète :

Command mysqld
service mysql start --wsrep_cluster_address='gcomm://<ip_du_node_1>' --wsrep_start_position="cfa9b8f1-f37b-11e2-0800-b37f8ac5092c:1"

ou

mysqld --wsrep_cluster_address='gcomm://<ip_du_node_1>' --wsrep_start_position="cfa9b8f1-f37b-11e2-0800-b37f8ac5092c:1"

7 Récupération et maintenance

7.1 Méthode automatique

Il n'y a pas à se soucier de la réplication si un nœud tombe autre que le master (node1). Une fois réparé et allumé, il se reconnectera automatiquement sur le node 1 et rattrapera son retard. Par contre, en cas de problème sur le noeud 1 :

Galera2.png

Les autres nodes continueront à communiquer entre eux et attendront le maitre revienne. Une fois le maitre rallumé, il va falloir lui indiquer un autre noeud sur lequel il devra se connecter pour continuer la synchro :

Galera3.png

Que ce soit pour forcer une reconnexion ou si vous voulez effectuer une maintenance sur le nœud master, il est conseillé de rediriger les autres serveurs vers un autre master pour éviter les coupures :

Command mysql
SET GLOBAL wsrep_cluster_address='gcomm://10.0.0.2';

Vous pouvez ensuite vérifier le noeud maitre sur vos instances MariaDB :

Command mysql
MariaDB [(none)]> SHOW VARIABLES LIKE 'wsrep_cluster_address';
+-----------------------+-----------------------+
| Variable_name         | Value                 |
+-----------------------+-----------------------+
| wsrep_cluster_address | gcomm://10.0.0.2      |
+-----------------------+-----------------------+

J'ai également testé de couper violemment n'importe quel node et le rallumer, une fois intégré dans le cluster, il récupère bien toutes le différentiel d'informations. J'ai poussé les tests et n'ai eu aucuns problèmes de corruptions. Les seuls problèmes que j'ai pu avoir étaient le démarrage de MariaDB et les problèmes de lock comme expliqué dans la #FAQ.

7.2 Méthode manuelle

Il est possible de mettre à jour un noeud depuis un delta entre une version à jour et celle d'un autre en retard. Pour cela, il faut regarder la version dans laquelle se trouve un des noeuds à jour :

Command mysql
SHOW global STATUS LIKE 'wsrep%';
+----------------------------+---------------------------------------+
| Variable_name              | VALUE                                 |
+----------------------------+---------------------------------------+
| wsrep_local_state_uuid     | 3e10ea72-f2b9-11e2-0800-4b821a7d26d5  || wsrep_protocol_version     | 4                                     |
| wsrep_last_committed       | 6                                     |

On peut voir ici le numéro d'uuid, ainsi que la position du dernier commit (wsrep_last_committed).

Warning WARNING
La commande suivant est à utiliser uniquement sur serveur éteint sous peine de perdre les données sur celui ci !!!

Sur serveur éteint, il est possible de récupérer la position du dernier commit :

Command mysqld
> mysqld --wsrep_recover=1
130722 15:44:53 InnoDB: The InnoDB memory heap is disabled
130722 15:44:53 InnoDB: Mutexes and rw_locks use GCC atomic builtins
130722 15:44:53 InnoDB: Compressed tables use zlib 1.2.7
130722 15:44:53 InnoDB: Using Linux native AIO
130722 15:44:53 InnoDB: Initializing buffer pool, size = 256.0M
130722 15:44:53 InnoDB: Completed initialization of buffer pool
130722 15:44:53 InnoDB: highest supported file format is Barracuda.
130722 15:44:53  InnoDB: Waiting for the background threads to start
130722 15:44:54 Percona XtraDB (http://www.percona.com) 1.1.8-29.3 started; log sequence number 1603853
130722 15:44:54 [Note] Plugin 'FEEDBACK' is disabled.
130722 15:44:54 [Note] WSREP: Recovered position: 3e10ea72-f2b9-11e2-0800-4b821a7d26d5:4130722 15:44:54  InnoDB: Starting shutdown...
130722 15:44:55  InnoDB: Shutdown completed; log sequence number 1603853
130722 15:44:55 [Note] mysqld: Shutdown complete

Puis on peut relancer le delta depuis ce dernier commit :

Command mysqld
mysqld --wsrep_start_position=<uuid>:<position>

soit

mysqld --wsrep_start_position=3e10ea72-f2b9-11e2-0800-4b821a7d26d5:4

La delta est alors effectué et le serveur en question est maintenant à la position 6.

7.3 Forcer un noeud à se resynchroniser

Si vous ne savez vraiment pas ce qu'un nœud a et que vous voulez le resynchroniser complètement car vous n'êtes pas sur des données qu'il contient, il suffit de supprimer le contenu de mariadb et de le relancer :

Command
service mysql stop
rm -Rf /var/lib/mysql/*
service mysql start

Toutes les données vont alors se resynchroniser.

Warning WARNING
Ceci peut durer un certain temps si votre base de données est grosses ou que la bande passante entre les nœuds est faible

7.4 Split brain

Lorsque l'on a un ou plusieurs nœuds en état de split brain, il est possible de continuer d'utiliser le cluster et de discard tous les changements des autres noeuds down pour qu'ils refassent une synchro complète au démarrage de ceux ci. Sur un serveur en 'primary' :

Command mysqld
SET global wsrep_provider_options = 'pc.bootstrap=1';
SET global wsrep_provider_options = 'pc.ignore_quorum=0';

  • pc.bootstrap : prend la main sur les autres noeuds du cluster et indique que c'est lui le master
  • pc.ignore_quorum : autorise à spliter les noeuds et avoir un split brain

Relancez ensuite vos autres serveurs pour qu'ils se synchronisent.

Warning WARNING
Une fois que le cluster est rétablit, il faut ABSOLUMENT repasser ces variables à False pour éviter des split brains à l'avenir sans pouvoir revenir en arrière !!!

8 FAQ

8.1 Un de mes services MariaDB refuse de démarrer après arrêt de celui ci

Il peut arriver que lorsque l'on éteint un service MariaDB, les fichiers de locks se libèrent mal et que le service rsync tourne encore. Pour mettre tout au propre (sans éviter de redémarrer complètement la machine), voici les opérations à suivre :
1. On s'assure que MariaDB ne fonctionne plus :

Command
service mysql stop
ps aux | grep mysql

2. Si ça tourne encore, on kill le processus !
3. On vérifie que le process rsync ne tourne plus et on le kill si c'est le cas
4. On supprime le fichiers de lock :

Command rm
rm -f /var/run/mysqld/mysqld.sock

5. On vérifie que le dossier pour stocker le pid existe, sinon on le créer :

Command
if [ ! -d /var/run/mysqld ] ; then mkdir /var/run/mysqld ; chown mysql. /var/run/mysqld ; fi

6. Vous pouvez maintenant démarrer le service, ça devrait fonctionner :

Command
service mysql start

Sinon regardez les logs (/var/log/syslog)

8.2 /dev/stderr: Permission denied

Si vous avez ce problèmes c'est du à un bug de Galera qui redirige mal sa sortie d'erreur :

/usr//bin/wsrep_sst_common: line 94: /dev/stderr: Permission denied

Pour corriger le problème, il suffit de mettre les bons droits sur la sortir d'erreurs :

Command
chmod 777 /proc/self/fd/2

9 References

  1. ^ http://www.codership.com/wiki/doku.php?id=galera_deployment
  2. ^ http://www.severalnines.com/galera-configurator/
  3. ^ http://www.severalnines.com/blog/understanding-gcache-galera
  4. ^ http://www.codership.com/wiki/doku.php?id=sst_mysql
  5. ^ http://www.codership.com/wiki/doku.php?id=galera_node_fsm
  6. ^ http://www.sebastien-han.fr/blog/2012/04/01/mysql-multi-master-replication-with-galera/