Posts tagged with “mysql”
Arrancando nuestro primer cluster
Una vez que conocemos la teoría, vamos a poner en marcha nuestro primer Cluster. Estará compuesto únicamente por 3 ordenadores.
Nodo 1 (192.168.1.106):
- ndb_mgmd
- mysqld
Nodo 2 (192.168.1.104):
- ndbd
Nodo 3 (192.168.1.105):
- ndbd
Esto es, el nodo 1 será un Management Node + API Node y los dos restantes Data Nodes.
Lo primero de todo es descargarnos MySQL Cluster de http://dev.mysql.com/downloads/cluster/
La instalación es tan sencilla como descomprimir el fichero y copiar a nuestro PATH los ejecutables que necesitemos. Por lo tanto, llevaremos a /usr/bin/ los ejecutables ndbd, ndb_mgmd, ndb_mgm, mysqld, mysqld_safe.
Para tener un poco ordenadas las cosas, creamos la carpeta /etc/mysql-cluster/ donde alojaremos el fichero de configuración del cluster config.ini.
# cat /etc/mysql-cluster/config.ini [ndbd default] NoOfReplicas=2 DataDir=/var/lib/mysql-cluster DataMemory=512M IndexMemory=128M TransactionDeadlockDetectionTimeout=5000 MaxNoOfConcurrentOperations=100000 MaxNoOfLocalOperations=110000 [ndb_mgmd] Id=1 HostName=192.168.1.106 [ndbd] Id=5 HostName=192.168.1.104 [ndbd] Id=6 HostName=192.168.1.105 [mysqld] Id=7
Como vemos, en primer lugar indicamos los valores por defecto para todos los Data Nodes (ndbd). Por ejemplo se indican el número de replicas, donde se almacenarán los datos, la cantidad de memoria usada para almacenar datos e índices, número de operaciones concurrentes, etc. Estos valores no están ni calculados ni ajustados a la realidad, solamente son funcionales para este ejemplo y para trabajar con la base de datos employees. Cada caso y cada base de datos necesitará distintos valores que se deberán ajustar en función de la carga y cantidad de datos a almacenar.
El Management Node será el número 1 con la IP indicada, mientras que los Data Nodes serán los ID 5 y 6 con sus respectivas IPs. El API node (o en este caso más concreto Mysql Node) no tiene una ip asignada, por lo que se podría conectar desde cualquier equipo de la red.
Una vez que tenemos el fichero procedemos a arrancar el Management Node:
# ndb_mgmd -f /etc/mysql-cluster/config.ini 2010-07-25 19:30:06 [MgmtSrvr] INFO -- NDB Cluster Management Server. mysql-5.1.44 ndb-7.1.4b 2010-07-25 19:30:06 [MgmtSrvr] INFO -- Reading cluster configuration from '/etc/mysql-cluster/config.ini'
Arrancamos la consola y vemos que nodos tenemos arrancados:
# ndb_mgm -- NDB Cluster -- Management Client -- ndb_mgm> show Connected to Management Server at: localhost:1186 Cluster Configuration --------------------- [ndbd(NDB)] 2 node(s) id=5 (not connected, accepting connect from 192.168.1.104) id=6 (not connected, accepting connect from 192.168.1.105) [ndb_mgmd(MGM)] 1 node(s) id=1 @192.168.1.106 (mysql-5.1.44 ndb-7.1.4) [mysqld(API)] 1 node(s) id=7 (not connected, accepting connect from any host)
Solo tenemos el Management Node en marcha. Vamos a proceder a arrancar los Data Nodes. Nos conectamos a cada nodo y ejecutamos:
# ndbd --connect-string=192.168.1.106 --initial -n 2010-07-25 19:31:38 [ndbd] INFO -- Configuration fetched from '192.168.1.106:1186', generation: 1
La opción --initial se usa cuando iniciamos por primera vez el Cluster para arrancar con el sistema de ficheros limpio. -n indica que el nodo no se autoarranque y --connect-string indica la IP del Management Node al que nos conectaremos.
Una vez que Data Node se conecta al Management Node, este último les entrega el fichero de configuración con los parametros necesarios para que se configuren. Ahora, desde la consola de administración podremos arrancar los dos Data Nodes:
ndb_mgm> 5 start Database node 5 is being started. ndb_mgm> Node 5: Start initiated (version 7.1.4) ndb_mgm> 6 start Database node 6 is being started. ndb_mgm> Node 6: Start initiated (version 7.1.4) ndb_mgm> show Cluster Configuration --------------------- [ndbd(NDB)] 2 node(s) id=5 @192.168.1.104 (mysql-5.1.44 ndb-7.1.4, Nodegroup: 0, Master) id=6 @192.168.1.105 (mysql-5.1.44 ndb-7.1.4, Nodegroup: 0) [ndb_mgmd(MGM)] 1 node(s) id=1 @192.168.1.106 (mysql-5.1.44 ndb-7.1.4) [mysqld(API)] 1 node(s) id=7 @192.168.1.106 (mysql-5.1.44 ndb-7.1.4)
Ya tenemos los Data Nodes en marcha.
Para arrancar el Api Node únicamente hay que ejecutar el demonio mysqld:
# mysqld_safe --ndbcluster &
No es necesario indicarle la IP del Management Node ya que se encuentran en la misma máquina.
Listo! Si ahora nos conectamos con el cliente mysql a localhost y creamos una base de datos usando tablas ndbcluster, estas se almacenarán en nuestro recién creado Cluster :)
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.
Finalmente no me certifico en MySQL Cluster
Realmente no es porque yo no quiera, que en realidad tengo muchas ganas, si no que el pésimo servicio de atención al cliente de Oracle me lo impide por su completa inutilidad operativa. Llevo meses esperando que hagan algo que a priori es sencillo, comprobar mis certificados en PearsonVUE para permitirme sacar la nueva certificación en Prometric. Algo tan sencillo como eso, más aún siendo Oracle cliente también de PearsonVUE, se ha convertido en una hazaña imposible.
Desde la última vez que me pidieron algunos datos y documentos desde "suncert_ww@oracle.com" no he vuelto a saber de ellos. Y cuando escribo ya no me llega ni el mensaje de respuesta automática. Por lo tanto, ¿que puedo pensar de esto? O que estoy filtrado de por vida o que son unos completos inútiles. Desde aquí lanzo unas preguntas:
- ¿Si tuviese una cuenta en Metalink u Oracle Support me harían más caso?
- ¿Y Si estuviese interesado en certificarme en Oracle?
Estas pidiendo ayuda al servicio de soporte para poder certificarte y te sientes como si estuvieras mendigando.
Si alguien ha tenido un problema similar y ha logrado solucionarlo, ¡que se comunique conmigo para saber como! Contacto
Entendiendo y utilizando la Query Cache
La Query Cache nos permite almacenar el resultado de las query SELECT en una cache, de forma que si se piden los mismos datos repetidamente, únicamente tendrá que ejecutarlo una vez, devolviendo el resto de veces el resultado desde la memoria. Esto, como os podeis imaginar, mejora en gran medida el rendimiento de nuestro servidor. Pero hay que tener una serie detalles en cuenta al hacer uso de esta cache :)
- Para mantener la consistencia en los resultados guarda una relación de las tablas a las cuales afectan la query, de forma que si una de esas tablas se ve modificada, la Query Cache se invalida.
- La query se guarda tal y como la hemos escrito, esto es, para la Cache no sería lo mismo "SELECT Nom,Ap from t where id=2" que "SELECT nom,ap from T where id=2".
- No se guardará el resultado de la query a no ser que esta no sera determinista. Por lo tanto, funciones como NOW(), CURRENT_DATE(), CURRENT_USER(), etc. no son candidatas a ser cacheadas.
- La Query Cache añade overhead. Las queries de lectura deben leer o escribir de la cache y las de escritura deben borrar las caches asociadas a las tablas modificadas.
- Durante una transacción, las caches asociadas a las tablas modificadas no se podrán usar hasta que no se haga COMMIT o ROLLBACK.
Podemos controlar como de eficiente es nuestra Cache mirando el estado de algunas variables de MySQL. Cuando una query se responde de la cache, el valor que aumenta es Qcache_hits. Por el contrario, si la query debe ejecutarse por no estar previamente cacheada, aumentaremos en uno el valor de Com_select. Por lo tanto, para conocer el ratio de hacierto podemos hacer uso de esta formula:
Qcache_hits / (Qcache_hits+Com_select)
Otra variable importante a tener en cuenta es Qcache_lowmem_prunes, que es un contador del número de queries sacadas de la caché por falta de memoria. Si el valor de esta variable sube demasiado a lo largo del tiempo, deberás ir pensando en aumentar el tamaño de la caché.
Los valores que debemos "tunear" en nuestro my.cf son los siguientes:
query_cache_type: puede tener el valor ON, OFF y DEMAND. Los dos primeros habilitan o deshabilitan la caché, mientras que el último cacheará una query siempre y cuando lleve el modificador SQL_CACHE
query_cache_size: es el tamaño de la caché. Debe ser un valor múltiplo de 1024 bytes
query_cache_min_res_unit: MySQL guarda las cachés en la memoria en pequeños bloques, como si de un sistema de ficheros se tratase. En un principio no sabe realmente el tamaño que va a tener el resultado de una query, por lo que según va enviando las filas al cliente, va cogiendo bloques. Los bloques tendrán como mínimo el tamaño aquí indicado. Este valor es importante para evitar la fragmentación de la memoria y así aprovecharla lo mejor posible
query_cache_limit: si un resultado supera el tamaño aquí indicado, no se cacheará. Pero recordad lo comentado en el punto anterior, MySQL no sabe a priori cuando ocupará, por lo que igualmente irá reservando bloques hasta llegar al query_cache_limit, momento en el cual los bloques escritos se liberarán de nuevo
Para evitar la fragmentación hay que elegir un valor correcto. Este no debe ser muy pequeño, ya que aunque evitaremos perder memoria, MySQL tendrá que ir cogiendo bloques constantemente. Ni muy grande, ya que si nuestras queries devuelven resultados pequeños tendremos bastante fragmentación. Una de las formas de tener un valor cercano al óptimo es saber la media de tamaño de las queries almacenadas. Para ello podemos aplicar la siguiente formula:
(query_cache_size – Qcache_free_memory) / Qcache_queries_in_cache
Esto es, la memoria usada entre el numero de queries en caché.
Para saber si realmente tienes la caché muy fragmentada, puedes hacerte una idea comprobando el número de bloques libres Qcache_free_blocks. Si el valor de esta variable está cercana a Qcache_total_blocks / 2, entonces tienes un grave problema de fragmentación.
MySQL también tiene su propio desfragmentador :) FLUSH QUERY CACHE moverá todos los bloques utilizados eliminando los espacios en blanco entre ellos.
La desastrosa atención al cliente de Oracle y Prometric
Si no me equivoco desde junio del año pasado Sun Microsystems ha pasado sus certificaciones de MySQL de PearsonVUE a Prometric. Justo antes de ese cambió aprobé la certificación de MySQL DBA. Y ahí comienza el infierno, como siempre protagonizada por los departamentos de atención al cliente.
Me cree una cuenta en Prometric para poder seguir con mi formación (MySQL Cluster) y me extrañé un poco al ver que no recibía ningún correo. Pero no me preocupé mucho, ya que podía entrar con mi cuenta y comprobar que funcionaba correctamente. Envié un correo a Prometric comentando que mi certificación estaba en el limbo, necesitaba que la moviesen a Prometric para poder hacer MySQL Cluster (MySQL DBA es un requisito). Pasaron los días y no recibí nada. Finalmente, después de días de espera, me dio por mirar los logs de mi servidor de correo y veo:
NOQUEUE: reject: RCPT from promailer.prometric.com[208.76.122.11]: 450 4.7.1 <MAILSVRRLY02.proint.prometric.root>: Helo command rejected: Host not found; from=NOSPAM@prometric.com to=NOSPAM@miguelangelnieto.net proto=ESMTP helo=<MAILSVRRLY02.proint.prometric.root>
Perfecto, se identifican en el HELO (MAILSVRRLY02.proint.prometric.root) con un nombre de dominio inválido. Quito la restricción en mi Postfix y al momento su SMTP me reenvía el correo.
Received-SPF: softfail (miguelangelnieto.net: best guess record for domain of transitioning NOSPAM@prometric.com does not designate 208.76.122.11 as permitted sender) client-ip=208.76.122.11;
Ah, vale, perfecto otra vez. También tienen mal configurado su SPF. ¿Se puede ser más mamado? Desactivo también la comprobación de SPF y me llega porfín el correo. Estoy nervioso, ¿será la respuesta a mi problema?
Mi gozo en un pozo, es el mail de bienvenida por registrarme. Desde entonces sigo con las protecciones AntiSPAM desactivadas, porque aunque les avisé por mail de que su Postmaster es un borracho aún no me han hecho caso. Quién sabe, quizás un día me escriben un mail y supongo que será interesante leerlo... o no.
En su propia web dicen:
As spam and security configurations vary from computer to computer, it is possible that our email response may land in your spam folder. Please check your spam folder frequently if you have not received a response within the two business day period.
No señores de Prometric, no es culpa de las configuraciones de spam o seguridad de los ordenadores, es vuestra mierda de configuración de correo.
Viendo que la atención al cliente de Prometric es nula, me pongo en contacto con el departamento de formación de Sun en España. En este caso la respuesta rápida, me pide documentos que prueben que aprobé el examen. Se los mando y se pone en contacto con Prometric. Pasan unas semanas y no hay respuesta, vuelvo a escribir a Sun y estos me piden disculpas, volviendo a reenviar el correo a Prometric. Pasan unas semanas otra vez y repito el proceso. Sun me dice que no puede hacer nada más que reenviarles el correo una y otra vez. Aprovecho para dejar claro que la atención de Sun España ha sido en todo momento correcta.
Finalmente recibo un correo de Oracle (en ingés) que más bien parece una respuesta automática. En ella me dicen que les diga a cual de los exámenes que he hecho en Prometric se refiere la consulta. Querido sistema automático de respuestas, a ninguno ya que aún no he podido examinarme. No se han leído ninguno de los correos que desde Sun les han enviado. Simplemente han cogido mi dirección y han pegado un texto. Les respondo repitiendo otra vez cual es mi problema y recibo este mensaje:
Thank you for contacting the Sun Certification Program. Read on for important information! suncert_ww receives a very high volume of emails daily. Your question is important to us and we reply to all requests as soon as possible. Please allow up to 7 business days for a reply. Please note that sending multiple emails will cause more email for us to filter through and may slow down our response time.
De eso hace ya 15 días.
Como podéis comprobar, el trato al cliente es de lo peor, lo más parecido a las empresas bananeras de telecomunicaciones que tenemos en España.
Sigo sin respuesta, sigo sin poder certificarme. Gracias Oracle, gracias Prometric.
Replicación multi-master y síncrona con Galera

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
Consejos para mejorar el rendimiento de MySQL (Parte I)
Acepto comentarios, puedo estar equivocado :)
- El tipo datetime ocupa 8 bytes y no es timezone-aware. Timestamp ocupa la mitad (4 bytes) y es timezone-aware. Usa timestamp.
- El tipo varchar es más lento que char, pero generalmente ocupa menos espacio. Antes de definir la columna piensa que datos se van a guardar. Si son de tamaño fijo (o muy muy similares) usa char (por ejemplo para un md5).
- Si tu charset es UTF-8, es posible que el string ocupe hasta el tripe de espacio. Usa UTF-8 solamente donde sea necesario.
- Si en un campo varchar o char vas a guardar siempre los mismos strings, usa enum.
- Si no necesitas decimales exactos, usa tipos de coma flotante (float o double). El tipo decimal no lo calcula la CPU (no puede), lo hace MySQL, lo cual es muchisimo más lento.
- Todas las columnas deben ser NOT NULL. Procesar un NULL consume CPU y memoria. Si quieres que los campos se puedan quedar vacios, mete un 0 o un string vacio ””
- Poner índices a todas las columnas no es la solución para mejorar el rendimiento. Ponlo solo en las columnas por las que busques. Contrá más índices, mas uso de memoria y los INSERT y UPDATES serán cada vez más lentos.
- En un sistema de 32 bits da igual cuanta memoria RAM tengas, MySQL solamente usará 2 GB como máximo. No configures los buffers y caches a un valor mayor o te empezarán a fallar las querys.
- Si tienes una tabla de insercción constante (por ejemplo un log) no lo dejes en InnoDB, utiliza archive. Comprimirá los datos y las busquedas posiblemente sean igual o más rápidas.
- No existe un engine perfecto para todas las situaciones. Debes estudiar como se tratará la tabla y que uso harás de ella. ¿Vas a usar transacciones? ¿necesitas merge? ¿haces busquedas full text? ¿se van a updatear o eliminar datos o todo serán insert? ¿vas a comprimir en un futuro la tabla? ¿necesitas cachear datos? Poner todo en InnoDB no es una solución.
- BLOB y TEXT no pueden ser índices.
- El engine MEMORY no soporta BLOB y TEXT, si alguna tabla con esos tipos de datos necesita una tabla temporal irá directamente a disco duro. No uses BLOG y TEXT a poder ser.
- Habilitar sync-binlog tiene cosas buenas y malas. La buena que no dependes del sistema de ficheros para recuperarte de un fallo del servidor (ningún FS es perfecto) y la mala que haces un uso más intenso en I/O del disco duro. Piensa bien que quieres antes de habilitarlo, rendimiento o seguridad.
- Habilita el log_slow_queries y échale un ojo de vez en cuando :) MySQL 5.0 solo permite especificar segundos para definir una query lenta, debes aplicar parche o pasarte a MySQL 5.1 para poder hacerlo en milisegundos.
- Habilitar log-queries-not-using-indexes no es recomendable. Que no tengan índices no quiere decir que tengan que ser lentas. Un “select count(*) from t” no usa índices y en MyISAM el resultado es instantaneo. Habilitarlo solo aumentará el I/O.
- Si en una misma conexión tienes que escribir en dos BBDD distintas, cambiate primero de una a otra con USE. No seas cerdete y hagas “INSERT INTO db.t”. Eso no se lleva muy bien con los logs binarios y la replicación.
- En replicaciones con poca carga (0 segundos en master behind) si esta se rompe es muy posiblemente culpa tuya, no de la replicación en si.
- A no ser que lo necesites de verdad no actives el log de todas las querys (con la opción “log”). Se escriben todas las sentencias ejecutadas, select incluidas, incluso aunque estas no se terminen commiteando. Además, te terminarás quedando sin disco duro sin contar el I/O que consume.
- Si tienes que borrar gran cantidad de datos cada X tiempo, no hagas un “DELETE from” ya que tardará infinito. Planteate hacer uso de particiones o tablas MERGE de forma que puedas borrarlas de golpe en lugar de fila a fila.
- No uses subquerys. Y si las has estado utilizando, reescribelas como JOIN. El rendimiento es mucho mejor.
- Si tienes que hacer un cambio de schema en una tabla muy grande hazlo por la noche. Un alter table te bloqueará toda la tabla para lecturas/escrituras.
- MySQL tiene un Query Profiler. Úsalo y no vayas siempre llorando al Sysadmin.
Usando MySQL con Python
Últimamente me ha dado por aprender Python o al menos intentarlo. Nunca me ha gustado la programación y cada vez que leía orientación a objetos terminaba dejándolo por puro aburrimiento. Espero que esta ocasión sea diferente :) Lo mejor que le veo a Python es su sintaxis sencilla y la cantidad brutal de módulos que podemos usar para hacernos la vida más facil.
En este simple ejemplo mostraré como acceder a MySQL y hacer querys, facil y para toda la familia. El primer requisito es tener MySQLdb instalado.
apt-get install python-mysqldb
El código es muy sencillo. Asociamos una conexión con un cursor y realizamos las querys contra el.
import MySQLdb db=MySQLdb.connect(unix_socket="/tmp/mysql_sandbox5140.sock", user="root", passwd="msandbox",db="information_schema") h=0 cursor=db.cursor() sql="SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_DESCRIPTION from plugins;" cursor.execute(sql) for n in cursor.fetchall(): if n[0]=="InnoDB": print "La BBDD tiene soporte para InnoDB" h=1 if h == 0: print "La BBDD no tiene soporte para InnoDB"
Con este simple script comprobamos si nuestro MySQL dispone de soporte para InnoDB.
Me gustaría aprender Python realizando alguna aplicación para MySQL, pero la verdad es que no se me ocurre nada útil. Si alguien tiene alguna idea me gustaría escucharla :)
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 :)
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!



