¿Ha estado experimentando tiempos lentos de inicio de MySQL en modo GTID? Recientemente nos encontramos con este problema en una de nuestras implementaciones de alojamiento de MySQL y nos dispusimos a resolver el problema. En este blog, desglosamos el problema que podría estar ralentizando los tiempos de reinicio de MySQL, cómo depurar para su implementación y qué puede hacer para reducir el tiempo de inicio y mejorar su comprensión de la replicación basada en GTID.
Cómo encontramos el problema
Estábamos investigando los tiempos lentos de inicio de MySQL en una implementación de MySQL 5.7.21 basada en disco de gama baja que tenía habilitado el modo GTID. El sistema formaba parte de un par maestro-esclavo y estaba bajo una carga de escritura moderada. Al reiniciar durante un mantenimiento programado, notamos que el servidor de la base de datos tardó entre 5 y 10 minutos en iniciarse y comenzar a aceptar conexiones. Ese tipo de retraso no tenía sentido, así que nos dispusimos a investigar.
Depuración de la hora de inicio lenta de MySQL
Utilizamos la popular herramienta pt-ioprofile de Percona para ver qué estaba haciendo la base de datos. perfil-pt-io es una utilidad muy importante en el popular conjunto de herramientas de Percona que se usa para depurar problemas de MySQL, y puede ver la lista completa de funciones en su documentación. El perfil-pt-io la herramienta usa strace y lsof para ver la E/S de un proceso e imprimir una tabla de archivos y actividad de E/S.
Entonces, comenzamos MySQL, esperamos el mysqld proceso para generar e iniciar pt-ioprofile para ver cuál podría ser el problema:
# pt-ioprofile --profile-process mysqld --run-time 200 Tue Oct 9 15:42:24 UTC 2018 Tracing process ID 18677 total pread read pwrite write fsync fdatasync open close getdents lseek fcntl filename ... 216.550641 0.000000 216.550565 0.000000 0.000000 0.000000 0.000000 0.000015 0.000040 0.000000 0.000021 0.000000 /mysql_data/binlogs/mysql-bin.000014 ...
¿Qué está ralentizando el reinicio de MySQL?
Al ejecutar esto varias veces, observamos lo siguiente:
- El mysqld El proceso pasaba la mayor parte de su tiempo leyendo el archivo de registro binario más reciente. Este fue el caso incluso cuando el servidor se había detenido correctamente y no había necesidad de una recuperación tras bloqueo, etc.
- El servidor también dedicó una cantidad considerable de tiempo a cargar los archivos de datos de InnoDB, pero ese tiempo fue mucho menor en comparación con el tiempo dedicado a leer el archivo de registro binario más reciente.
- Si el servidor se reiniciara inmediatamente, este reinicio posterior sería mucho más rápido.
- Dado que el cierre de una base de datos vacía el registro binario y crea uno nuevo al inicio, hicimos un experimento adicional:antes de apagar el servidor, limpiamos los registros binarios. El inicio posterior del servidor fue rápido nuevamente.
Estas observaciones apuntaban claramente al hecho de que MySQL pasaba mucho tiempo leyendo el archivo de registro binario más reciente. Si el archivo era pequeño, como lo sería cuando se vació el archivo de registro antes de apagarlo, el inicio fue rápido.
¿Tiempo de inicio lento de MySQL en GTID? El tamaño de su archivo de registro binario puede ser el problemaHaga clic para twittear
Comprender la recuperación de Binlog GTID
Resulta que, para completar los valores de gtid_executed y gtid_purged, el servidor MySQL debe analizar los archivos de registro binarios.
Este es el resumen de la recomendación del método de documentación de MySQL 5.7 basado en una lectura FALSA o VERDADERA:
Cuando binlog_gtid_simple_recovery =FALSO:
Para calcular gtid_ejecutado:
- Itera archivos de registro binarios desde el más reciente, deteniéndose en el primer archivo que tiene un evento Previous_gtids_log_event entrada.
- Consumir todos los GTID de Previous_gtids_log_event y Gtid_log_events de este archivo de registro binario y almacene este conjunto de GTID internamente. Se denomina gtids_in_binlog.
- Valor de gtid_ejecutado se calcula como la unión de gtids_in_binlog y los GTID en la tabla mysql.gtid_executed .
Este proceso puede llevar mucho tiempo si hay una gran cantidad de archivos de registro binarios sin GTID, por ejemplo, creados cuando gtid_mode =DESACTIVADO.
Del mismo modo, para calcular gtid_purged:
- Itera los archivos de registro binario desde el más antiguo al más nuevo, deteniéndose en el primer registro binario que contiene un Previous_gtids_log_event no vacío. (tiene al menos un GTID), o que tiene al menos un Gtid_log_event .
- Leer Previous_gtids_log_event de este archivo. Calcule la variable interna gtids_in_binlog_not_purged como este conjunto de GTID restado de gtids_in_binlog.
- Valor de gtid_purged está establecido en gtid_ejecutado , menos gtids_in_binlog_not_purged .
Entonces, esto forma la base de nuestra comprensión de cómo solían funcionar las cosas en versiones anteriores. Sin embargo, se pueden realizar ciertas optimizaciones cuando binlog_gtid_simple_recovery es verdad. Este es el caso que nos interesa:
Cuando binlog_gtid_simple_recovery =VERDADERO:
(Nota, este es el valor predeterminado en MySQL 5.7.7 y versiones posteriores)
- Lee solo los archivos de registro binarios más antiguos y más nuevos.
- Calcular gtid_purged del Previous_gtids_log_event o Gtid_log_event encontrado en el archivo de registro binario más antiguo.
- Calcular gtid_ejecutado del Previous_gtids_log_event o Gtid_log_event encontrado en el archivo de registro binario más reciente.
- Por lo tanto, solo dos archivos de registro binarios se leen durante el reinicio del servidor o al purgar los registros binarios.
Por lo tanto, para las versiones de MySQL 5.7.7 y superiores, los archivos de registro binarios más recientes y antiguos siempre se leen durante el inicio del sistema para inicializar correctamente las variables del sistema GTID. Leer el archivo de registro binario más antiguo no es tan costoso ya que el evento que busca MySQL, Previous_gtids_log_event, siempre es el primer evento en un archivo de registro binario.
Sin embargo, para calcular correctamente gtid_ejecutado , el servidor debe leer todo el archivo de registro binario más reciente y recopilar todos los eventos en ese archivo. Entonces, el tiempo de inicio del sistema se vuelve directamente proporcional al tamaño del archivo de registro binario más reciente .
Tenga en cuenta que la situación es aún peor cuando binlog_gtid_simple_recovery es FALSO . Dado que ya no es la opción predeterminada en versiones recientes, no es una gran preocupación.
Cómo resolver su tiempo de inicio lento
Habiendo entendido la causa del problema con el que nos encontrábamos, la solución que decidimos fue bastante obvia:reducir el tamaño de los archivos de registro binarios. El tamaño predeterminado de los archivos de registro binarios es de 1 GB. Lleva tiempo analizar un archivo de este tamaño durante el inicio, por lo que tiene sentido disminuir el valor de max_binlog_size a un valor más bajo.
Si reducir el tamaño del archivo de registro binario no es una opción, puede ser útil vaciar los archivos de registro binarios justo antes de un cierre de mantenimiento del proceso mysqld para disminuir los tiempos de recuperación binlog GTID.