Configuración MySQL Master Slave

1 febrero 2013 at 20:42 by Adrián Pérez

Cloud ComputingÉste es un post que he tenido en borrador durante varios meses, por la pereza de acabar de pulirlo. Por fín, me ha coincidido otra configuración de MySQL Máster-Slave (esta vez basada en un entorno CentOS 6.3 con Percona Server 5.5), y he aprovechado para, a la vez que seguía los pasos, acabar de documentar el proceso.

Una de las posibilidades que nos ofrece MySQL (o Percona), es la de montar un entorno en el que se tienen varios servidores, cada uno con una réplica de las bases de datos. De esta manera, el servidor con el rol de máster, es el único que permite lecturas y escrituras, mientras que el resto de servidores, con el rol de slaves, únicamente permiten lecturas, y se encargan de actualizar sus datos con las modificaciones que reciben del master.

Está claro que este tipo de entornos mejora el rendimiento de cualquier aplicación, al repartir la carga de trabajo de la base de datos entre varios servidores. Además, se puede usar un balanceador de carga para los slaves, de manera que podamos incluir más slaves según lo necesitemos.

Partimos de un entorno con MySQL Server instalado en nuestros servidores (vamos a usar un servidor como Master y otro como Slave, a modo de ejemplo). Los MySQL Servers se han iniciado (creando así las tablas de sistema) y pueden tener tuneadas o no, sus configuraciones. Sin embargo, en el ejemplo, no hay bases de datos adicionales, más allá de las que genera el propio sistema al iniciar el servidor. NOTA: No pasaría nada si el master tuviera otras bases de datos, pero lo importante es que los slaves no tengan otras bases de datos, a ser posible, puesto que si algún slave ya tuviera una base de datos también existente en el master, tendríamos problemas si los datos difirieran.

PASO 1 Master - Configuración

El primer paso, será modificar la configuración del master, para incluir el apartado referente a la replicación. Para ello, modificaremos su fichero /etc/my.cnf (sería recomendable hacer un backup del fichero, por si las moscas) y añadiremos lo siguiente, al final del apartado [mysqld]:

[mysqld]
...
# MASTER-SLAVE #
server-id=1
log-bin=mysql-bin
binlog_format=mixed
sync_binlog=1
max-binlog-size=500M
expire_logs_days=4
innodb_flush_log_at_trx_commit=1

Si ya se había modificado el fichero my.cnf, será importante revisar que no se haya declarado anteriormente alguno de estos parámetros.

PASO 2 SLAVE - Configuración

A continuación, pasaremos a configurar el slave. Hay dos métodos para hacerlo.

2.1. Primer método. CHANGE MASTER TO

El primer método (y recomendado) es usar el comando CHANGE MASTER TO en el slave. La sintaxis es la siguiente:

CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
MASTER_USER=<user>, MASTER_PASSWORD=<password> ;

Por ejemplo:

CHANGE MASTER TO MASTER_HOST='192.168.2.175', MASTER_PORT=3306,
MASTER_USER='replication', MASTER_PASSWORD='slavePass';

Queda claro que se necesitará indicar lo siguiente:

  • La IP del master, con la variable "master-host", así como el puerto (por defecto el 3306).
  • Las credenciales del usuario mysql, que se usará para la replicación, mediante "master-user" y "master-password". Este usuario lo daremos de alta en unos momentos.

Por precaución, en un entorno con múltiples slaves, sí que he configurado en el my.cnf de cada slave, el parámetro "server-id" para que cada slave tenga un server-id diferente y que no haya problemas con la replicación.

2.2. Segundo método. my.cnf

El segundo método, es modificar, también la configuración del slave, en el fichero /etc/my.cnf, bajo el apartado [mysqld]. Hay que tener en cuenta que el server-id debe ser diferente del usado para el master.

[mysqld]
...
# MASTER-SLAVE #
server-id=2
relay-log=mysqld-relay-bin
max-relay-log-size=500M
relay_log_purge=1
master-host = 192.168.2.175
master-user = replication
master-password = slavePass
master-port = 3306

El problema que tiene este segundo método, es que el slave creará un fichero master.info, que será el encargado de mantener esta información, aunque se realicen cambios en las secciones referentes al master-slave en el my.cnf del slave. Si se quisieran hacer modificaciones, habiendo usado este segundo método, se debería apagar el servidor slave, eliminar el fichero master.info, y reiniciar el slave.

PASO 3 - Reiniciar ambos mysqld

/etc/init.d/mysqld restart

PASO 4 - MASTER - Crear usuario

Tal y como hemos visto en el paso 2, se necesitará un usuario mysql para la replicación. En este paso, daremos de alta al usuario en el master, únicamente.

mysql> GRANT REPLICATION SLAVE ON *.* to 'replication'@'%' IDENTIFIED BY 'slave';
mysql> FLUSH PRIVILEGES;
mysql> GRANT RELOAD ON *.* TO 'replication'@'%';
mysql> GRANT SUPER ON *.* TO 'replication'@'%';
mysql> FLUSH PRIVILEGES;

PASO 5 - MASTER - Backup datos

A partir de aquí, lo que quedaría sería pasar los datos al slave, para que tanto master como slave tengan los mismos datos, y acto seguido iniciar la replicación. Para ello, podemos hacer un backup, en el master, de la base de datos a replicar, para posteriormente restaurarla en el slave, y ahí iniciar la replicación.

De nuevo, hay varios métodos para realizar e, backup, desde el habitual mysqldump, hasta el uso de herramientas como XtraBackup de Percona, que permite realizar backups en caliente sin bloquear.

5.1. Primer método. XtraBackup

Si se puede, se recomienda usar XtraBackup para no bloquear las tablas. Además, XtraBackup permite realizar backups incrementales, que nos pueden venir bien, aunque tiene bastantes requisitos y no siempre se pueden usar sus funcionalidades. Si no, siempre se puede ir al método tradicional, con mysqldump, explicado a continuación.

5.2. Segundo método. MySQLDump

Si se prefiere usar mysqldump, en el master, haríamos lo siguiente:

mysql> FLUSH TABLES;
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW MASTER STATUS;

$ mysqldump -u root -p --all-databases --master-data > master.sql
mysql> UNLOCK TABLES;

NOTA: En el ejemplo se ha usado un "--all-databases" pero se podría haber hecho el backup de

PASO 6 - SLAVE - Recovery backup

Una vez tengamos el backup, deberemos restaurarlo en el/los slave/s. A continuación se describe cómo restaurar un backup hecho con mysqldump.

mysql> slave stop;
mysql -u root -p < master.sql
/etc/init.d/mysqld restart
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS\G

NOTA: A partir de ahora, todo lo que se cree/modifique en el master, se replicará al slave. No hará falta volver a ejecutar un "start slave" al inciar el mysqld, incluso si el mysqld se para y posteriormente se incia, no hará falta iniciar ni el master ni el slave de nuevo, ya que se iniciarán automáticamente.

Errores

No siempre todo puede ir bien, y es posible que nos hayamos equivocado en algún punto, o que el proceso que hayamos seguido incluya algún paso extra, si por ejemplo, estamos aprovechando para migrar un entorno MySQL a nuevos servidores, que harán de Master-Slave. En cualquier caso, si nos encontramos con algún error al iniciar los slaves, tras haber restaurado el dump del master en los slaves, siempre podemos forzar la resincronización.

Para ello haremos:

  • En el master, ejecutaremos un show master status, lo cual nos devolverá el fichero de bin log y la posición en la que está.

mysql> show master status;
+------------------+-----------+--------------+------------------+
| File             | Position  | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+-----------+--------------+------------------+
| mysql-bin.000060 | 315815204 |              |                  |
+------------------+-----------+--------------+------------------+
1 row in set (0.00 sec)

  • En los slaves, los resetearemos y los forzaremos a apuntar al mismo fichero y posición de logs que el master, para que empiecen a sincronizar desde ahí:

mysql> stop slave;
Query OK, 0 rows affected (0.04 sec)
mysql> RESET SLAVE;
Query OK, 0 rows affected (0.14 sec)
mysql> CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000060', MASTER_LOG_POS=315815204;
Query OK, 0 rows affected (0.31 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

PASO 7- CHECKEOS

Llegados a este punto, ya deberíamos tener la replicación Master-Slave funcionando. Una buena forma de testearlo, es creando una nueva tabla en el master, y realizando varios inserts, updates y deletes, para ver cómo se replican en el slave. En el siguiente enlace hay un paso a paso de cómo hacer este tipo de testeos: http://systemadmin.es/2010/03/como-montar-replicacion-en-master-slave-con-mysql

PASO 8 - USO

El uso de un entorno master-slave dependerá del Framework que se esté usando. Si se tienen varios slaves, se podrá configurar un load balancer para que de cara al código, únicamente tengamos un slave, que repartirá las peticiones entre los diferentes slaves.

A continuación algunos enlaces sobre el uso de un entorno Master-Slave:

  1. http://zend-framework-community.634137.n4.nabble.com/Best-practice-for-Master-Slave-Db-w-ZF-td660775.html
  2. http://solarphp.com/blog/read/19-adapter-for-master-slave-my-sql-setups

NOTAS

Escrituras en Slaves

Aunque los slaves estén pensados únicamente para lecturas, nada impide hacer una escritura. Si se hiciera una escritura en un campo de un slave, ese campo podría dejarse de sincronizarse con el master dependiendo del tipo de replicación usada, aunque a posteriori al master se le haga un update de ese campo para forzar la replicación a los slaves. Así pues, para recuperar la sincronización deberemos actualizar el campo del slave que hemos modificado, para que tenga el mismo valor que el master. Hecho eso, ya las actualizaciones en el master que afecten a ese campo, se replicarán en el slave.

Reincio seguro de un Slave (Fuente)

Pasos para reiniciar un mysqld en un Slave, de forma segura:

  • Sacar al slave del Load Balancer
  • in mysql client do: STOP SLAVE;
  • in mysql client do: FLUSH TABLES;
  • in command line do: /etc/init.d/mysql stop
  • in command line do: /etc/init.d/mysql start
  • in mysql client do: START SLAVE;
  • in mysql client do: SHOW SLAVE STATUS\G
  • Meter de nuevo al slave en el Load Balancer

Resincronizar de nuevo un Slave con un Master

El proceso está descrito en StackOverflow, "How to re-sync the Mysql DB if Master and slave have different database incase of Mysql replication?".

RESUMEN

- Master slave funciona bien en cuanto a replicación de datos.
- Perfecto para dividir las lecturas de las escrituras, las cuales añaden importantes tiempos de espera si coinciden atacando a una misma tabla.
- En estos entornos, se suele configurar un balanceador para los slaves. Así por código las lecturas van al balanceador, que es el encargado de distribuirlas. El balanceador sería un punto de fallo al no estar replicado. El escalado horizontal de la solución, se haría añadiendo servers al balanceador.
- Mediante heartbeat se podría controlar la disponibilidad de los servers
- Si se quiere montar un entorno MySQL Master-Slave, se recomienda pensar en la posibilidad de usar Percona, un fork de MySQL que asegura ofrecer mayor rendimiento y viene con prevención de errores ante fallos de replicación (muy comunes en este tipo de entornos).
-Solar's MysqlReplicated adapter, promete encargarse él de enviar las lecturas y escrituras allá donde toquen, sin necesidad de hacerlo por código (no se ha testeado).
- El master es un punto de fallo. Si cae, cae y nos quedamos sin poder escribir. Hay soluciones no nativas de MySQL para pasarle el rol de master a otro (como MMM Multi-Master Replication Manager for MySQL), y soluciones nativas (http://www.howtoforge.com/mysql_master_master_replication). Ninguna solución parece ser 100% efectiva y puede haver inconsistencia de datos, o que un slave no se reenganche tras una caída. En estos casos hay que volver a sincronizar el slave o incluso volver a backupear la bbdd del master para machacarla en ese slave.

 

LINKS

http://systemadmin.es/2010/03/como-montar-replicacion-en-master-slave-con-mysql

http://www.howtoforge.com/mysql_master_master_replication

http://www.webdeveloperjuice.com/2010/02/15/3-jump-steps-to-configure-master-slave-replication-in-mysql/

 

Flickr! Foto por Moyan_Brenn