enchufado.com RSS 2.0 Feed http://enchufado.com/ Feed rss 2.0 del blog enchufado.com es Infiniband en Debian GNU/Linux Wheezy http://enchufado.com/post.php?ID=368 http://enchufado.com/post.php?ID=368 Mon, 14 Apr 2014 00:30:46 +0200Los motivos de la elección de Infiniband por encima de otras opciones pueden ser la alta tasa de transferencia (10, 20 o incluso más Gbps), la baja latencia, el bajo precio si nos decidimos por hardware de segunda mano (comparado p.ej. con 10GbE) y la posibilidad de hacerlo funcionar con el protocolo ip (IPoIB / IP over Infiniband). Algún que otro inconveniente puede ser que la rigidez de los cables puede complicar la instalación y que no hay instrucciones claras -o no las supe encontrar- de cómo echarlo a andar.

Así pues, vamos al lio. Las tarjetas que cayeron en nuestras manos fueron unas Mellanox MT25418.

  1. La pinchamos en el servidor y tendríamos que verla:
  2. # lspci
    07:00.0 InfiniBand: Mellanox Technologies MT25418 [ConnectX VPI PCIe 2.0 2.5GT/s - IB DDR / 10GigE] (rev a0)
    
    # dmesg | grep -i mlx4
    [    4.500835] mlx4_core: Mellanox ConnectX core driver v1.0 (July 14, 2011)
    [    4.500839] mlx4_core: Initializing 0000:07:00.0
    [    4.500889] mlx4_core 0000:07:00.0: setting latency timer to 64
    [    6.492856] mlx4_core 0000:07:00.0: irq 84 for MSI/MSI-X
    [    6.492864] mlx4_core 0000:07:00.0: irq 85 for MSI/MSI-X
    [    6.492873] mlx4_core 0000:07:00.0: irq 86 for MSI/MSI-X
    [    6.492879] mlx4_core 0000:07:00.0: irq 87 for MSI/MSI-X
    [    6.492887] mlx4_core 0000:07:00.0: irq 88 for MSI/MSI-X
    [    6.492894] mlx4_core 0000:07:00.0: irq 89 for MSI/MSI-X
    [    6.492901] mlx4_core 0000:07:00.0: irq 90 for MSI/MSI-X
    [    6.492907] mlx4_core 0000:07:00.0: irq 91 for MSI/MSI-X
    [    6.492914] mlx4_core 0000:07:00.0: irq 92 for MSI/MSI-X
    [    6.492921] mlx4_core 0000:07:00.0: irq 93 for MSI/MSI-X
    [    6.492928] mlx4_core 0000:07:00.0: irq 94 for MSI/MSI-X
    [    6.492935] mlx4_core 0000:07:00.0: irq 95 for MSI/MSI-X
    [    6.492942] mlx4_core 0000:07:00.0: irq 96 for MSI/MSI-X
    [    6.492949] mlx4_core 0000:07:00.0: irq 97 for MSI/MSI-X
    
    # lsmod | grep mlx
    mlx4_core              78702  0
    
  3. Como vemos ya carga algún módulo, pero no es suficiente, así que cargamos otros necesarios:
  4. # modprobe ib_ipoib mlx4_en mlx4_ib
    
  5. Si no trabajamos con un switch Infiniband, también necesitamos instalar el paquete opensm para tener link ACTIVE (en el siguiente punto vemos cómo poder consultarlo):
  6. # aptitude install opensm
    
  7. Podemos obtener un poco de información de la tarjeta/interfície de distintas maneras:
  8. # Bien consultando /sys, p.ej. consultando el modo de conexión Infiniband:
    # cat /sys/class/net/ib0/mode 
    datagram
    # cat /sys/class/net/ib1/mode 
    datagram
    
    # Bien instalando el siguiente paquete:
    # apt-get install infiniband-diags
    # ibstat
    ibwarn: [8624] umad_init: can't read ABI version from /sys/class/infiniband_mad/abi_version (No such file or directory): is ib_umad module loaded?
    ibpanic: [8624] main: can't init UMAD library: (No such file or directory)
    
    # En éste caso nos falta cargar otro módulo:
    # modprobe ib_umad
    
    # Ahora sí:
    # ibstat
    CA 'mlx4_0'
     CA type: MT25418
     Number of ports: 2
     Firmware version: 2.6.0
     Hardware version: a0
     Node GUID: 0x001a4bffff0cf264
     System image GUID: 0x001a4bffff0cf267
     Port 1:
      State: Active ('Initializing' si no está instalado opensm!)
      Physical state: LinkUp
      Rate: 20
      Base lid: 2 ('0' si no está instalado opensm!)
      LMC: 0
      SM lid: 1 ('0' si no está instalado opensm!)
      Capability mask: 0x0251086a ('0x02510868' si no está instalado opensm!)
      Port GUID: 0x001a4bffff0cf265
     Port 2:
      State: Down
      Physical state: Polling
      Rate: 8
      Base lid: 0
      LMC: 0
      SM lid: 0
      Capability mask: 0x02510868
      Port GUID: 0x001a4bffff0cf266
    
    # ibhosts
    Ca	: 0x001a4bffff0c22b8 ports 2 "MT25408 ConnectX Mellanox Technologies"
    Ca	: 0x001a4bffff0cf264 ports 2 "MT25408 ConnectX Mellanox Technologies"
    
  9. También podemos instalar un poco de literatura (documentación) acerca del tema:
  10. # apt-get install ofed-docs
    # dpkg -S ofed-docs
    ofed-docs: /usr/share/doc/ofed-docs/DEBIAN-HOWTO/infiniband-howto.txt.gz
    ofed-docs: /usr/share/doc/ofed-docs/DEBIAN-HOWTO/infiniband-howto-6.html
    ofed-docs: /usr/share/doc/ofed-docs/mpi-selector_release_notes.txt
    ofed-docs: /usr/share/doc/ofed-docs/copyright
    (...)
    # zless /usr/share/doc/ofed-docs/ipoib_release_notes.txt.gz
    

    De la misma, sacamos un poco de tunning con sysctl, si bien aparentmente no marca ninguna diferencia:

    # sysctl -p
    net.ipv4.tcp_timestamps = 0
    net.ipv4.tcp_sack = 0
    net.core.netdev_max_backlog = 250000
    net.core.rmem_max = 16777216
    net.core.wmem_max = 16777216
    net.core.rmem_default = 16777216
    net.core.wmem_default = 16777216
    net.core.optmem_max = 16777216
    net.ipv4.tcp_mem = 16777216 16777216 16777216
    net.ipv4.tcp_rmem = 4096 87380 16777216
    net.ipv4.tcp_wmem = 4096 65536 16777216
    
  11. Finalmente ya sólo nos queda asignar un direccionamiento ip a las interfaces (mapeadas como ib0, ib1, etc...) y ya podemos proceder a hacer pruebas de ancho de banda:
  12. # iperf -c 10.99.99.4
    ------------------------------------------------------------
    Client connecting to 10.99.99.4, TCP port 5001
    TCP window size:  649 KByte (default)
    ------------------------------------------------------------
    [  3] local 10.99.99.3 port 55727 connected with 10.99.99.4 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec  13.1 GBytes  11.3 Gbits/sec
    
    # iperf -c 10.99.99.4
    ------------------------------------------------------------
    Client connecting to 10.99.99.4, TCP port 5001
    TCP window size:  649 KByte (default)
    ------------------------------------------------------------
    [  3] local 10.99.99.3 port 55728 connected with 10.99.99.4 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  3]  0.0-10.0 sec  13.3 GBytes  11.4 Gbits/sec
    
    # iperf -s
    ------------------------------------------------------------
    Server listening on TCP port 5001
    TCP window size: 85.3 KByte (default)
    ------------------------------------------------------------
    [  4] local 10.99.99.4 port 5001 connected with 10.99.99.3 port 55727
    [ ID] Interval       Transfer     Bandwidth
    [  4]  0.0-10.0 sec  13.1 GBytes  11.3 Gbits/sec
    [  5] local 10.99.99.4 port 5001 connected with 10.99.99.3 port 55728
    [  5]  0.0-10.0 sec  13.3 GBytes  11.4 Gbits/sec
    

Referencias:

http://blog.maumene.com/installing-the-mlx4-ib-driver-for-infiniband-on-debian-squeeze
http://inqbus-hosting.de/support/dokumentation/docs/debian-infiniband-howto
http://pkg-ofed.alioth.debian.org/howto/infiniband-howto-5.html#ss5.4
https://www.kernel.org/doc/Documentation/infiniband/ipoib.txt]]>
MySQL HA Multi-Master con Percona XtraDB Cluster, parte II http://enchufado.com/post.php?ID=367 http://enchufado.com/post.php?ID=367 Fri, 27 Dec 2013 16:26:51 +0100En un post previo vimos cómo crear una infraestructura Multi-Master con Percona XtraDB Cluster, pero si hacemos caso omiso a las recomendaciones y montamos clusters de 2 nodos, si se pierde la conexión entre los 2 nodos del cluster se pierde el quorum (cada nodo obtiene el 50%). Y ésto no sólo rompe el cluster, sino que además cada nodo por separado deja de funcionar.

Éste hecho lo tratan en la documentación de Percona relativa al failover:

Cluster Failover

The size of the cluster is used to determine the required votes to achieve 
quorum. A quorum vote is done when a node or nodes are suspected to no longer 
be part of the cluster (they do not respond). This no response timeout is the 
evs.suspect_timeout setting in the wsrep_provider_options (default 5 sec), and 
when a node goes down ungracefully, write operations will be blocked on the 
cluster for slightly longer than that timeout.

Once the node (or nodes) is determined to be disconnected, then the remaining 
nodes cast a quorum vote and if a majority remain from the total nodes 
connected from before the disconnect, then that partition remains up. In the 
case of a network partition, some nodes will be alive and active on each side 
of the network disconnect. In this case, only the quorum will continue, the 
partition(s) without quorum will go to the non-Primary state.

Because of this, it’s not possible to safely have automatic failover in a 2 
node cluster, because the failure of one node will cause the remaining node 
to go non-Primary. Further, cluster with an even number of nodes (say two 
nodes in two different switches) have some possibility of a split brain 
condition when if network connectivity is lost between the two partitions, 
neither would retain quorum, and so both would go to Non-Primary. Therefore: 
for automatic failover, the “rule of 3s” is recommended. It applies at various 
levels of infrastructure, depending on how far cluster is spread out to avoid 
single points of failure.

Ante éste escenario, ¿qué soluciones se nos ofrecen? En éste enlace de MySQL Performance Blog hablan del tema:

*Is is possible anyway to have a two nodes cluster?*

So, by default, Percona XtraDB Cluster does the right thing, this is how
it needs to work and you don’t suffer critical problem when you have
enough nodes. But how can we deal with that and avoid the resource to
stop ? If we check the list of parameters on galera’s wiki 
(http://www.codership.com/wiki/doku.php?id=galera_parameters_0.8) we can
see that there are two options referring to that:

- pc.ignore_quorum: Completely ignore quorum calculations. E.g. in
case master splits from several slaves it still remains operational. Use
with extreme caution even in master-slave setups, because slaves won’t
automatically reconnect to master in this case.

- pc.ignore_sb: Should we allow nodes to process updates even in the
case of split brain? This is a dangerous setting in multi-master setup,
but should simplify things in master-slave cluster (especially if only 2
nodes are used).

By ignoring the quorum (*wsrep_provider_options = “pc.ignore_quorum =
true”*), we ask to the cluster to not perform the majority calculation
to define the Primary Component (PC). A component is a set of nodes
which are connected to each other and when everything is ok, the whole
cluster is one component. For example if you have 3 nodes, and if 1 node
gets isolated (2 nodes can see each others and 1 node can see only
itself), we have then 2 components and the quorum calculation will be
2/3 (66%) on the 2 nodes communicating each others and 1/3 (33%) on the
single one. In this case the service will be stopped on the nodes where
the majority is not reached. The quorum algorithm helps to select a PC
and guarantees that there is no more than one primary component in the
cluster.

In our 2 nodes setup, when the communication between the 2 nodes is
broken, the quorum will be 1/2 (50%) on both node which is not the
majority… therefore the service is stopped on both node. In this case,
__/service/__means accepting queries.

By ignoring the splitbrain situation (*wsrep_provider_options =
“pc.ignore_sb = true”*). When the quorum algorithm fails to select a
Primary Component, we have then a split-brain condition. In our 2 nodes
setup when a node loses connection to it’s only peer, the default is to
stop accepting queries to avoid database inconsistency. If we bypass
this behaviour by ignoring the split-brain, then we can insert in both
nodes without any problem when the connection between the nodes is gone.
When the connection is back, the two servers are like independent, these
are now two single node clusters.

This is why two node clusters is not recommended at all. Now if you have
only storage for 2 nodes, using the galera arbitrator
(http://www.codership.com/wiki/doku.php?id=galera_arbitrator) is a very
good alternative then. On a third node, instead of running Percona
XtraDB Cluster (mysqld) just run *garbd*. Currently there is no init
script for garbd, but this is something easy to write as it can run in
daemon mode using -d:

garbd -a gcomm://192.168.70.2:4567 -g trimethylxanthine

If the communication fails between node1 and node2, they will
communicate and eventually send the changes through the node running
garbd (node3) and if one node dies, the other one behaves without any
problem and when the dead node comes back it will perform its IST or SST.

*In conclusion:* 2 nodes cluster is possible with Percona XtraDB Cluster
but it’s not advised at all because it will generates a lot of problem
in case of issue on one of the nodes. It’s much safer to use then a 3rd
node even a fake one using garbd.

If you plan anyway to have a cluster with only 2 nodes, don’t forget that:

- by default if one peer dies or if the communication between both nodes
is unstable, both nodes won’t accept queries.
- if you plan to ignore split-brain or quorum, you risk to have
inconsistent data very easily.

Así pues, podemos ver que la mejor solución para un cluster con 2 nodos pasa por crear un nuevo 'thin node' con un demonio (garbd, también conocido como galera arbitrator) para no encontrarnos con split brains a la mínima que los 2 nodos pierdan comunicación y evitar así que ésto pase. Cierto es que ésto supone usar un tercer nodo, pero sólo lo será a efectos de quorum, pues no aloja ni datos ni siquiera la parte cliente/servidor de MySQL.

Antes de proceder, nótese que usamos las direcciones de red del post previo relativo al tema más una nueva dirección ip para el 'thin node' (192.168.0.63). Asimismo, aquí asumimos que en el escenario que nos ocupa (con 2 nodos "reales") usaremos una configuración Unicast. Así pues, vamos a ello:

  1. Instalamos el paquete que contiene el demonio:
  2. $ apt-get install percona-xtradb-cluster-galera-2.x
    
  3. Iniciamos el demonio indicando la cadena de conexión, el nombre del cluster y un fichero de log que nos puede ayudar en caso de necesitarlo:
  4. garbd -d -a gcomm://192.168.0.61,192.168.0.62,192.168.0.63 -g my_percona_cluster -l /var/log/garbd.log
    

    Hay que tener en cuenta de modificar y tener el mismo string de conexión (gcomm://...) en todos los nodos, adaptándolo para nuestro caso.

  5. Si la comunicación es correcta con los demás nodos del cluster, esto debería ser cuanto se necesita. Comprobamos que tengamos el nuevo 'thin node' unido al cluster:
  6. $ mysql> show status like 'wsrep%';
    | wsrep_cluster_conf_id      | 19                                   |
    | wsrep_cluster_size         | 3                                    |
    
  7. Finalmente podemos situar éste demonio para que se inicie automáticamente (p.ej. en /etc/rc.local).

Con ésto, podemos hacer la prueba de bajar uno de los 2 nodos "reales" por un tiempo y veremos que podemos seguir lanzando queries al restante. Y no sólo eso, puesto que cuando el caído vuelva en sí, se podrá al día de los cambios que sufrió el primero.

]]>
http://enchufado.com/post.php?ID=366 http://enchufado.com/post.php?ID=366 Sun, 15 Dec 2013 22:03:50 +0100Para empezar, comentar que Policyd es un sistema antispam para Postfix que hace muchas cosas: greylisting, throttling, rate limiting, spamtrap y blacklisting/whitelisting. Aquí vamos a usar la función de throttling o de limitación del número de correos por unidad de tiempo. Efectivamente, usaremos Debian GNU/Linux, aunque partes de la guía puedan adaptarse a otras distros.

Al lío:

  1. Instalamos el paquete:
  2. $ apt-get install postfix-policyd

    A modo de nota informativa, la instalación del paquete nos crea automáticamente la BD postfixpolicyd en MySQL, y la tabla que nos interesa aquí es throttle.

  3. Configuración de la opción de throttling (sección SENDER THROTTLE):
  4. $ vi /etc/postfix-policyd.conf:
    
    # Habilitamos el sender throttling.
    SENDERTHROTTLE=1
    # Le decimos que dé un rechazo temporal (4xx) en lugar de uno definitivo (5xx).
    QUOTA_EXCEEDED_TEMP_REJECT=1
    # Ponemos un mensajito que nos sirva para identificarlo.
    SENDER_QUOTA_REJECTION="Quota Exceeded (check policyd!)."
    SENDER_SIZE_REJECTION="Message size too big (check policyd!)."
    # Definimos la quota de número de correos permitido por unidad de tiempo...
    SENDERMSGLIMIT=200
    # ...así como la cantidad de destinatarios permitidos.
    SENDERRCPTLIMIT=500
    # Y el tamaño máximo total transferido. Ojo porque tiene un hardlimit en 2GB.
    SENDERQUOTALIMIT=2000000000
    # La unidad de tiempo en que ésta limitación se reinicializa/resetea.
    SENDERTIMELIMIT=1h
    # El tamaño máximo del mensaje (100MB).
    SENDERMSGSIZE=102400000
    # Y finalmente los umbrales de los avisos, que iran a syslog.
    SENDERMSGSIZE_WARN=50
    SENDERMSGSIZE_PANIC=90
    SENDER_INACTIVE_EXPIRE=5d
    
  5. Reiniciamos el servicio para aplicar éstos cambios:
  6. $ /etc/init.d/postfix-policyd restart
  7. Finalmente incluimos éste filtro en postfix y lo reiniciamos también:
  8. $ vi /etc/postfix/main.cf:
    smtpd_end_of_data_restrictions =
            check_policy_service inet:127.0.0.1:10031,
            permit_mynetworks
    
    $ /etc/init.d/postfix restart
    
  9. Opcional: hice éste pequeño script de monitoritzación en PHP a modo de interfaz gráfico web que toma los valores de la base de datos para poder consultar (y también resetear) el estado de éste throttling. Sustituir los campos ip, db_user y dp_password al principio del script por unos correctos para tu setup.

Y con ésto ya tendríamos funcionando el throttling, cuyo estado podemos consultar a través de la base de datos, los logs o el mencionado script.

]]>
MySQL HA Multi-Master con Percona XtraDB Cluster http://enchufado.com/post.php?ID=365 http://enchufado.com/post.php?ID=365 Fri, 08 Nov 2013 21:59:58 +0100Con un nombre de producto cual detergente anunciado en TV tenemos una solución de HA y Multi-Master que deja en pañales en cuanto a senzillez de configuración, mantenimiento y resolución de incidencias (troubleshooting) a la infraestructura sobre la que hablamos hace poco en éste post acerca de DRBD + Pacemaker + Corosync (aunque está claro que ésta última es multipurpose, y no sólo orientada a un servicio en particular). Estamos hablando del Percona XtraDB Cluster, una solución opensource (GPLv2) de HA y cluster escalable para MySQL que integra la librería Galera y le añade una serie de herramientas propias.

Como hemos dejado entrever, Percona nos ofrece un setup rápido y senzillo para montar una infraestructura Multi-Master de N nodos MySQL. Lo que viene a traducirse a que podemos usar cualquier nodo tanto para leer como para escribir en paralelo, encargándose de gestionar el acceso en simultáneo a un mismo recurso. Ésto nos da la opción de definir un buen abanico de arquitecturas, como por ejemplo:

Elegir una u otra ya depende de las necesidades/presupuesto de cada cual. El setup que vamos a comentar aquí es el correspondiente al segundo gráfico, dónde un host accede a uno de los 2 nodos que forman el Percona XtraDB Cluster. Si bien para Percona ambos estan en modo Master (siendo viable atacar a cualquiera de ellos para leer, escribir o ambos en un momento dado), haremos que sólo uno actúe a la vez, quedando el otro de reserva/backup. Es decir, vamos a simular un entorno Master-Slave. ¿Por qué íbamos a hacer eso pudiendo aprovecharnos de un entorno Multi-Master? Porque deseamos disponer de un entorno de HA por encima del load balancing, teniendo un nodo en producción y el otro en replicación constante, y si algo le sucediera al que está en producción poder poner el otro en su lugar (y que todo siga funcionando). Y éste comportamiento lo lograremos configurando una ip virtual con Keepalived que será la que definirá el nodo en producción, estando el otro de reserva pero con todos los datos actualizados al momento.

Comentar también que si bien en todo momento sólo hablamos de clusters de 2 nodos, en realidad pueden ser los que se deseen. De hecho, Percona/Galera recomiendan un setup mínimo de 3 para evitar encontrarse con situaciones de split brain, de las cuales no se encarga el cluster. Esto nos lleva a recomendar que en previsión del posible crecimiento del número de nodos que forma el cluster, éste funcione por Multicast para evitar saturar el ancho de banda de los equipos de red. Ésto también lo veremos aquí, así que vamos al lio.

Instalación de Percona XtraDB Cluster y configuración básica

  1. Añadimos la key y el repositorio de paquetes para Debian de Percona y actualizamos la lista de paquetes. Nótese que sustituimos convenientemente VERSION por nuestra versión de Debian (creo que actualmente sólo hay paquetes para squeeze y wheezy):
  2. $ apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A
    $ vi /etc/apt/sources.list.d/percona.list
    deb http://repo.percona.com/apt VERSION main
    deb-src http://repo.percona.com/apt VERSION main
    $ apt-get update
    
  3. Instalamos Percona y paramos el servicio:
  4. $ apt-get install percona-xtradb-cluster-server-5.5 percona-xtradb-cluster-client-5.5
    $ /etc/init.d/mysql stop
    
  5. A continuación, configuramos el nodo primario (el que hará el bootstrap/inicialización del cluster) y lo iniciamos:
  6. $ vi /etc/mysql/my.cnf
    
    [mysqld]
    datadir=/var/lib/mysql
    user=mysql
    # Path to Galera library
    wsrep_provider=/usr/lib/libgalera_smm.so
    # Empty gcomm address is being used when cluster is getting bootstrapped
    wsrep_cluster_address=gcomm://
    # Cluster connection URL contains the IPs of node#1 and node#2
    ###wsrep_cluster_address=gcomm://192.168.0.61,192.168.0.62
    # 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 is a recommended tuning variable for performance
    innodb_locks_unsafe_for_binlog=1
    # 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.61
    # SST method
    wsrep_sst_method=xtrabackup
    # Cluster name
    wsrep_cluster_name=my_percona_cluster
    # Authentication for SST method
    wsrep_sst_auth="sstuser:s3cretPass"
    
    $ /etc/init.d/mysql start
    
  7. Breve explicación de algunos de los parámetros de la configuración del punto anterior:
    • wsrep_cluster_address: Inicialmente indicamos el string de conexión vacío/sin direcciones ip (gcomm://) para inicializar (bootstrapping) el cluster y una vez esté formado, debemos sustituirla por la cadena (comentada con ###) que tiene todas las direcciones ip correspondientes a los nodos del cluster.
    • default_storage_engine: Motor de BD por defecto. Recomendable -aunque no obligatorio- usar InnoDB. Actualmente la replicación también funciona con MyISAM, con sus limitaciones intrínsecas (bloqueo a nivel de tabla).
    • wsrep_node_address: Dirección ip de éste nodo.
    • wsrep_sst_method: método SST (State Snapshow Transfer), o cómo son transferidos los datos cuando un nodo se une al cluster. Puede ser vía mysqldump, rsync y xtrabackup, éste último el más conveniente por no requerir READ LOCK.
    • wsrep_cluster_name: Nombre del cluster.
    • wsrep_sst_auth: Autenticación (usuario:contraseña) para unir nodos al cluster.
  8. Hacemos un check del cluster para ver su estado:
  9. mysql@percona1> 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                                   |
    +----------------------------+--------------------------------------+
    40 rows in set (0.01 sec)
    

    Fijémonos que el parámetro wsrep_cluster_size nos indica que efectivamente es el primer nodo que conforma el cluster.

  10. En el mismo nodo, creamos el usuario que se usará para hacer el SST (State Snapshot Transfer):
  11. mysql@percona1> CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 's3cretPass';
    mysql@percona1> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';
    mysql@percona1> FLUSH PRIVILEGES;
    
  12. Ahora configuramos el nodo secundario y lo iniciamos. Es posible que dé un error al iniciar el servicio, en cuyo caso tenemos que cerciorarnos que la contraseña para el usuario que gestiona el servicio en Debian (debian-sys-maint) sea la misma que la del nodo primario (/etc/mysql/debian.cnf):
  13. $ vi /etc/mysql/my.cnf
    
    [mysqld]
    datadir=/var/lib/mysql
    user=mysql
    # Path to Galera library
    wsrep_provider=/usr/lib/libgalera_smm.so
    # Cluster connection URL contains IPs of node#1 and node#2
    wsrep_cluster_address=gcomm://192.168.0.61,192.168.0.62
    # 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 is a recommended tuning variable for performance
    innodb_locks_unsafe_for_binlog=1
    # This changes how InnoDB autoincrement locks are managed and is a requirement for Galera
    innodb_autoinc_lock_mode=2
    # Node #2 address
    wsrep_node_address=192.168.0.62
    # Cluster name
    wsrep_cluster_name=my_percona_cluster
    # SST method
    wsrep_sst_method=xtrabackup
    #Authentication for SST method
    wsrep_sst_auth="sstuser:s3cretPass"
    
    $ /etc/init.d/mysql start
    
  14. Finalmente hacemos un check del cluster en éste mismo nodo:
  15. mysql@percona2> 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         | 2                                    |
    | wsrep_cluster_status       | Primary                              |
    | wsrep_connected            | ON                                   |
    ...
    | wsrep_ready                | ON                                   |
    +----------------------------+--------------------------------------+
    40 rows in set (0.01 sec)
    

    De nuevo, el parámetro wsrep_cluster_size nos indica que ahora tenemos 2 nodos en el cluster. El wsrep_local_state_uuid nos dará (para ir bien) un id del cluster que coincidirá con el previo. Para cada nodo a añadir al cluster seguiremos los pasos 1, 2, 7 y 8.

Con ésto ya tenemos el cluster de 2 nodos MySQL montado y funcionando por Unicast. Referencia: Percona Ubuntu Howto

Configuración del Multicast.

  1. Primero debemos comprobar que el tráfico Multicast esté permitido en nuestra red. Hay muchas maneras de hacerlo, a continuación se usa iperf para averiguarlo:
  2. root@percona2:~# iperf -s -u -B 226.94.1.1 -i 1
    ------------------------------------------------------------
    Server listening on UDP port 5001
    Binding to local address 226.94.1.1
    Joining multicast group 226.94.1.1
    Receiving 1470 byte datagrams
    UDP buffer size: 122 KByte (default)
    ------------------------------------------------------------
    [ 3] local 226.94.1.1 port 5001 connected with 212.11.66.254 port 49525
    [ ID] Interval Transfer Bandwidth Jitter Lost/Total
    Datagrams
    [ 3] 0.0- 1.0 sec 128 KBytes 1.05 Mbits/sec 0.037 ms 0/ 89
    
    root@percona1:~# iperf -c 226.94.1.1 -u -T 32 -t 3 -i 1
    ------------------------------------------------------------
    Client connecting to 226.94.1.1, UDP port 5001
    Sending 1470 byte datagrams
    Setting multicast TTL to 32
    UDP buffer size: 122 KByte (default)
    ------------------------------------------------------------
    [ 3] local 212.11.66.254 port 49525 connected with 226.94.1.1 port 5001
    [ ID] Interval Transfer Bandwidth
    [ 3] 0.0- 1.0 sec 129 KBytes 1.06 Mbits/sec
    
  3. Si el test fue correcto, debemos añadir primero una interfaz de red (p.ej. eth1) que se encargará del tráfico Multicast:
  4. # Adición manual/temporal para salir del caso:
    $ ifconfig eth1 up
    $ ip ro add dev eth1 224.0.0.0/4
    
    # O adición permanente, preferible para evitar olvidos al reiniciar:
    $ vi /etc/network/interfaces
    auto eth1
    iface eth1 inet manual
    up ifconfig eth1 up
    post-up route add -net 224.0.0.0/24 dev eth1
    
  5. Posteriormente definiremos una nueva variable a la configuración de MySQL que le indicará la ip Multicast que usaremos, tras lo cual reiniciaremos por separado (núnca a la vez) cada nodo:
  6. $ vi /etc/mysql/my.cnf
    wsrep_provider_options = "gmcast.mcast_addr=239.192.0.11"
    $ /etc/init.d/mysql restart
    
  7. Para comprobar que todo fue bien, podemos monitorizar éste tráfico (UDP) en cada nodo para esa ip del grupo Multicast:
  8. $ tcpdump -n udp host 239.192.0.11
    

    Aplicaremos ésta configuración en cada nodo del cluster siguiendo los mismos pasos.

Instalación y configuración de Keepalived + indicador de rol en prompt.

Como hemos comentado con anterioridad, Keepalived nos servirá para definir quién es el nodo Master y quién el Slave en base a una ip virtual (usaremos la 192.168.0.60) que migrará de un nodo a otro en función de su disponibilidad. Esto lo hará usando su capacidad de failover gracias a la gestión del protocolo VRRP. A parte, también crearemos un script que nos proporcionará una identificación visual rápida/cómoda a través de un string coloreado en el prompt (con M para Master o S para Slave) para saber qué nodo está actuando con qué rol con sólo conectarnos.

  1. Instalamos Keepalived, lo configuramos y reiniciamos el servicio:
  2. $ apt-get install keepalived
    $ vi /etc/keepalived/keepalived.conf
    
    vrrp_instance PERCONA {
            interface eth0
    	# Equidad de preferencia en los nodos
            state EQUAL
    	# Identificador para la comunicación de los nodos por VRRP
            virtual_router_id 123
            priority 10
            virtual_ipaddress {
    		# Ip virtual que definirá el nodo Master
                    192.168.0.60/24 label eth0:60
            }
    	# Script lanzado a cada cambio de estado
            notify /usr/sbin/prompt.sh
    }
    
  3. Creamos el script que gestionará el cambio de prompt y le damos permisos de ejecución:
  4. $ vi /usr/sbin/prompt.sh
    
    #!/bin/bash
    msg (){
            if [ "$TERM" = "xterm" ]; then
                    case "$1" in
                            "Slave")
                                    echo -e '\e[0;33m(S)\e[0m'
                            ;;
                            "Master")
                                    echo -e '\e[0;32m(M)\e[0m'
                            ;;
                            *)
                                    echo -e '\e[0;35m(U)\e[0m'
                    esac
            else
                    if [ -n "$1" ]; then echo $1
                    else echo "Unknown"
                    fi
            fi
    }
    ifconfig | grep "192.168.0.60"
    if [ $? -eq 0 ]; then msg Master
    else msg Slave
    fi
    
    $ chmod +x /usr/sbin/prompt.sh
    
  5. Añadimos la llamada al script al inicio de sesión:
  6. $ vi /root/.bashrc
    PS1='\u@\h:\w`prompt.sh`\$ '
    
  7. Para finalizar, reiniciamos Keepalived y salimos/entramos a la sesión:
  8. $ /etc/init.d/keepalived restart
    $ exit
    

    Esto cabe hacerlo en cada nodo del cluster. Con ésto bien configurado, seran los prompts los que nos indiquen quién es Master y quién Slave. Si tuviéramos 2 hosts del cluster distintos (p.ej. uno más potente que otro), podríamos definir para el potente una mayor priority para forzar que éste sea el nodo Master preferido siempre que esté disponible.

Popourri

  • Procotolos y puertos. Por si usamos firewalls, conviene tener presente que usaremos los protocolos TCP, UDP (para el Multicast) y VRRP (para Keepalived). Los puertos, a parte del de MySQL (3306) son el 4444, 4567 y 4568.
  • Monitorización. Se podria hacer un script para Nagios (o cualquier otro sistema de monirorización) que tomara en cuenta el valor que devuelven las siguientes variables en cada uno de los nodos que forman el cluster (con una consulta como la que vimos antes, show status like 'wsrep%';):
  • wsrep_cluster_size - Nombre de nodos del cluster (ojo porque existe algún BUG con éste parámetro)
    wsrep_cluster_status - Indica si todos los nodos del cluster estan sincronizados (Primary) o hay alguno en situación de split brain
    wsrep_ready - Indica si el cluster está listo o si por el contrario, no puede recibir comandos SQL.
    wsrep_connected - Indica si el nodo está o no conectado al cluster.
    wsrep_flow_control_paused - Indica el estado de sincronización del cluster (si tiene o no lag).
    
  • Motores. Aunque ya lo hemos comentado antes, hasta no hace mucho, la replicación con éste sistema sólo funcionaba con el motor InnoDB, pero las últimas versiones estables incorporan soporte para MyISAM, evidentemente con sus limitaciones (bloqueo a nivel de tabla) y los problemas que ésto puede conllevar. Edit: El soporte de replicación para MyISAM parece que continúa en bragas, así que mejor no usarlo.
  • Troubleshooting. En un montaje de 2 nodos como el que hemos comentado, si un nodo queda fuera de juego no debería pasar nada porque queda el otro sirviendo las peticiones. Y cuando el nodo en fallo vuelva en sí, debería unirse de nuevo al cluster replicando aquello que vea necesario. Pero en situación de split brain, es función del sysadmin decidir qué nodo es el que tiene los datos más nuevos y proceder a una inicialización del mismo para formar de nuevo cluster. Edit: Si se pierde la conexión entre los 2 nodos del cluster, no sólo el cluster deja de funcionar como tal sino que también lo hace cada nodo de forma individual, quedando las bases de datos inaccesibles. Ver el próximo post que trata el tema en setups de clusters de 2 nodos.
No podría finalizar sin mencionar que es altamente recomendable consultar, a parte de la documentación de Percona, la Wiki de Galera.]]>