Percona XtraDB Clúster, es la solución de alta disponibilidad y balanceo de carga multi-máster de la bifurcación (fork) de MySQL de Percona. Según la recomendación de Percona, este tipo de clúster necesita un mínimo de 3 nodos o más, pero siempre es recomendable instalarlo en un número impar de nodos. En este artículo, te mostraré cómo instalar y configurar un clúster MySQL de Percona con 3 nodos.
Pre-requisitos
- Todos los nodos deben tener instalado Ubuntu 16.04 LTS. Se supone que las direcciones IP de cada nodo sean: 192.168.0.10 a la 192.168.0.12.
- Cuenta de usuario en cada servidor con privilegios administrativos. Puedes aprender cómo hacer esto siguiendo los pasos del tutorial: Configuración inicial del servidor de Ubuntu.
- La configuración del Firewall permite las conexiones hacia los puertos 3306, 4444, 4567 y 4568
- Desactivar AppArmor para el perfil MySQL. Si no sabes cómo hacerlo, sigue los pasos del tutorial: Cómo desactivar o activar un perfil de AppArmor.
Instalar Percona XtraDB Clúster
Los paquetes del repositorio de percona para Ubuntu y Debian están firmados con una llave. Lo primero que debes hacer es agregar a apt la llave con la que están firmados los paquetes. Para eso ejecuta el siguiente comando:
1 |
$ apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A |
Luego debes agregar al fichero /etc/apt/sources.list,
la información del repositorio de Percona. Debes reemplazar VERSION con el nombre de la distribución que utilices:
1 2 |
deb http://repo.percona.com/apt VERSION main deb-src http://repo.percona.com/apt VERSION main |
El fichero sources.list
tiene una apariencia similar a esta:
1 2 |
deb http://archive.ubuntu.com/ubuntu xenial main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu xenial-security main restricted universe multiverse |
Una vez que agregues la información del repositorio de Percona para la distribución xenial, en este caso, quedará de la siguiente forma:
1 2 |
deb http://archive.ubuntu.com/ubuntu xenial main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu xenial-security main restricted universe multiverse deb http://repo.percona.com/apt xenial main deb-src http://repo.percona.com/apt xenial main |
Lo próximo es actualizar la caché:
1 |
apt-get update |
Finalmente debes utilizar apt para instalar el clúster de la siguiente manera:
1 |
$ sudo apt-get install percona-xtradb-cluster-56 |
Configurar el primer nodo
Sin detener el MySQL debes crear el usuario de réplica:
1 2 3 4 5 |
mysql -uroot -p CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'password'; GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost'; FLUSH PRIVILEGES; exit; |
Luego debes detener el MySQL de la siguiente forma:
1 |
$ sudo systemctl stop mysql |
Puedes comprobar que MySQL se ha detenido utilizando systemctl
:
1 |
$ sudo systemctl status mysql |
1 2 3 4 5 |
● mysql.service - LSB: Start and stop the mysql (Percona XtraDB Cluster) daemon Loaded: loaded (/etc/init.d/mysql; bad; vendor preset: enabled) Active: inactive (dead) since Wed 2016-09-28 19:08:43 UTC; 51s ago Docs: man:systemd-sysv-generator(8) Process: 3461 ExecStop=/etc/init.d/mysql stop (code=exited, status=0/SUCCESS) |
Lo siguiente es editar el archivo my.cnf
con la configuración necesaria para que el clúster funcione.
1 |
$ sudo nano /etc/mysql/my.cnf |
Una vez que edites el archivo, el contenido será muy similar a esto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# # The MySQL database server configuration file. # # You can copy this 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. # Here is entries for some specific programs # The following values assume you have at least 32M ram !includedir /etc/mysql/conf.d/ |
Luego debes agregar al archivo de configuración las siguientes líneas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
[mysqld] datadir=/var/lib/mysql user=mysql # Path to Galera library wsrep_provider=/usr/lib/libgalera_smm.so # Cluster connection URL contains the IPs of node#1, node#2 and node#3 wsrep_cluster_address=gcomm://192.168.0.10,192.168.0.11,192.168.0.12 # In order for Galera to work correctly binlog format should be ROW binlog_format=ROW # MyISAM storage engine has only experimental support default_storage_engine=InnoDB # This changes how InnoDB autoincrement locks are managed and is a requirement for Galera innodb_autoinc_lock_mode=2 # Node #1 address wsrep_node_address=192.168.0.10 # SST method wsrep_sst_method=xtrabackup-v2 # Cluster name wsrep_cluster_name=my_ubuntu_cluster # Authentication for SST method wsrep_sst_auth="sstuser:s3cretPass" # Error Log log_error = /var/log/mysql/error.log |
En este momento debes estar preguntándote qué significa todo esto. Acá te dejo una breve explicación de cada uno de los elementos de la configuración:
- Los dos primeros valores,
datadir
yuser
son: el directorio de datos de MySQL y el usuario que se utiliza para acceder a los datos, respectivamente.
es el directorio donde se encuentra la librería galera. Este tutorial está ejemplificado en un sistema operativo de 64 bits. Si utilizas un sistema de 32 bits la librería galera se encontrará en el directoriowsrep_provider:
wsrep_cluster_address
: contiene las direcciones de cada nodo dentro del clúster separadas por «,».binlog_format
: contiene el formato en el que se guarda el log binario y según la especificación de Percona debe serROW
.default_storage_engine
: este valor le indica al clúster el tipo de tablas que debe replicar. Sin embargo, por limitaciones de Galera, este valor siempre debe serInnoDB
- innodb_autoinc_lock_mode: este valor, por defecto, es 1 en un servidor MySQL común, pero en el clúster de Percona es necesario ponerlo en 2 para evitar errores en la replicación.
wsrep_node_address
: es la dirección del nodo actual.wsrep_sst_method
: es el método de réplica empleado. Es recomendable utilizarxtrabackup-v2
, al menos en el momento de escribir este artículo (Versión del clúster 5.6).wsrep_cluster_name
: es el nombre que deseas ponerle al clúster. Puede tener cualquier valor, pero sí debe ser el mismo en todos los nodos.wsrep_sst_auth
: son las credenciales para poder autenticar el usuario de réplica en las instancias MySQL. Es un valor con la siguiente estructura «nombre_usuario:contraseña
«log_error
: es la ubicacion del log de errores.
Una vez que hayas terminado de edtitar el archivo, solo resta guardar el documento y salir del editor (ctrl + X
y luego Y,
en caso de utilizar nano).
Es momento de que inicies el primer nodo del clúster. Para eso ejecuta el siguiente comando:
1 |
$ sudo /etc/init.d/mysql bootstrap-pxc |
Este comando ejecuta el primer nodo sin la necesidad de que estén activos los nodos restantes del clúster. A este proceso se le llama bootstrap.
Como el bootstrap no inicia el servicio MySQL, es preciso que lo inicies utilizando el comando:
1 |
$ sudo systemctl start mysql |
Para comprobar que se haya iniciado correctamante usa: systemctl status mysql.
Deberás ver algo como esto:
1 2 3 4 5 6 |
● mysql.service - LSB: Start and stop the mysql (Percona XtraDB Cluster) daemon Loaded: loaded (/etc/init.d/mysql; bad; vendor preset: enabled) Active: active (running) since Wed 2016-09-28 19:36:48 UTC; 3s ago Docs: man:systemd-sysv-generator(8) Process: 3461 ExecStop=/etc/init.d/mysql stop (code=exited, status=0/SUCCESS) Process: 3862 ExecStart=/etc/init.d/mysql start (code=exited, status=0/SUCCESS) |
Lo otro que debes hacer es iniciar sesión en MySQL y comprobar el estado del clúster con el siguiente comando:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
mysql> show status like 'wsrep%'; +----------------------------+--------------------------------------+ | Variable_name | Value | +----------------------------+--------------------------------------+ | wsrep_local_state_uuid | b598af3e-ace3-11e2-0800-3e90eb9cd5d3 | ... | wsrep_local_state | 4 | | wsrep_local_state_comment | Synced | ... | wsrep_cluster_size | 1 | | wsrep_cluster_status | Primary | | wsrep_connected | ON | ... | wsrep_ready | ON | +----------------------------+--------------------------------------+ 59 rows in set (0.01 sec) |
Configurar los 2 nodos restantes
La configuración de los 2 nodos restantes es exactamente igual a la del primer nodo, solo cambia la propiedad:
1 2 |
# Node #2 address wsrep_node_address=192.168.0.11 |
Una vez que copies el archivo de configuración del primer nodo y cambies el parámetro wsrep_node_address
debes iniciar el MySQL con el siguiente comando:
1 |
$ sudo systemctl start mysql |
Inicia sesión y comprueba el estado del clúster:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
mysql> show status like 'wsrep%'; +----------------------------+--------------------------------------+ | Variable_name | Value | +----------------------------+--------------------------------------+ | wsrep_local_state_uuid | a1696cc0-85b2-11e6-b4af-7703b3bcc33a | ... | wsrep_local_state | 4 | | wsrep_local_state_comment | Synced | ... | wsrep_cluster_size | 2 | | wsrep_cluster_status | Primary | | wsrep_connected | ON | ... | wsrep_ready | ON | +----------------------------+--------------------------------------+ 59 rows in set (0.01 sec) |
Lo más importante es que el parámetro wsrep_cluster_size
tenga un valor mayor a 1, 2 en el caso de que tengas 2 nodos 3 en el caso de 3 y así sucesivamente.
Probar el funcionamiento
Para probar el funcionamiento del Percona XtraDB Clúster harás una serie de consultas en cada nodo de forma aleatoria y revisarás que la información esté en los otros 2 nodos.
En el nodo 1 escribe:
1 2 |
CREATE DATABASE dbtest; Query OK, 1 row affected (0.09 sec) |
En el 2:
1 2 |
mysql> USE dbtest; Database changed |
En el nodo 3:
1 2 |
mysql> CREATE TABLE example (node_id INT PRIMARY KEY, node_name VARCHAR(30)); Query OK, 0 rows affected (0.00 sec) |
Regresa al nodo 1 y escribe:
1 2 |
mysql> INSERT INTO dbtest.example VALUES (1, 'node1'); Query OK, 1 row affected (0.03 sec) |
Luego en el nodo 2 podrás ver los datos insertados:
1 2 3 4 5 6 7 |
mysql> SELECT * FROM dbtest.example; +---------+-----------+ | node_id | node_name | +---------+-----------+ | 1 | node1 | +---------+-----------+ 1 row in set (0.00 sec) |
Llegado a este punto verás que la réplica entre los nodos funciona perfectamente.
Prueba más exhaustiva
Si todavía no estás totalmente convencido de que la réplica funciona como esperas, puedes utilizar el siguiente script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/bin/bash host1=192.168.0.10 host2=192.168.0.11 host3=192.168.0.12 i=0 while [ $i -le 2000 ] do mysql -u remote -pmipass -h $host1 -D dbtest -e 'INSERT INTO dbtest.example VALUES ($i, 'node1');' ((i++)) mysql -u remote -pmipass -h $host2 -D dbtest -e 'INSERT INTO dbtest.example VALUES ($i, 'node2');' ((i++)) mysql -u remote -pmipass -h $host3 -D dbtest -e 'INSERT INTO dbtest.example VALUES ($i, 'node3');' ((i++)) done |
Con este script podrás comprobar que el campo node_id
aumenta consecutivamente hasta 2000, mientras que el campo node_name
te muestra qué nodo ejecutó la inserción.
Punto final
Finalmente, deberías probar qué pasa cuando uno de los nodos cae. Para ello, puedes utilizar un balanceador de carga, HAProxy por ejemplo, y añadir los nodos del clúster. Con HAProxy es muy fácil de hacerlo. Puedes seleccionar el algoritmo de balanceo de Round Robin para que actúe como un balanceador «tonto» que simplemente vaya repartiendo las conexiones entre los nodos del clúster una a una.
Una vez que lo tengas, puedes modificar el script anterior para enviar los inserts
a la IP del balanceador y que éste se encargue de balancear entre los nodos. Mientras, puedes apagar uno de los nodos, parando el servicio mysqld
o habilitando iptables
para simular la caída y ver qué pasa en los otros 2. Debes ver un incremento lineal de la variable para cerciorarte de que todo funciona bien.