Configurar Percona XtraDB Cluster con Docker

By rogerarjona Sept. 13, 2024, 11:36 p.m.

¿Qué es Percona XtraDB Cluster?

Percona XtraDB Cluster es una versión avanzada de MySQL que permite que múltiples servidores de bases de datos trabajen juntos como un solo "clúster". Imagina que tienes varias computadoras (servidores) que actúan como una única base de datos. El propósito principal de este clúster es ofrecer alta disponibilidad y replicación de datos en tiempo real.

¿Por qué usar un clúster de bases de datos?

En desarrollo, a veces una sola base de datos puede no ser suficiente por varias razones:

  1. Escalabilidad: Si tienes muchos usuarios y una sola base de datos, el servidor puede saturarse. Un clúster permite distribuir la carga entre múltiples servidores.
  2. Disponibilidad: Si la única base de datos falla, tu aplicación se detiene. Con un clúster, los datos se replican entre varios servidores, por lo que si uno falla, los demás continúan funcionando.
  3. Seguridad de datos: Al tener los datos replicados en varios servidores, reduces el riesgo de pérdida de datos.

¿Cómo funciona Percona XtraDB Cluster?

Para entender cómo funciona, imagina un equipo de personas trabajando en un documento compartido:

  1. Replicación en tiempo real: Cuando uno de los servidores (nodos) recibe una solicitud para agregar, modificar o eliminar datos, esta información se copia automáticamente a los demás servidores del clúster. Es como si varias personas estuvieran editando el mismo documento y cada cambio se sincronizara inmediatamente para que todos vean lo mismo.
  2. Todos los nodos son iguales: En un clúster de Percona, todos los servidores (nodos) pueden realizar operaciones de lectura y escritura. No hay un "servidor principal" y un "servidor secundario" como en otros sistemas. Esto significa que puedes distribuir las solicitudes de tu aplicación entre los diferentes nodos para mejorar la velocidad y eficiencia.
  3. Consenso y sincronización: Percona XtraDB Cluster usa un mecanismo llamado Galera para asegurarse de que todos los nodos estén sincronizados. Si un nodo recibe una solicitud para insertar datos, ese cambio debe ser aprobado por los demás nodos antes de aplicarse. Esto garantiza que los datos sean coherentes en todos los servidores.
  4. Fallos y recuperación: Si un nodo falla, el clúster sigue funcionando con los demás nodos. Cuando el nodo caído se reinicia, automáticamente se sincroniza con el resto del clúster para recuperar los datos que se perdió mientras estuvo desconectado.

¿Cómo se configura Percona XtraDB Cluster en términos simples?

  • Nodos: Un clúster de Percona está formado por varios nodos. Cada nodo es básicamente una instancia de MySQL que está configurada para sincronizar datos con los demás nodos.
  • Replicación: Al escribir o actualizar datos en uno de los nodos, esos cambios se replican a los otros nodos casi inmediatamente.
  • Balanceo de carga: En tu aplicación, puedes configurar las operaciones de lectura y escritura para que se distribuyan entre los nodos. Por ejemplo, puedes configurar que todas las escrituras se hagan en un nodo específico y que las lecturas se distribuyan entre los demás nodos.

1. Crear contenedores de Docker


NOTA

Para poder seguir los pasos del manual sera necesario tener instalado docker previamente, si aun lo has hecho puedes consultar la documentación oficial para tu sistema operativo. Install Docker Engine


1.1 Crear archivos Dockerfile y docker-compose.yml

Creamos una carpeta llamada percona-xdb-cluster

mkdir percona-xdb-cluster

Nos posicionamos dentro de la carpeta y creamos el archivo Dockerfile y docker-compose.yml

nano Dockerfile

Pegamos el siguiente contenido dentro de nuestro Dockerfile

# Dockerfile

# Usar la imagen base de Ubuntu 20.04
FROM ubuntu:20.04

# Establecer el entorno no interactivo para evitar prompts durante la instalación
ENV DEBIAN_FRONTEND=noninteractive

# Exponer el puerto 3306 para MySQL
EXPOSE 3306

Creamos el archivo docker-compose.yml

nano docker-compose.yml

Pegamos el siguiente contenido dentro de nuestro docker-compose.yml

version: '3.8'

services:
  mysql-server-1:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-1
    hostname: node-1
    networks:
      custom_network:
        ipv4_address: 172.20.0.3
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql1_data:/var/lib/mysql
    ports:
      - "3308:3306"  # Mapeo de puerto para acceso externo
    #command: mysqld_safe
    command: bash -c "tail -f /dev/null"
  mysql-server-2:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-2
    hostname: node-2
    networks:
      custom_network:
        ipv4_address: 172.20.0.4
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql2_data:/var/lib/mysql
    ports:
      - "3309:3306"  # Mapeo de puerto para acceso externo
    # command: mysqld_safe
    command: bash -c "tail -f /dev/null"
  mysql-server-3:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-3
    hostname: node-3
    networks:
      custom_network:
        ipv4_address: 172.20.0.5
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql3_data:/var/lib/mysql
    ports:
      - "3310:3306"  # Mapeo de puerto para acceso externo
    # command: mysqld_safe
    command: bash -c "tail -f /dev/null"

networks:
  custom_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

volumes:
  proxy_data:
  mysql1_data:
  mysql2_data:
  mysql3_data:

1.2 Levantar contenedores

Levantamos los contenedores usando el siguiente comando

docker compose up --build

1.3 Comprobación

Una vez hecho esto deberiampos poder nuestros contenedores usando el siguiente comando

docker ps

La salida del comando deberia ser algo similar a esto

CONTAINER ID   IMAGE                                 COMMAND                  CREATED       STATUS       PORTS                                             NAMES
e57dde592d32   dokcer-cluster-mysql-mysql-server-1   "bash -c 'tail -f /d…"   3 hours ago   Up 3 hours   4444/tcp, 4567-4568/tcp, 0.0.0.0:3308->3306/tcp   mysql-server-1
1ac0df8488c3   dokcer-cluster-mysql-mysql-server-2   "bash -c 'tail -f /d…"   3 hours ago   Up 3 hours   4444/tcp, 4567-4568/tcp, 0.0.0.0:3309->3306/tcp   mysql-server-2
191806016fff   dokcer-cluster-mysql-mysql-server-3   "bash -c 'tail -f /d…"   3 hours ago   Up 3 hours   4444/tcp, 4567-4568/tcp, 0.0.0.0:3310->3306/tcp   mysql-server-3
f448ea10cc7f   dokcer-cluster-mysql-proxysql         "bash -c 'tail -f /d…"   3 hours ago   Up 3 hours   4444/tcp, 4567-4568/tcp, 0.0.0.0:3307->3306/tcp   mysql-proxysql

2. Instalar Percona XtraDB Cluster

Una vez que tengamos nuestro contenedores corriendo, procedemos a configurar, para ello realizaremos los pasos descritos en Implementar Percona Cluster - Parte 1, en este caso omitiremos la instalación del proxy, trabajaremos unicamente con los nodos

Para acceder a nuestro primer nodo usamos el siguiente comando

docker exec -it <id_contenedor> bash
# Ejemplo:
docker exec -it e57dde592d32 bash

Una vez hayamos accedido a nuestro contenedor realizamos la instalación de Percona XtraDB Cluster

# Actualizamos nuestro sistema
apt-get update

# Instalamos wget, lsb-release, gnup y curl
apt-get install -y wget lsb-release gnupg curl systemctl nano htop tree net-tools

# Actualizamos nuevamente
apt update

wget https://repo.percona.com/apt/percona-release_latest.generic_all.deb

dpkg -i percona-release_latest.generic_all.deb

percona-release setup pxc57

apt install -y libdbi-perl libdbd-mysql-perl libmecab2 socat  libcurl4-openssl-dev libev4

apt install -y percona-xtrabackup-24  qpress

apt install -y percona-xtradb-cluster-full-57=5.7.40-31.63-1.focal percona-xtradb-cluster-server-5.7=5.7.40-31.63-1.focal percona-xtradb-cluster-client-5.7=5.7.40-31.63-1.focal percona-xtradb-cluster-test-5.7=5.7.40-31.63-1.focal percona-xtradb-cluster-5.7-dbg=5.7.40-31.63-1.focal percona-xtradb-cluster-server-debug-5.7=5.7.40-31.63-1.focal percona-xtradb-cluster-garbd-5.7=5.7.40-31.63-1.focal percona-xtradb-cluster-garbd-debug-5.7=5.7.40-31.63-1.focal percona-xtradb-cluster-common-5.7=5.7.40-31.63-1.focal

Repetimos los pasos en nuestros nodos restantes

3. Configuración de los nodos

3.1 Configuración de los nodos

Para acceder a nuestro primer nodo usamos el siguiente comando

docker exec -it <id_contenedor> bash
# Ejemplo:
docker exec -it e57dde592d32 bash

Una vez dentro de nuestro contenedor configuramos el archivo wsrep.cnf

nano /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf

NOTA

Usamos nano como editor para poder modificar nuestros archivos, sin embargo, nano no viene instalado por defecto, para instalarlo podemos usar el siguiente comando `apt-get install nano`


Modificaremos unicamente lo siguiente:

wsrep_cluster_address=gcomm://<ip_nodos_cluster>
wsrep_node_address=<ip_nodo>
wsrep_node_name=<nombre_nodo>
pxc_strict_mode=PERMISSIVE
wsrep_sst_auth="sstuser:<my_secure_password>"

Nuestro archivos deberian verse de la siguiente manera en cada nodo

Nodo 1:

[mysqld]
# Path to Galera library
wsrep_provider=/usr/lib/galera3/libgalera_smm.so

wsrep_cluster_address=gcomm://172.20.0.3,172.20.0.4,172.20.0.5 # IPs de los nodos que conforman el cluster
binlog_format=ROW

default_storage_engine=InnoDB

wsrep_slave_threads= 4

wsrep_log_conflicts

innodb_autoinc_lock_mode=2

wsrep_node_address=172.20.0.3 # IP del nodo que estamos configurando
wsrep_cluster_name=pxc-cluster

wsrep_node_name=Node-1 # Nombre de nuestro nodo, es importante que no se repita el nombre entre nodos

pxc_strict_mode=PERMISSIVE

wsrep_sst_method=xtrabackup-v2

wsrep_sst_auth="sstuser:my_secure_password"

Nodo 2:

[mysqld]
# Path to Galera library
wsrep_provider=/usr/lib/galera3/libgalera_smm.so

wsrep_cluster_address=gcomm://172.20.0.3,172.20.0.4,172.20.0.5 # IPs de los nodos que conforman el cluster
binlog_format=ROW

default_storage_engine=InnoDB

wsrep_slave_threads= 4

wsrep_log_conflicts

innodb_autoinc_lock_mode=2

wsrep_node_address=172.20.0.4 # IP del nodo que estamos configurando
wsrep_cluster_name=pxc-cluster

wsrep_node_name=Node-2 # Nombre de nuestro nodo, es importante que no se repita el nombre entre nodos

pxc_strict_mode=PERMISSIVE

wsrep_sst_method=xtrabackup-v2

wsrep_sst_auth="sstuser:my_secure_password"

Nodo 3:

[mysqld]
# Path to Galera library
wsrep_provider=/usr/lib/galera3/libgalera_smm.so

wsrep_cluster_address=gcomm://172.20.0.3,172.20.0.4,172.20.0.5 # IPs de los nodos que conforman el cluster
binlog_format=ROW

default_storage_engine=InnoDB

wsrep_slave_threads= 4

wsrep_log_conflicts

innodb_autoinc_lock_mode=2

wsrep_node_address=172.20.0.5 # IP del nodo que estamos configurando
wsrep_cluster_name=pxc-cluster

wsrep_node_name=Node-3 # Nombre de nuestro nodo, es importante que no se repita el nombre entre nodos

pxc_strict_mode=PERMISSIVE

wsrep_sst_method=xtrabackup-v2

wsrep_sst_auth="sstuser:my_secure_password"

Asegurate que en las variables wsrep_node_address y wsrep_node_name coloquemos la IP y nombre respectivamente del nodo que se este configurando, en el caso de la variable wsrep_sst_auth es importante que coloquemos la misma contraseña,

3.2 Iniciar el primer nodo

Una vez que hemos finalizado al configuración de nuestros 3 nodos, accedemos al nodo 1 y lo inicializamos usando el siguiente comando

/etc/init.d/mysql bootstrap-pxc

Este comando iniciara nuestro nodo pero ademas indicara que es nuestro nodo principal

Una vez hecho esto accedemos a mysql

mysql -u root -p

Podemos verificar el estado de nuestro cluster usando el siguiente comando

show status like 'wsrep%';

La salida del comando deberia ser algo similar a esto

+----------------------------+--------------------------------------+
| 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                                   |
+----------------------------+--------------------------------------+
40 rows in set (0.01 sec)

Para realizar la transferencia de instantáneas de estado usando XtraBackup, configure un nuevo usuario con los privilegios adecuados

CREATE USER 'sstuser'@'%' IDENTIFIED BY 'my_secure_password';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sstuser'@'%';
FLUSH PRIVILEGES;

NOTA

El usuario debe crearse en el servidor que inicializara el Cluster. Para este caso, se crea en el Nodo 1


3.3 Iniciar el segundo y tercer nodo

Accedemos a los nodos 2 y 3 respectivamente y ejecutamos el siguiente comando

/etc/init.d/mysql start

Eso inicializara nuestro nodo y deberia sincronizarse con nuestro nodo principal, nodo 1

Una vez se haya inicializado ingresamos a mysql y comprobamos el estado de nuestro cluster

mysql -u root -p
show status like 'wsrep%';

La salida de nuestro comando ahora deberia mostrarnos que el tamaño del cluster ha cambiado, podemos observarlo en la variable wsrep_cluster_size

+----------------------------+--------------------------------------+
| Variable_name              | Value                                |
+----------------------------+--------------------------------------+
| wsrep_local_state_uuid     | b598af3e-ace3-11e2-0800-3e90eb9cd5d3 |
| wsrep_local_state          | 4                                    |
| wsrep_local_state_comment  | Synced                               |
| wsrep_cluster_size         | 2                                    |  -- El cluster size ha incrementado una vez iniciamos un nodo
| wsrep_cluster_status       | Primary                              |
| wsrep_connected            | ON                                   |
| wsrep_ready                | ON                                   |
+----------------------------+--------------------------------------+
40 rows in set (0.01 sec)

NOTA

Hasta este punto, ya tendras un Cluster de Base de Datos con Percona XtraDB Cluster.
La información se replica entre todos los nodos.

Puedes comprobarlo creando una base de datos.


4. Importar Base de Datos

4.1 Crear base de datos

Para poder realizar las pruebas podemos crear una base de datos con datos de prueba, para el ejercicio trabajaremos con la siguiente base de datos: CompanyDB

Ingresamos a mysql y creamos una base de datos

mysql -u root -p

Una vez hayamos accedido a mysql podemos crear la base de datos usando el siguiente comando

CREATE DATABASE companydb;

Salimos de mysql

exit

Para poder importar la base de datos sera necesario agregarla al volumen de nuestro contenedor, puedes hacerlo de la siguiente forma en una nueva terminal:

docker docker cp /path/to/bdahkinc.sql mysql-server-1:/data/

Una vez la hayamos importado nos posicionamos en la ruta donde tengamos nuestro backup y ejectuamos el siguiente comando

mysql -u root -p companydb < backup.sql

NOTA

Si te da error importar la base de datos, porque el collation no corresponde a tu version de MySQL, puede ejecutar lo siguiente:

sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g' backup.sql -> Actualizar la bd


4.2 Comprobación

Esto nos importara la información de la base de datos que creamos previamente, ademas, al tener configurados nuestros nodos deberia replicarse la información de nuestra base de datos, para ello podemos comprobarlo accediendo a mysql en alguno de nuestros nodos

mysql -u root -p

Verificamos que tengamos la base de datos que creamos en el nodo 1

show databases;

La salida del comando deberia mostrarnos la base de datos que creamos en el nodo 1

+--------------------+
| Database           |
+--------------------+
| information_schema |
| companydb          | -- Base de datos que creamos en el nodo 1
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)

Una vez que hayamos comprobado que tenemos nuestra base de datos en los tres nodos podemos realizar las pruebas, las pruebas que realizaremos seran las mismas que se hicieron en Implementar Percona Cluster - Parte 2

Al final el nodo que hemos creado se veria de la siguiente manera

diagramaDockerCluster1.png

5. Replicación de Información


NOTA

La finalidad de esta prueba es agregar registros en uno de nuestros nodos, al encontrarse dentro de un cluster la información deberia replicarse a nuestros otros nodos.


5.1 Conectarse a cualquier nodo

docker exec -it <id_contenedor> bash

5.2 Para comprobar que todos los nodos estan conectados podemos hacer lo siguiente

5.2.1 Conectarse a mysql en los nodos

mysql

5.2.2 Conectarse a la base de datos

use companydb;

5.2.3 Verificamos en todos los nodos el ultimo ID

select * from Companies order by CompanyID DESC LIMIT 10 \G

percona_1_2.png

5.2.4 Hacer inserciones en el nodo 1 (se puede realizar desde cualquier nodo):

INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');
INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');
INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');

Creamos 3 registros en el nodo 1, al crearlo, la información debería reflejarse en los otros nodos

percona_1_3.png

Volvemos a verificar los últimos IDs

5.3 En todos los nodos, verificamos que la información se este replicando correctamente:

select * from Companies order by CompanyID DESC LIMIT 10 \G

Podemos observar que la información se ha replicado correctamente

percona_1_4.png

6. Reintegro de un Servidor Caído


NOTA

La finalidad de esta prueba es que si uno de nuestros nodos esta caido/detenido, al momento de ponerse nuevamente en linea este deberia sincronizarse con nuestros nodos, esto quiere decir que la información deberia replicarse una vez que el nodo este nuevamente en linea.


En esta prueba podremos observar que sucede en caso de que uno de nuestros nodos se detenga, para ello lo que haremos sera detener mysql en alguno de nuestros nodos, posterior a eso crearemos registros, al levantar nuevamente nuestro nodo caido este deberia poder replicar la información creada

6.1 Detenemos mysql en cualquiera de nuestros nodos

Accedemos a uno de nuestros nodos de la siguiente manera

docker exec -it <id_contenedor> bash

Una vez hayamos accedido ejecutamos el siguiente comando

service mysql stop

6.2 Insertamos registros

Hacer inserciones en cualquiera de los nodos sobrantes (Se pueden realizar desde cualquier nodo), accedemos a otro nodo:

docker exec -it <id_contenedor> bash

Ingresamos a mysql

mysql

Usamos nuestra base de datos

use companydb;

Agregamos registros

INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');
INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');
INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');
INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');
INSERT INTO Companies (CompanyID, Name, Address, Phone, Email) VALUES (NULL, 'Other Company', 'Unit 5699 Box 8173 DPO AP 62802', '+1-635-243-2015x623', '[email protected]');

Para esta prueba, teniendo un servidor detenido realizamos una inserción de 5 registros, la cual se replico hacia nuestro servidor que esta en linea

percona_3_1.png

6.3 Levantamos el nodo faltante

En el nodo caido ejecutamos:

service mysql start

Levantamos nuevamente nuestro nodo y al hacerlo se nos replica la información que se agrego previamente

percona_3_2.png

Levantamos nuevamente nuestro nodo y al hacerlo se nos replica la información que se agrego previamente:

select * from Companies order by CompanyID DESC LIMIT 10 \G

NOTA

Extrabackup tiene una forma de conocer el ultimo hash de los registros insertados, con esto se guiá de que tan sincronizado esta con las otras bases de datos.


7. Levantar un nodo con xtrabackup y unirlo al cluster

En esta practica levantaremos un nuevo nodo con Docker y lo uniremos a nuestro cluster, para ello lo primero que debemos hacer es modificar nuestro archivo docker-compose.yml

6.1 Modificar docker-compose.yml

Agregamos un nuevo servicio llamado mysql-server-4

  mysql-server-4:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-4
    hostname: node-4
    networks:
      custom_network:
        ipv4_address: 172.20.0.6
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql4_data:/var/lib/mysql
    ports:
      - "3311:3306"
    command: bash -c "tail -f /dev/null"

Al final nuestro archivo docker-compose.yml se vera de la siguiente manera

version: '3.8'

services:
  mysql-server-1:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-1
    hostname: node-1
    networks:
      custom_network:
        ipv4_address: 172.20.0.3
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql1_data:/var/lib/mysql
    ports:
      - "3308:3306"  # Mapeo de puerto para acceso externo
    #command: mysqld_safe
    command: bash -c "tail -f /dev/null"
  mysql-server-2:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-2
    hostname: node-2
    networks:
      custom_network:
        ipv4_address: 172.20.0.4
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql2_data:/var/lib/mysql
    ports:
      - "3309:3306"  # Mapeo de puerto para acceso externo
    # command: mysqld_safe
    command: bash -c "tail -f /dev/null"
  mysql-server-3:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-3
    hostname: node-3
    networks:
      custom_network:
        ipv4_address: 172.20.0.5
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql3_data:/var/lib/mysql
    ports:
      - "3310:3306"  # Mapeo de puerto para acceso externo
    # command: mysqld_safe
    command: bash -c "tail -f /dev/null"
  mysql-server-4:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: mysql-server-4
    hostname: node-4
    networks:
      custom_network:
        ipv4_address: 172.20.0.6
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql4_data:/var/lib/mysql
    ports:
      - "3311:3306"
    command: bash -c "tail -f /dev/null"

networks:
  custom_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

6.2 Iniciar el nuevo nodo

Para inciar nuestro nodo ejecutamos el siguiente comando

docker-compose up -d mysql-server-4

De esta manera se levantara el nuevo nodo sin afectar a los que ya tenemos, una vez que se haya inicializado sera necesario realizar la configuración correspondiente

6.3 Configurar nuevo nodo

Una vez que hayamos levantado el nuevo nodo, sera necesario identificar su ID de contenedor, para ello usamos el siguiente comando

docker ps

Identificamos el contenedor por su nombre y accedemos a el

docker exec -it <id_contenedor> bash

Una vez hayamos ingresado, repetimos los puntos del paso Configuración de los nodos, con la diferencia de que al momento de modificar el archivo wsrep.cnf, en la variable wsrep_cluster_address agregaremos la IP de nuestro nuevo nodo, por lo que ahora se veria de la siguiente manera

wsrep_cluster_address=gcomm://172.20.0.3,172.20.0.4,172.20.0.5,172.20.0.6

Una vez hayamos realizado las configuración correspondiente guardamos los cambios realizados al archivo

6.4 Actualizar nodos

Debido a que hemos agregado un nuevo nodo, sera necesario modificar la configuración de nuestros otros nodos para poder agregarlo al cluster, por lo que sera necesario modificar el archivo wsrep.cnf en nuestros nodos.

Primero, debemos detener mysql

service mysql stop

A continuación, modificamos el archivo wsrep.cnf

nano /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf

Modificamos unicamente la variable wsrep_cluster_address y agregamos la IP de nuestro nuevo nodo, al final nos deberia quedar de la siguiente manera

wsrep_cluster_address=gcomm://172.20.0.3,172.20.0.4,172.20.0.5,172.20.0.6

6.5 Iniciar nodos

Iniciamos nuevamente nuestros nodos, comenzando por el nodo 1, en cuyo caso lo haremos de la siguiente manera

/etc/init.d/mysql bootstrap-pxc

Para nuestros otros nodos lo haremos de la siguiente manera

/etc/init.d/mysql start

Es importante iniciar los nodos uno a uno, es decir, esperara a que se inicie uno para seguir con el otro sucesivamente hasta iniciar todos nuestros nodos

6.6 Comprobación

Una vez hayamos iniciado nuestros nodos sera necesario comprobar nuevamente el estado del cluster, para ello en el nodo 1 accedemos a mysql

mysql

Ejecutamos el siguiente comando

show status like 'wsrep%';

En la salida del comando, en la variable wsrep_cluster_size deberiamos observar que ahora dice 4, asi como la variable wsrep_incoming_addresses en la cual ahora podremos observar que se ha añadido la IP de nuestro nuevo nodo

+----------------------------------+-----------------------------------------------------------------+
| wsrep_ist_receive_seqno_end      | 0                                                               |
| wsrep_incoming_addresses         | 172.20.0.3:3306,172.20.0.4:3306,172.20.0.5:3306,172.20.0.6:3306 |
| wsrep_cluster_weight             | 4                                                               |
| wsrep_desync_count               | 0                                                               |
| wsrep_evs_delayed                |                                                                 |
| wsrep_evs_evict_list             |                                                                 |
| wsrep_evs_repl_latency           | 0.000103651/0.000977444/0.00479661/0.00171043/6                 |
| wsrep_evs_state                  | OPERATIONAL                                                     |
| wsrep_gcomm_uuid                 | 9f43bdb5-6975-11ef-8a50-9ab358c7ecaa                            |
| wsrep_gmcast_segment             | 0                                                               |
| wsrep_cluster_conf_id            | 4                                                               |
| wsrep_cluster_size               | 4                                                               |
| wsrep_cluster_state_uuid         | aab1fa2a-6972-11ef-b4c4-5f1c0e026749                            |
| wsrep_cluster_status             | Primary                                                         |
| wsrep_connected                  | ON                                                              |
| wsrep_local_bf_aborts            | 0                                                               |
| wsrep_local_index                | 0                                                               |
| wsrep_provider_name              | Galera                                                          |
| wsrep_provider_vendor            | Codership Oy <info@codership.com>                               |
| wsrep_provider_version           | 3.63(rf47405c)                                                  |
| wsrep_ready                      | ON                                                              |
+----------------------------------+-----------------------------------------------------------------+

Con esto habremos finalizado esta practica de Percona XDB Cluster con Docker.

Al finalizar, nuestro cluster quedaria de la siguiente manera

diagramaDockerCluster2.png

Video Tutorial

Puedes ver el paso a paso en el video de nuestro canal.

Utilidades para el Desarrollo

Debido a que esto se realiza en un entorno de Desarrollo/Pruebas para entender el concepto y funcionamiento de Percona XtradbCluster, brindaremos los siguientes comandos para facilitar la solución de errores:

Logs de Errores de Mysql Percona Cluster:

tail -f /var/log/mysqld.log

Logs de Errores de Xtrabackup (al momento de levantar un nuevo nodo)

tail -f /var/lib/mysql//innobackup.backup.log

Error al inicializar Cluster

Una cosa a tener en cuenta es que si el vagrant se detiene bruscamente (como si se apagaran los servidores) el cluster mostrara un error al volver a levantarse, ya que desconoce que servidor fue el ultimo en detenerse.

image

Teniendo en cuenta esto, podemos levantar el Cluster nuevamente entrando al nodo 1 (nodo principal) y modificando el siguiente archivo:

nano /var/lib/mysql/grastate.dat

Modifica la variable safe_to_bootstrap, de la siguiente forma:

safe_to_bootstrap: 1

image

Con esto ya podremos levantar el cluster nuevamente:

/etc/init.d/mysql bootstrap-pxc

Problemas de Sincronizacion debido a Firewall

Puedes comprobar que los puertos 4444, 4567 y 4568 esten abiertos entre las maquinas virtuales de la siguiente forma:

En el servidor que se unira al cluster (JOINER):

socat - TCP-LISTEN:4444

En el servidor que sera el donante (DONOR): a

echo "hello" | socat - TCP:ip.adr.of.donor:4444

Con esto puedes comprobar si los puertos se encuentran abiertos o tienes inconvenientes con Firewall. El servidor nuevo estará a la escucha de informacion en el puerto designado (en este caso 4444) y el servidor Donante, enviara un "hello" que se imprimira en el donante.

Levantar cluster con un Backup usando Xtrabackup

Debido a que Percona Cluster necesita una tabla en donde almacenar datos de la replicacion y el cluster, se necesita realizar lo siguiente en el nodo que iniciará el cluster. Con el MySQL funcionando ejecuta en la terminal de ubuntu:

mysql_upgrade

Esto deberia mostrar un output parecido a esto:

bd.table1                     OK
bd.table2             OK
bd.table                  OK
...
sys.sys_config                                     OK
Upgrade process completed successfully.
Checking if update is needed.

Puedes comprobar que el cambio funcionío ejecutando lo siguiente:

SHOW GLOBAL VARIABLES LIKE 'wsrep_sync_wait';

Saber si el cluster esta en funcionamiento

Puedes ejecutar la siguiente query:

show global status where variable_name IN ('wsrep_local_state','wsrep_local_state_comment','wsrep_local_commits','wsrep_received','wsrep_cluster_size','wsrep_cluster_status','wsrep_connected','wsrep_ready');

Esto brindará un output como el siguiente:

+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| wsrep_received            | 7       |
| wsrep_local_commits       | 0       |
| wsrep_local_state         | 4       |
| wsrep_local_state_comment | Synced  |
| wsrep_cluster_size        | 3       |
| wsrep_cluster_status      | Primary |
| wsrep_connected           | ON      |
| wsrep_ready               | ON      |
+---------------------------+---------+
8 rows in set (0.00 sec)

Explicacion de cada parametro:

  • wsrep_received: Esta variable indica cuántos eventos de replicación (transacciones) ha recibido el nodo desde los otros nodos del clúster. En este caso, el nodo ha recibido 7 eventos.
  • wsrep_local_commits: Muestra cuántas transacciones locales ha confirmado el nodo en su propia base de datos. En este caso, el nodo no ha hecho ninguna confirmación de transacciones propias, por eso está en 0.
  • wsrep_local_state: Indica el estado del nodo dentro del clúster. El valor 4 corresponde al estado Synced, lo que significa que el nodo está completamente sincronizado y listo para procesar transacciones.
  • wsrep_local_state_comment: Es un comentario en texto del estado del nodo. Como el valor es Synced, confirma que el nodo está sincronizado con el resto del clúster. Mas Info
  • wsrep_cluster_size: Indica el número de nodos activos en el clúster. En este caso, hay 3 nodos activos.
  • wsrep_cluster_status: Muestra el estado del clúster. Primary significa que el clúster está operativo y que los nodos pueden comunicarse y replicar datos correctamente. Este es el estado deseado
  • wsrep_connected: Indica si el nodo está conectado al clúster. ON significa que el nodo está conectado correctamente a los otros nodos.