Posts tagged with “replicación”


Thu 22 Jul

Introducción a MySQL Cluster

MySQL Cluster es una base de datos que como su nombre indica funciona en un Cluster de servidores. Mucha gente confunde terminos y define un conjunto de servidores con replicación como un MySQL Cluster, pero hay que tener en cuenta que son dos conceptos totalmente distintos. MySQL Cluster nos ofrece:

  • Alta disponibilidad
  • Escalabilidad
  • Failover automático
  • Redundancia
  • Alto throughput

La versión actual es la 7.1 y puede descargarse de http://www.mysql.com/products/database/cluster/

Componentes

Un Cluster MySQL está compuesto por los siguientes componentes:

Manager (ndb_mgmd): es un servicio encargado de poner en marcha el cluster, conectar nuevos servidores y ejecutar distintos comandos de administración mediante el CLI ndb_mgm. Una vez que hemos levantado el cluster no es necesario ni un requisito indispensable que esté levantado.

Data Nodes (ndbd): son nodos encargados del almacenamiento de los datos. Se recomiendan al menos dos para disponer de redundancia y alta disponibilidad. Estas serán las máquinas más potentes del cluster, almacenarán los índices en memoria y los datos en memoria o disco. Todos los Data Nodes deben tener el mismo hardware para evitar crear cuellos de botella.

API nodes (mysqld): aunque el más usado sea mysqld, un API node puede ser cualquier aplicación que haciendo uso de la API acceda al cluster. El típico, también conocido como SQL Node, es el demonio mysqld típico (compilado con soporte nbdcluster). De esta forma podremos escribir o leer datos de nuestra BBDD como hemos hecho hasta ahora, mediante comandos SQL.

Se recomienda que cada componente esté instalado en una máquina física distinta.

Funcionamiento interno

Internamente, el funcionamiento del cluster se basa en dos conceptos básicos. Replicación interna síncrona y auto particionado de datos. La primera nos ofrece la redundancia y el segundo nos da la escalabilidad. Importante diferenciarlo de la replicación típica de MySQL (asíncrona). En este caso, hasta que los datos no han sido replicados en los nodos seleccionados no se devuelve el control al usuario, obteniendo de esta forma la consistencia que no tenemos en la replicación asíncrona.

El particionado (PARTITION BY KEY) es también totalmente automático. El cluster se encarga de dividir las tablas en distintas particiones y dividir los datos entre los distintos Data Nodes. Aunque es posible que definamos nuestro propio particionado, no se recomienda. Añades complejidad y posiblemente el rendimiento no sea el esperado.

Replicas

A la hora de configurar nuestro cluster, una de los valores más importantes a tener en cuenta es decidir el número de replicas que tendremos de nuestros datos. No podemos decidir cualquier número, si no que tendremos que seguir unas sencillas reglas. Pongamos por ejemplo que tenemos 4 Data Nodes. En este caso podremos tener 1, 2 y 4 replicas. Esto es, el número de nodos debe poder ser divisible por el numero de replicas. Aún así, no se debería tener una única replica, ya que eso no nos da ningún tipo de alta disponibilidad ya que al caerse un solo nodo perderíamos el acceso a los datos.

Node Groups

MySQL Cluster agrupa automáticamente los Data Nodes en grupos. Esto no está bajo nuestro control ni podemos decidir que nodo está en que grupo, será trabajo del cluster hacer estas agrupaciones. Siguiendo el ejemplo anterior, si tenemos 4 Data Nodes y 2 réplicas, MySQL Cluster nos generará dos Node Groups (4/2=2). Además hay que tener en cuenta que el número de particiones que se harán de nuestros datos siempre será igual al número de Data Nodes.

Por lo tanto, imaginemos que tenemos el N1 y N2 en el grupo 1 (G1) y N3 y N4 en el grupo 2 (G2). A la hora de particionar y repartir los datos es necesario pensar en la alta disponibilidad, por lo que el particionado se hará de la siguiente forma:

G1
N1 = P1 y P2'
N2 = P2 y P1'

G2 N3 = P3 y P4' N4 = P4 y P3'

Siendo PX el número de la partición y PX' una copia de la partición de Backup.

Sabiendo esto, podemos imaginar cuando dispondremos de alta disponibilidad. Mientras al menos uno de los nodos de un grupo esté levantado, el cluster estará online. Por ejemplo se podrían caer N1 y N4 o N3 y N2 y todo seguiría funcionando. Pero una caida de N1 y N2 dejaría el cluster completamente caido.

A mayor número de replicas menos posibilidades de fallo, más escalabe y más throughput :)

Próximamente extenderé el tema de MySQL Cluster con más entradas según vaya profundizando en el estudio de la certificación. La intención será termianr teniendo un mini manual para andar por casa que nos permita dar los primeros pasos.


Sat 12 Jun

Replicación maestro-esclavo en MongoDB

Esta es una entrada cortita, gracias en parte a la extrema facilidad de administrador de nuestra base de datos NoSQL favorita. En esta ocasión vamos a ver como crear una replicación dentre dos sistemas MongoDB, en arquitectura Maestro-Esclavo. Como pasa bastante habitualmente, la arquitectura Maestro-Maestro, a pesar de ser posible, no la recomiendan. Esta, al igual que en MySQL, se basa en el truco de hacer que un esclavo sea al mismo tiempo maestro.

Yo voy a mostrar la opción recomendada, Maestro-Esclavo.

Para ello, lo primero es instalar dos MongoDB en Debian Lenny.

El primero se llamará Maestro con IP 192.168.1.105 y el segundo Esclavo con IP 192.168.1.101.

Arrancamos el maestro indicando que actuará con ese Rol:

debian1:/usr/local/mongodb# bin/mongod --master
Sat Jun 12 16:41:23 Mongo DB : starting : pid = 2158 port = 27017 
dbpath = /data/db/ master = 1 slave = 0  64-bit 
Sat Jun 12 16:41:23 db version v1.4.3, pdfile version 4.5
Sat Jun 12 16:41:23 git version: 47ffbdfd53f46edeb6ff54bbb734783db7abc8ca
Sat Jun 12 16:41:23 sys info: Linux domU-12-31-39-06-79-A1 
2.6.21.7-2.ec2.v1.2.fc8xen #1 SMP Fri Nov 20 17:48:28 EST 2009 x86_64 BOOST_LIB_VERSION=1_41
Sat Jun 12 16:41:23 waiting for connections on port 27017
Sat Jun 12 16:41:23 ******
Sat Jun 12 16:41:23 creating replication oplog of size: 944MB (use --oplogSize to change)
Sat Jun 12 16:41:23 ******
Sat Jun 12 16:41:23 allocating new datafile /data/db/local.ns, filling with zeroes...
Sat Jun 12 16:41:23 done allocating datafile /data/db/local.ns, size: 16MB, took 0.026 secs
Sat Jun 12 16:41:23 allocating new datafile /data/db/local.0, filling with zeroes...
Sat Jun 12 16:41:23 done allocating datafile /data/db/local.0, size: 64MB, took 0.185 secs
Sat Jun 12 16:41:23 allocating new datafile /data/db/local.1, filling with zeroes...

Una vez hecho, arrancamos el Esclavo indicándole por parámetro donde está su Maestro:

debian2:/usr/local/mongodb/bin# ./mongod --slave --source 192.168.1.105:27017
Sat Jun 12 16:42:03 Mongo DB : starting : pid = 2172 port = 27017 
dbpath = /data/db/ master = 0 slave = 1  64-bit 
Sat Jun 12 16:42:03 db version v1.4.3, pdfile version 4.5
Sat Jun 12 16:42:03 git version: 47ffbdfd53f46edeb6ff54bbb734783db7abc8ca
Sat Jun 12 16:42:03 sys info: Linux domU-12-31-39-06-79-A1 
2.6.21.7-2.ec2.v1.2.fc8xen #1 SMP Fri Nov 20 17:48:28 EST 2009 x86_64 BOOST_LIB_VERSION=1_41
Sat Jun 12 16:42:03 waiting for connections on port 27017
Sat Jun 12 16:42:03 web admin interface listening on port 28017
Sat Jun 12 16:42:04 allocating new datafile /data/db/local.ns, filling with zeroes...
Sat Jun 12 16:42:04 done allocating datafile /data/db/local.ns, size: 16MB, took 0.028 secs
Sat Jun 12 16:42:04 allocating new datafile /data/db/local.0, filling with zeroes...
Sat Jun 12 16:42:05 done allocating datafile /data/db/local.0, size: 64MB, took 0.185 secs
Sat Jun 12 16:42:05 building new index on { id: 1 } for local.sources
Sat Jun 12 16:42:05 Buildindex local.sources idxNo:0 { name: "_id", ns: "local.sources", key: { _id: 1 } }
Sat Jun 12 16:42:05 done for 0 records 0secs
Sat Jun 12 16:42:05 repl: from host:192.168.1.105:27017
Sat Jun 12 16:42:05 repl:   applied 1 operations
Sat Jun 12 16:42:05 repl:  end sync_pullOpLog syncedTo: Sat Jun 12 16:42:00 2010 4c139cb8:1

Ya tenemos las dos bases de datos en marcha:

Creamos una nueva base de datos llamada test y añadimos una colección:

> use test
switched to db test
> a = { nombre : "Miguel Angel", apellido : "Nieto" }
{ "nombre" : "Miguel Angel", "apellido" : "Nieto" }
> db.gente.save(a);

Comprobamos que se ha añadido en Maestro:

Comprobamos que se ha añadido en Esclavo:

Y lo buscamos en el Esclavo:

Más facil y rápido imposible :)


Sun 21 Mar

Replicación multi-master y síncrona con Galera

Rocky prefiere la replicación en Access
Rocky prefiere la replicación en Access

La replicación de bases de datos síncronas siempre ha dado algún que otro quebradero de cabeza ya que no es tan facil de implementar como en un principio se puede pensar. Una de las técnicas más usadas para lograrlo es el conocido commit en dos fases. En este modo un nodo llamado el coordinador envía un mensaje con una consulta a un commit. Los participantes, en función de si pueden o no aplicar la transacción, mandan una respuesta de fallo o acierto al coordinador. Si alguno manda fallo, la transacción se cancela (rollback) pero si todos dan su visto bueno esta se aplica globalmente (commit).

Esto a simple vista ya nos muestra un problema de base, la gran cantidad de bloqueos que se tienen que aplicar a las tablas y/o filas mientras se hacen las comprobaciones, degradando en gran medida el rendimiento global de nuestro cluster de replicación. Por otro lado si un nodo participante se quedase bloqueado, el coordinador tendría que esperar un timeout para después abortar la transacción. O peor aún, si durante una comprobación el coordinador se cae, los nodos participantes se quedarían bloqueados esperando la respuesta del coordinador sobre que hacer con la transacción.

Por estas y otras razones, sistemas de bases de datos como MySQL o PostgreSQL implementan replicaciones asíncronas.

Para dar una solución a este problema ha nacido la empresa Codership, desarrolladora de un sistema de replicación basado en certificación llamado Galera.

Viendo el gráfico podemos resumir el funcionamiento de Galera:

1- Galera, mediante su API, extrae la información referente a los datos a modificar.

2- Si la transacción pasa el proceso de certificado, se commitea. Si no, se hace rollback.

3- Si la replicación es correcta, se comunica al resto de nodos a través del grupo de comunicación, que es una línea (TCP) a través de la cual se comunican los diferentes nodos.

4- Cada nodo recibirá la transacción y lo pasará también por la prueba de certificación. Si esta es correcta se aplica y si no rollback.

El proceso está muy resumido, internamente la API WSREP (Write Set Replication) es mucho más compleja, pero solo es necesario conocerla a fondo en caso de querer programar contra ella. Para nuestro ejemplo es más que suficiente con tener una visión global.

Una de las primeras cosas que se deben tener en cuenta es que el control de concurrencias es Optimista. Dos nodos pueden estar modificando las mismas filas en transacciones diferentes, pero solo una de ellas será la "ganadora". En ese caso el cluster Galera cancelará la fallida y enviará un mensaje de error, Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK). Además, en caso de que producirse este problema, se puede configurar Galera para reintentar automáticamente el commit de la transacción con wsrep_retry_autocommit=On

Para que Galera funcione, el engine o la base de datos debe ser compatible con la API WSREP, por lo tanto es necesario una modificación del código fuente. La primera en recibir dichas modificaciones y que según Codership está preparada para la producción es InnoDB, así que será la que probaremos en este post :) Dicen que están trabajando en importar los cambios a MariaDB y PostgreSQL.

Para la instalación haremos uso de 3 máquinas debian. El ellas descargaremos el siguiente fichero:

http://launchpad.net/codership-mysql/0.7/0.7.3/+download/mysql-5.1.43-galera-0.7.3-i686.tgz

Este incluye la versión 5.1.43 de MySQL con los parches de compatibilidad con WSREP necesarios. Una vez descomprimido arrancamos el primer nodo:

nodo1:~/mysql-5.1.43-galera-0.7.3-i686# ./mysql-galera -g gcomm:// start
Starting mysqld instance with data dir /root/mysql-5.1.39-galera-0.7-i686/mysql/var and 
listening at port 3306 and socket /root/mysql-5.1.39-galera-0.7-i686/mysql/var/mysqld.sock. Done (PID:2226)
Waiting for wsrep_ready. Done

Le hemos indicado que queremos empezar un cluster vacio (ya que no indicamos ninguna IP). Esto es así porque no tiene ningún otro nodo al que conectarse. En cambio, el resto de los nodos se tendrán que arrancar conectandose a este:

nodo2:~/mysql-5.1.43-galera-0.7.3-i686# ./mysql-galera -g gcomm://192.168.1.106 start
Starting mysqld instance with data dir /root/mysql-5.1.39-galera-0.7-i686/mysql/var and
listening at port 3306 and socket /root/mysql-5.1.39-galera-0.7-i686/mysql/var/mysqld.sock. Done (PID:2376)
Waiting for wsrep_ready........ Done

nodo3:~/mysql-5.1.43-galera-0.7.3-i686# ./mysql-galera -g gcomm://192.168.1.106 start
Starting mysqld instance with data dir /root/mysql-5.1.39-galera-0.7-i686/mysql/var and 
listening at port 3306 and socket /root/mysql-5.1.39-galera-0.7-i686/mysql/var/mysqld.sock. Done (PID:2376)
Waiting for wsrep_ready........ Done

¡Listo! Ya tenemos nuestro cluster en marcha. Ahora solo queda entrar en MySQL y crear una base de datos :)

nodo1:~# mysql -u root -prootpass -S /root/mysql-5.1.43-galera-0.7.3-i686/mysql/var/mysqld.sock
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.1.43 wsrep_0.7
nodo1> create database pruebas;
Query OK, 1 row affected (0.04 sec)
nodo1> use pruebas;
Database changed
nodo1> create table t (i int) engine=innodb;
Query OK, 0 rows affected (0.08 sec)

Si nos vamos al nodo2, veremos que tenemos la tabla creada:

nodo2> use pruebas;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
nodo2> show tables;
+-------------------+
| Tables_in_pruebas |
+-------------------+
| t                 | 
+-------------------+
1 row in set (0.01 sec)

Para comprobar el correcto funcionamiento de la replicación maestro maestro, metemos un dato en cada nodo. El nodo uno inserta "1", el dos "2"...

nodo1> insert into t VALUES(1);
nodo2> insert into t VALUES(2);
nodo3> insert into t VALUES(3);
nodo3> select * from t;
+------+
| i    |
+------+
|    1 | 
|    2 | 
|    3 | 
+------+
3 rows in set (0.01 sec)

¡Yeah! Funciona :)

Pero, ¿que pasa si uno de los nodos se cae?

Este sistema de replicación no usa los logs binarios, por lo tanto, a la hora de levantarse un nodo caido el modo de resincronización es ligeramente diferente. Cuando el nodo se reconecta, de los activos se selecciona uno que será el encargado de sincronizar los datos. Dicha sincronización se hace mediante mysqldump, de forma que el nodo activo hará un dump de los datos y los restaurará en el nuevo nodo entrante. Este proceso, como puedes imaginar, se hará más lento y consumirá más recursos contra más grande sean las tablas. En este momento (versión 0.7) galera no soporta otro modo de sincronización, pero se espera que en futuras versiones disponga de compatibilidad con Xtrabackup, LVM y InnoDB HotBackup. Este mismo sistema se usa cada vez que se agrega un nuevo nodo al cluster.

La teoría está bien, pero a mi me ha fallado. Después de parar el nodo3 y escribir datos en el nodo1 y nodo2, los datos no se han resincronizado. También puede ser fallo mio, no he investigado mucho. Acepto críticas y correcciones :P

Respecto a los auto incrementales, no es necesario preocuparse. Galera se encarga de gestionarlos gracias a la opción (que viene activada por defecto) wsrep_auto_increment_control.

En resumen, una solución completa para disponer de replicación multi-master y síncrona y aún en las primeras fases de desarrollo, con muchísimas posibilidades a futuro. Alta disponibilidad y escalabilidad con un sistema muy fácil de implementar y administrar. De momento solo es compatible con InnoDB.

Gracias a Seppo Jaakola por darme permiso para usar imágenes de sus diapositivas en este post.

Las imágenes tienen copyright de CoderShip Puedes conseguir las diapositivas originales en http://forge.mysql.com/w/images/2/20/MySQLGalera.pdf


Sat 27 Feb

Timeout en la replicación del esclavo

Otro de los problemas que nos podemos encontrar en una replicación es la red. Si esta está congestionada o con desconexiones intermitentes podemos terminar teniendo graves como lag entre maestro y esclavos o la parada completa del esclavo. Últimamente me he encontrado con este problema en algunas instalaciones de replicación y los síntomas no ayudaban a conocer la causa. Conectándome al esclavo y ejecutando el típico show slave status no encontraba la razón por la cual la replicación se habia parado. Los dos procesos, IO y SQL estaban funcionando y Seconds Behind Master indicaba 0.

Cuando el esclavo pide los últimos logs al maestro, se queda esperando un tiempo para recibir la respuesta hasta que al final da timeout. Eso es un comportamiento normal, lo que ya no es normal es el valor por defecto de dicha espera, 3600 segundos, ¡una hora! El esclavo se quedará en el estado:

Slave_IO_State: Waiting for master to send event

Los valores que tendremos que modificar en nuestra configuración son:

slave-net-timeout = 30
master-connect-retry = 60

De esta forma, el esclavo se quedará esperando a los eventos del maestro 30 segundos y después dará timeout y se intentará reconectar. Si por alguna razón no puede conectarse al maestro, lo seguirá reintentando cada 60 segundos (valor por defecto).

Como bien dice Daniel Schneller, no te creas todo lo que te dice el show slave status :)

· Tags: ,

Thu 25 Feb

Nuevas trasparencias: administración avanzada de MySQL

Aquí os pongo unas nuevas transparencias de un curso que he dado recientemente. Abarca gran cantidad de temas relacionados con la administración de nuestra base de datos favorita :)

  • Instalación
  • Engines
  • Optimización de consultas
  • Optimización de tablas
  • Optimización del servicio
  • Usuarios y permisos
  • Replicación
  • Alta disponibilidad
  • Backup
  • etc. :)

Espero que os guste y os sea de utilidad. Cualquier sugerencia o crítica es bienvenida. Si hay algún fallo comentádmelo para solucionarlo lo antes posible.

¡Gracias a todos!


Sun 21 Feb

Los peligros de binlog-do-db en la replicación

A la hora de configurar una replicación, el punto más importante es aquel en el que decidimos que replicar. Y para ello debemos seleccionar que guardar en el log binario. Tenemos muchas opciones, pero hay algunas que debemos evitar:

  • binlog-do-db
  • binlog-ignore-db
  • replicate-do-db
  • replicate-ignore-db

Para ver la razón, nada mejor que un ejemplo practico de un sistema master-master.

El servidor A tiene dos bases de datos, VIDA y MUERTE. VIDA será la que se replicará al segundo maestro.

El servidor B solo tiene la base de datos VIDA.

Servidor A:

server-id=101
log-bin=mysql-bin
log-slave-updates
replicate-same-server-id=0
auto_increment_increment=2
auto_increment_offset=1
binlog-do-db=vida

Servidor B:

server-id=102
log-bin=mysql-bin
log-slave-updates
replicate-same-server-id=0
auto_increment_increment=2
auto_increment_offset=2
binlog-do-db=vida

Ejecutamos en el servidor A:

node1 [localhost] {msandbox} ((none)) > insert into vida.t values(10);
Query OK, 1 row affected (0.00 sec)
node1 [localhost] {msandbox} ((none)) > use vida;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
node1 [localhost] {msandbox} (vida) > create table muerte.t (i int);
Query OK, 0 rows affected (0.00 sec)

Ya nos hemos cargado la replicación por dos sitios. El valor 10 no se ha insertado en la tabla t de VIDA y por otro lado, el servidor B intentará crear la tabla t en la base de datos MUERTE (que en realidad no tiene).

Last_SQL_Error: Error 'Unknown database 'muerte'' on query. Default database: 'vida'. Query: 'create table muerte.t (i int)'

¿Y cual es la razón de este comportamiento si le hemos indicado que queremos solo la replicación de VIDA? Respuesta corta, binlog-do-db no hace lo que nosotros creemos :) Bien... ¿y la respuesta larga?

Los 4 parámetros para el log binario que hemos visto antes, se aplican si son la base de datos por defecto, esto es, si hemos hecho un USE VIDA. Una vez que convertimos mediante ese comando VIDA en la base de datos por defecto, todos los comandos que ejecutemos se logearán en el log binario.

Por lo tanto, si vemos los comandos SQL ejecutados anteriormente se puede entender la razón por la cual hemos roto la replicación:

  • Hemos realizado un insert en la tabla t de VIDA sin que esta sea nuestra base de datos por defecto. MAL! No se logeará, el esclavo no recibirá las actualizaciones.
  • Hemos creado una tabla t en MUERTE siendo VIDA nuestra base de datos por defecto. MAL! La sentencia se logeará y enviará al esclavo. Cuando este intente replicarla fallará por no tener dicha base de datos.

Ahora sabemos cual es el problema, hay que saber la solución. Y en esta ocasión tenemos dos:

  • Hacer uso de replicate-wild-do-table=VIDA.% Esto logeará todo lo que modifique la base de datos VIDA, sea nuestra base de datos por defecto o no.
  • Activar la replicación en base a filas (MySQL 5.1)

Este es un fallo muy común, por lo que os recomiendo revisar las configuraciones de vuestras replicaciones ante posibles fallos de configuración.


Sat 6 Feb

Replicación semi-síncrona con MySQL 5.5

El problema más grave de la replicación en MySQL es su funcionamiento asíncrono. Cuando se añade o modifica algún dato en el master, este commitea los datos en local sin esperar a que los slaves lo hagan. Esto normalmente no supone un gran problema, ya que la replicación, si no hay ningún problema con índices o con la red, es casi instantanea. Pero aún así se pueden dar algunos problemas:

  • El master commitea los datos sin esperar. Durante un tiempo, aunque pequeño, master y slave tendrán datos diferentes. Contra mas alto sea el valor seconds behind master, mayor será el problema.

  • El master no comprueba que los esclavos hayan recibido los binlogs con los cambios.

  • El master no comprueba que los esclavos hayan hecho efectivos los cambios en sus bases de datos.

Este es un problema solucionado en MySQL Cluster, donde la replicación es totalmente síncrona. Los nodos no commitean los cambios hasta que estos se hayan escrito correctamente en los node groups que correspondan. Si esto no es así, se hace un rollback. Pero en la replicación normal no tenemos tanta suerte.

Una de las novedades de MySQL 5.5 viene a medio solventar el problema. Con esta nueva versión de desarrollo disponemos de replicación semi-síncrona. Algo es algo :)

Su funcionamiento es simple. Ahora el master antes de hacer commit espera a que al menos uno de los slaves reciba los logs binarios. Pero aún así hay que tener en cuenta lo siguiente:

  • El master solamente comprueba que un slave haya recibido los logs, pero no que si lo ha podido escribir correctamente o no. Esto es, no importa el estado del SQL Thread.

  • Podemos tener 1000 slaves, pero con que solo uno reciba los logs ya se da por bueno.

  • Si pasado un tiempo ninguno de los esclavos recibe los logs, el master cambia a modo asíncrono commiteando los cambios.

Vamos a hacer unas pruebas. Necesitaremos dos cosas, MySQL 5.5 y sandbox :) Creamos un entorno de replicación con un master y dos slaves:

punisher@shyris:~$ make_replication_sandbox --how_many_slaves=2 
/home/punisher/MySQL/mysql-5.5.1-m2-linux-x86_64-glibc23.tar.gz 
installing and starting master
installing slave 1
installing slave 2
starting slave 1
.. sandbox server started
starting slave 2
. sandbox server started
initializing slave 1
initializing slave 2

Una vez hecho, debemos cargar el plugin que nos permite hacer uso de la replicación semi-síncrona en todos los hosts:

master [localhost] {msandbox} ((none)) > INSTALL PLUGIN rpl_semi_sync_master
SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.00 sec)
slave1 [localhost] {msandbox} ((none)) > INSTALL PLUGIN rpl_semi_sync_slave
SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)
slave2 [localhost] {msandbox} ((none)) > INSTALL PLUGIN rpl_semi_sync_slave
SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)

A continuación, debemos habilitar su uso en los ficheros de configuración:

Master:
rpl_semi_sync_master_enabled=1;
Slaves:
rpl_semi_sync_slave_enabled=1;

Reiniciamos mysql y ya lo tenemos :) Creamos una base de datos llamada prueba y comprobamos si al menos un slave ha recibido el binlog:

master [localhost] {msandbox} ((none)) > create database pruebas;
Query OK, 1 row affected (0.00 sec)
master [localhost] {msandbox} ((none)) > SHOW STATUS LIKE 'Rpl_semi_sync%tx';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_no_tx  | 0     |
| Rpl_semi_sync_master_yes_tx | 1     |
+-----------------------------+-------+
2 rows in set (0.00 sec)

Rpl_semi_sync_master_yes_tx es el número de queries correctamente replicadas. Rpl_semi_sync_master_no_tx es el número de queries que no se han replicado.

Hay que tener en cuenta, que estamos hablando de IO no de SQL. Para comprobarlo, paramos el SQL thread en los dos nodos:

slave1 [localhost] {msandbox} ((none)) > STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.00 sec)
slave2 [localhost] {msandbox} ((none)) > STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.00 sec)

Y a continuación insertamos un dato en el master:

master [localhost] {msandbox} (pruebas) > create table t(i int(10));
Query OK, 0 rows affected (0.00 sec)
master [localhost] {msandbox} (pruebas) > SHOW STATUS LIKE 'Rpl_semi_sync%tx';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_no_tx  | 0     |
| Rpl_semi_sync_master_yes_tx | 2     |
+-----------------------------+-------+
2 rows in set (0.00 sec)

Los slaves han recibido los datos, eso es suficiente para el master y se da por bueno. Ahora vamos a parar el IO Thread:

slave1 [localhost] {msandbox} ((none)) > STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
slave2 [localhost] {msandbox} ((none)) > STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)

Y volvemos a meter datos en el master:

master [localhost] {msandbox} (pruebas) > create table z(i int(10));
Query OK, 0 rows affected (10.00 sec)
master [localhost] {msandbox} (pruebas) > SHOW STATUS LIKE 'Rpl_semi_sync%tx';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_no_tx  | 1     |
| Rpl_semi_sync_master_yes_tx | 2     |
+-----------------------------+-------+
2 rows in set (0.00 sec)

La query ha tardado 10 segundos en commitearse. Si durante esos 10 segundos ninguno de los slaves ha recibido los binlogs, el master hace commit y se cuenta como una query no sincronizada.