Crear un cluster de base de datos MariaDB con Galera

De Apuntes
Saltar a: navegación, buscar

MariaDB es un sistema de gestión de bases de datos derivado de MySQL con licencia GPL (General Public License). Es desarrollado por Michael (Monty) Widenius (fundador de MySQL), la fundación MariaDB y la comunidad de desarrolladores de software libre.[1]

Por otro lado Galera es un sistema de cluster síncrono y multi-maestro para MariaDB. [2]

Esta guía es parte de un conjunto de tutoriales para bases de datos con MariaDB y mostrará la manera más básica para desplegar un cluster multi-maestro con MariaDB Galera Cluster.

Guías
Crear un cluster de base de datos MariaDB con Galera
Configurar balanceador de cargas para MariaDB Galera Cluster


Prerrequisitos

Servidores

Se requiere de al menos 3 nodos para desplegar el cluster, ya sea físicos o virtuales.

Las características de cada uno dependerá del contexto en donde se vaya a desplegar el cluster.

Se recomienda al menos 4 cores y 8 GB de RAM

Software

Esta guía esta planteada para ser ejecutada en el sistema Debian GNU/Linux 10, no obstantes muchos de los pasos pueden ser replicados en otras distribuciones de GNU/Linux.

Se asume que el sistema operativo ya se encuentra instalado, que los equipos cuentan con conectividad de red y pueden comunicarse entre ellos.

Asimismo, es necesario que cada equipo pueda resolver el nombre de los otros por lo que se debe editar el archivo /etc/hosts y agregar cada nodo:

127.0.0.1	localhost
172.16.0.34	db00.beta.ucr.ac.cr	db00
172.16.0.35	db01.beta.ucr.ac.cr	db01
172.16.0.36	db02.beta.ucr.ac.cr	db02

Instalación

MariaDB Galera Cluster

Los siguientes comandos agregan el repositorio oficial de MariaDB e instalan el software requerido.

Para determinar cuál repositorio debe ser configurado, puede consultarse el sitio https://downloads.mariadb.org/mariadb/repositories/

sudo apt-get install software-properties-common dirmngr
sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'
sudo add-apt-repository 'deb [arch=amd64] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.4/debian buster main'
sudo apt-get update
sudo apt-get install mariadb-server

La secuencia de comandos anterior debe ejecutarse en los 3 nodos.

Configuración

Archivo de configuración

En todos los nodos, se edita o se crea el archivo /etc/mysql/mariadb.conf.d/galera.cnf

sudo editor /etc/mysql/mariadb.conf.d/galera.cnf

Se agrega el siguiente contenido

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so

# Galera Cluster Configuration
wsrep_cluster_name="db_cluster_beta"
wsrep_cluster_address="gcomm://db00,db01,db02"

# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Can use mariabackup: apt install mariadb-backup
# https://mariadb.com/kb/en/library/mariadb-backup-overview/#using-mariadb-backup-for-galera-ssts
#wsrep_sst_method=mariabackup
#wsrep_sst_auth=USER:PASSWORD


# Galera Node Configuration
wsrep_node_address="IP_DEL_NODO"
wsrep_node_name="NOMBRE_DEL_NODO"

Nótese que wsrep_node_address y wsrep_node_name deben coincidir con la dirección IP y el nombre del nodo en donde se está creando el archivo. Así, por ejemplo, en el nodo db0 estas variables serán "172.16.0.34" y "db0" respectivamente.

Construcción del cluster

Opcionalmente, para asegurar la instalación de MariaDB y borrar las bases de datos de pruebas se ejecuta el siguiente comando solamente en uno de los nodos

sudo mysql_secure_installation

Se detiene el servicio de MariaDB en todos los nodos ejecutando el siguiente comando en cada uno de ellos

sudo systemctl stop mysql

Se verifica que el servicio esté detenido

sudo systemctl is-active mysql

El comando debe mostrar "inactive"

Ahora, en el nodo db00 se crea el nuevo cluster de Galera ejecutando el siguiente comando solamente en el nodo db00

sudo galera_new_cluster

Se verifica que el cluster haya inicializado

mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"

Debe mostrar lo siguiente

+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 1     |
+--------------------+-------+

Luego, se inicia el servicio de MariaDB normalmente en los otros nodos

sudo systemctl start mysql

Se verifica que los nodos hayan sido agregados al cluster

mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"

Ahora debe mostrarse el número total de nodos

+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     |
+--------------------+-------+

Por último, se requiere copiar la información de la cuenta de mantenimiento de Debian en los otros nodos del cluster. Para esto se copia la información del archivo /etc/mysql/debian.cnf del nodo db00 a los otros nodos. Puede realizarse de manera manual o utilizando el comando scp.

NOTA: Se debe recordar que la replicación de Galera solo funciona sobre bases de datos en InnoDB. Por ejemplo, base de datos de system como 'mysql' (MyISAM) no son replicadas, excepto en la replicación inicial; no obstante, sentencias como CREATE USER y GRANT sí se replican, por lo que la creación de un usuario con estas sentencias sí se replicarán en el cluster pero si se utiliza INSERT no.

Pruebas de replicación

Se crea la base de datos playground en el nodo db00:

(db00)$ mysql -u root -p -e 'CREATE DATABASE playground;
  CREATE TABLE playground.equipment ( id INT NOT NULL AUTO_INCREMENT, type VARCHAR(50), quant INT, color VARCHAR(25), PRIMARY KEY(id));
  INSERT INTO playground.equipment (type, quant, color) VALUES ("slide", 2, "blue");'

Se observa el cambio en el nodo db01:

(db01)$ mysql -u root -p -e 'SELECT * FROM playground.equipment;'

Se mostrarán la tabla y el valor insertados desde nodo db00.

Luego, se inserta un nuevo valor desde nodo db01

(db01)$ mysql -u root -p -e 'INSERT INTO playground.equipment (type, quant, color) VALUES ("swing", 10, "yellow");'

Se observa el cambio en nodo db02:

(db02)$ mysql -u root -p -e 'SELECT * FROM playground.equipment;'

Se mostrarán los valores del nodo db00 y db01.

Se inserta un nuevo valor desde nodo db02

(db02)$ mysql -u root -p -e 'INSERT INTO playground.equipment (type, quant, color) VALUES ("seesaw", 3, "green");'

Se puede observar que los cambios se reflejan en todos los nodos.

Problemas

Nodos no se comunican

Se debe verificar que los puertos del firewall estén abiertos. Galera puede hacer uso de 4 puertos:

  • 3306 For MySQL client connections and State Snapshot Transfer that use the mysqldump method.
  • 4567 For Galera Cluster replication traffic, multicast replication uses both UDP transport and TCP on this port.
  • 4568 For Incremental State Transfer.
  • 4444 For all other State Snapshot Transfer.

Recuperar nodos luego de un fallo

Si se da un fallo en todo el cluster y debe ser reiniciado (ej. un fallo eléctrico), el servicio no iniciará normalmente y se debe realizar un proceso de recuperación. En las bitácoras el mensaje de error sería similar a este:

mysqld[1411]: 2018-06-26 15:16:52 0 [ERROR] WSREP: failed to open gcomm backend connection: 110: failed to reach primary view: 110 (Connection timed out)
mysqld[1411]:          at gcomm/src/pc.cpp:connect():158
mysqld[1411]: 2018-06-26 15:16:52 0 [ERROR] WSREP: gcs/src/gcs_core.cpp:gcs_core_open():208: Failed to open backend connection: -110 (Connection timed out)
mysqld[1411]: 2018-06-26 15:16:52 0 [ERROR] WSREP: gcs/src/gcs.cpp:gcs_open():1458: Failed to open channel 'db_cluster_beta' at 'gcomm://db00,db01,db02': -110 (Connection timed out)
mysqld[1411]: 2018-06-26 15:16:52 0 [ERROR] WSREP: gcs connect failed: Connection timed out
mysqld[1411]: 2018-06-26 15:16:52 0 [ERROR] WSREP: wsrep::connect(gcomm://db00,db01,db02) failed: 7
mysqld[1411]: 2018-06-26 15:16:52 0 [ERROR] Aborting
systemd[1]: mariadb.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: Failed to start MariaDB 10.3.7 database server.

El primer paso es determinar el seqno (Número de secuencia) válido, esto determina cuál de los nodos posee el último estado consistente. Se debe revisar el archivo /var/lib/mysql/grastate.dat (la ubicación puede ser diferente según la distribución) en cada uno de los nodos. El nodo con el seqno más grande es el que posee los datos más actuales antes de la caída.

El siguiente es un ejemplo del archivo grastate.dat

# GALERA saved state
version: 2.1
uuid:    cf9e1fb2-7660-11e8-9b5b-9fe6692e98e3
seqno:   -1
safe_to_bootstrap: 1

Si el archivo muestra en seqno en -1, significa que el nodo no se apagó correctamente. Para determinar el seqno se ejecuta el siguiente comando:

mysqld --wsrep-recover

Esto iniciará mysqld, leerá los encabezados de InnoDB y luego se apagará. La última posición de wsrep se mostrará en las bitácoras o en pantalla. Es importante determinar el seqno de todos los nodos que tienen un uuid válido en el archivo grastate.dat.

[Note] WSREP: Recovered position: cf9e1fb2-7660-11e8-9b5b-9fe6692e98e3:165060

En el caso anterior, el seqno es 165060, este valor puede ser introducido manualmente en el archivo grastate.dat. Se debe revisar cada uno de los nodos para determinar cuál posee el número de secuencia más grande.

Además del número de secuencia, el archivo muestra la opción safe_to_bootstrap que, cuando posee el valor de 1, podría ayudar a determinar cuál nodo puede ser utilizado para iniciar el cluster. Si fuera el caso que ninguno de los nodos posee safe_to_bootstrap: 1, se debe determinar el número de secuencia y luego cambiar el valor de 0 a 1 para el nodo más apto y así forzarlo como nodo de inicialización.

Una vez determinado el nodo más apto para iniciar el cluster, se ejecuta el siguiente comando solamente en dicho nodo y se espera a que la base de datos inicie:

mysqld_safe -- wsrep_cluster_address=gcomm:// &;

Luego de que se tiene la base de datos arriba, se inicia el servicio de MariaDB en los demás nodos como normalmente se haría, solo uno a la vez:

systemctl start mariadb

Una ves que todos los nodos están arriba y en estado consistente (primary state), se reinicia el primer nodo (el que fue ejecutado con mysqld_safe) de la manera normal para que de esta forma se reincorpore al cluster como un nodo más y no como el iniciador.

Mejoras de rendimiento

Las mejoras de rendimiento (performace) deben analizarse según la carga de cada sistema, el rendimiento de los servidores de base de datos, discos duros y red.

Se recomienda el uso de herramientas para medir el rendimiento y otras que sugieren recomendaciones como mysqltuner y PHPMyAdmin.

Algunos valores que se pueden tomar de referencia y que fueron utilizados en los servidores de prueba para la elaboración de esta guía son los siguientes:

# FILE: /etc/mysql/mariadb.conf.d/galera_performance.cnf                           
[mysqld]
# Variables
innodb_flush_log_at_trx_commit=0
#innodb_doublewrite=0
#sync_binlog=0

## Constant
innodb_buffer_pool_size=5G
innodb_buffer_pool_instances=5
#innodb_log_file_size=1500M
#innodb_log_files_in_group=2
#innodb_locks_unsafe_for_binlog=1
#wsrep_slave_threads=32

#max_connections=1000

##idle_readonly_transaction_timeout     0
##idle_transaction_timeout      0
##idle_write_transaction_timeout        0

#innodb_open_files=2000
#max_heap_table_size=1073741824

query_cache_limit=2M
query_cache_size=512M 

#slow_query_log=ON
#slow_query_log_file=/var/log/mysql/mariadb-slow.log

#table_open_cache=2000

tmp_table_size=1G
max-heap-table-size = 1G


Los servidores (virtuales) de la prueba poseen 4 procesadores y 16 GB de RAM, sin discos rápidos ni optimizaciones de hardware. Los valores anteriores no deben se aplicados sin primero analizar la plataforma pues son muy dependientes de los factores del contexto donde se despliega la base de datos, las consultas y los datos mismos. Para consultar los valores de las variables, visitar: https://mariadb.com/kb/en/library/server-system-variables/

La herramienta que se utilizó para realizar el benchmark fue sysbench, con el siguiente script de bash y utilizando contenedores de Docker:

#!/bin/bash

# Run this manually to prepare some tables:
# mysqladmin -uroot -p create sbtest
# docker run -it --rm severalnines/sysbench sysbench \
#  --db-driver=mysql --mysql-host=172.16.251.34 \
#  --mysql-user=sbtest --mysql-password="SECURE_PASSWORD" \
#  --mysql-table-engine=InnoDB --mysql-engine-trx=yes \
#  --oltp-table-size=2000000 --oltp-auto-inc=off \
#  --max-requests=0 --threads=1 --oltp-tables-count=10 \
#  /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua prepare
# The above creates a dataset roughly
# 189,8*2000000*10/1024/1024 = 3620M = 3,5G

DBDIR=$(dirname "$0")
#NUM_THREADS="1"
NUM_THREADS="1 2 4 8 16 32 64 128 256 512 1023"
#TEST_DBS="172.16.251.40" # For testing maxscale LB
TEST_DBS="172.16.251.34,172.16.251.35,172.16.251.36"
PASS_DB="SECURE_PASSWORD"
USER_DB="sbtest"

for N in $NUM_THREADS; do
  # --oltp-auto-inc=off is undocumented, but important when running galera.
  # sysbench assumes that autoinc columns will be a continuos sequence 1,2,3...
  # but with galera they're not (auto_increment_increment)
  docker run -it --rm severalnines/sysbench sysbench \
    --db-driver=mysql --mysql-host=$TEST_DBS \
    --mysql-user=$USER_DB --mysql-password=$PASS_DB \
    --mysql-table-engine=InnoDB --mysql-engine-trx=yes \
    --oltp-table-size=2000000 --time=60 \
    --max-requests=0 --threads=$N --oltp-tables-count=10 \
    --oltp-auto-inc=off /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua run
done

Enlaces

Enlaces de referencia