Posts tagged with “labs”
Pre-cachear los datos de InnoDB en el buffer pool
Cuando tienes un entorno activo-pasivo o montas un esclavo para las lecturas, el mayor problema que te puedes encontrar al poner los nuevos servidores en producción es que las cachés se encuentren frias (cold cache). Como dichos servidores no han recibido consultas, todas sus cachés, como query cache o innodb_buffer_pool se encuentran vacias y todas las consultas tendrán que ir a disco duro durante los primeros minutos u horas. En esos primeros instantes, el rendimiento de tu backend será pésimo.
Hasta ahora, para evitar en la medida de lo posible ese problema, se lanzaban SELECT contra las tablas que obligasen a leerse todas las filas. Eran consultas muy pesadas que tardaban mucho tiempo en ejecutarse y ralentizaban aún más el rendimiento, pero... no había otra solución. Un ejemplo de está solución se puede leer en el blog de Santi Saez Woop!. Pero esto ya ha cambiado.
En la versión de desarrollo de MySQL 5.6 ya es posible guardar el estado actual del buffer pool en un fichero y recuperarlo en memoria después del reinicio del servicio. No más esperas ni trucos de scripting, ahora hablamos de un procedimiento nativo dentro del propio servicio.
Lanzar un dump del buffer pool:
mysql> SET innodb_buffer_pool_dump_now=ON;
Configurar un dump cuando se realice el apagado del servicio:
mysql> SET innodb_buffer_pool_dump_at_shutdown=ON;
Recuperar un dump en memoria:
mysql> SET innodb_buffer_pool_load_now=ON;
Y en my.cnf podemos poner esta línea, para que se cargue automáticamente durante el arranque del servicio:
innodb_buffer_pool_load_at_startup=ON
Podemos ver el progreso del dump:
mysql> SHOW STATUS LIKE 'innodb_buffer_pool_dump_status';
Y el progreso de la restauración:
mysql> SHOW STATUS LIKE 'innodb_buffer_pool_load_status';
Así como cancelarlo :)
mysql> SET innodb_buffer_pool_load_abort=ON;
Es importante recalcar que si estás utilizando Percona Server, su engine xtradb dispone también de esta funcionalidad, por lo que no tienes que esperar. Simplemente, los comandos cambian:
Lanzar un dump del buffer pool:
mysql> select * from information_schema.XTRADB_ADMIN_COMMAND /*!XTRA_LRU_DUMP*/;
Recuperar un dump en memoria:
mysql> select * from information_schema.XTRADB_ADMIN_COMMAND /*!XTRA_LRU_RESTORE*/;
Programar un dump cada X segundos:
innodb_auto_lru_dump = X
Cargar automáticamente el dump en el arranque:
innodb_buffer_pool_restore_at_startup=1
Replicación con Multi-Threaded Slaves, sacando uso a nuestros cores
Ahora mismo, todos los servidores que compramos son multi-core o multi-cpu. MySQL ha ido solucionando sus problemas de escalabilidad, sobre todo a nivel del engine InnoDB, y la diferencia es clara entre MySQL 5.0 y MySQL 5.5, donde el rendimiento en entornos multicore es cada vez mayor. Pero aún queda un punto por mejorar, la replicación de MySQL.
En una replicación MySQL Master/Slave el problema se puede ver claramente. Mientras que en el maestro puedes tener cientos de threads modificando datos en paralelo, estos se escriben de forma ordenada en el binlog mientras que el slave, que solo tiene un thread para aplicar los cambios (SQL Thread), tiene que escribir los cambios uno a uno. De esta forma, el rendimiento que ganamos con la paralelización de las consultas, se pierden al llegar al Slave. Razón por la cual en entornos de alta carga siempre vemos que el esclavo va muy por detrás del Master aplicando los cambios (Seconds Behind Master).
Este es un problema que se está intentando solucionar en las versiones de desarrollo de MySQL. En la versión 5.6 se ha introducido un nuevo concepto llamado Workers, que son diferentes SQL Threads para la aplicación en paralelo de los cambios.

Podemos descargar una versión de desarrollo con esta funcionalidad desde http://labs.mysql.com/.
Con una serie nueva de parámetros que veremos a continuación podemos decirle a nuestro Slave cuantos Workers debe lanzar. Cada Worker podrá escribir los cambios del relaylog en paralelo, siempre y cuando pertenezcan a diferentes bases de datos. Por lo que de momento, para poder sacar beneficio a esta nueva funcionalidad, deberás tener diferentes bases de datos, cosa que es bastante habitual en entornos complejos donde el Sharding es la norma a seguir.
En primer lugar, debemos decirle a nuestro MySQL que ahora algunos de los estados relacionados con la replicación la queremos guardar en base de datos, concretamente en tablas dentro de la BD mysql:
relay-log-info-repository="TABLE" master-info-repository="TABLE"
relay-log-info-repository: esta variable indica donde se guardará la posición en la que nos encontramos dentro del relay log master-info-repository: esta variable indica donde se guardará la información referente a su master
Todas las opciones se encuentran ya documentadas en http://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html. Es recomendable tener esta URL a mano, ya que al ser algo que se encuentra en desarrollo, las especificaciones y las opciones cambian constantemente.
Una vez hecho, nos conectamos al Slave y le decimos que queremos cuatro Workers.
mysql> STOP SLAVE; Query OK, 0 rows affected (0.00 sec) mysql> SET GLOBAL slave_parallel_workers=4; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@slave_parallel_workers; +------------------------------+ | @@slave_parallel_workers | +------------------------------+ | 4 | +------------------------------+ 1 row in set (0.00 sec) mysql> START SLAVE; Query OK, 0 rows affected (0.05 sec)
A continuación comprobamos si realmente se han lanzado los 4 procesos:
mysql> show processlist; +----+-------------+------+---------+------+---------------------------------------------+ | Id | User | db | Command | Time | State | +----+-------------+------+---------+------+---------------------------------------------+ | 1 | root | NULL | Query | 0 | init | | 8 | system user | NULL | Connect | 2 | Waiting for master to send event | | 9 | system user | NULL | Connect | 2 | Slave has read all relay log; waiting [...] | | 10 | system user | NULL | Connect | 2 | Waiting for an event from sql thread | | 11 | system user | NULL | Connect | 2 | Waiting for an event from sql thread | | 12 | system user | NULL | Connect | 2 | Waiting for an event from sql thread | | 13 | system user | NULL | Connect | 2 | Waiting for an event from sql thread | +----+-------------+------+---------+------+---------------------------------------------+ 7 rows in set (0.00 sec)
Ahora mismo ya tenemos cuatro threads SQL para la aplicación de datos en paralelo. Como hemos comentado anteriormente, es posible aplicar cambios en paralelo siempre que estos sean de bases de datos diferentes. Por lo no tiene sentido que el número de threads que lancemos sea superior al del número de bases de datos que queremos replicar.
Esta es solo una más de las múltiples mejoras que se están implantando en la rama de desarrollo, intentaré manteneros informados de todas las novedades interesantes que sigan surgiendo :)







