
El progreso no se detiene, por lo que las razones para actualizar a las versiones actuales de MySQL son cada vez más convincentes. No hace mucho tiempo, en uno de nuestros proyectos llegó el momento de actualizar los cómodos clústeres de Percona Server 5.7 a la versión 8. Todo esto se realizó en la plataforma Ubuntu Linux 16.04. Cómo llevar a cabo dicha operación con un tiempo de inactividad mínimo y con qué problemas nos encontramos durante la actualización — léelo en este artículo.
Preparación
Cualquier actualización del servidor de bases de datos probablemente esté relacionada con la reconfiguración de la base: cambios en los requisitos de recursos del sistema y la corrección de las configuraciones de la base deben eliminar las directivas obsoletas.
Antes de actualizar, nos referiremos a la documentación oficial:
- ;
- ;
- ;
- .
Y elaboraremos un plan de acción:
- Corregir los archivos de configuración, eliminando directivas obsoletas.
- Verificar la compatibilidad con utilidades.
- Actualizar las bases de datos esclavas, instalando el paquete
percona-server-server. - Actualizar el maestro, instalando el mismo paquete.
Analizaremos cada punto del plan y veremos qué podría salir mal.
¡IMPORTANTE! El procedimiento de actualización de un clúster MySQL basado en Galera tiene sus propias sutilezas, que no se describen en este artículo. No se debe utilizar esta instrucción en tal caso.
Parte 1: Verificación de configuraciones
En la versión 8 de MySQL se eliminó query_cache. En realidad, fue ya en la versión 5.7, pero ahora también . Por ende, es necesario eliminar las directivas relacionadas. Ahora, para la caché de consultas, se pueden utilizar herramientas externas — por ejemplo, .
También en la configuración se encontraron directivas obsoletas sobre innodb_file_format. Si en MySQL 5.7 había la opción de elegir el formato de InnoDB, en la versión 8 ya funciona .
Nuestro resultado — la eliminación de las siguientes directivas:
-
query_cache_type,query_cache_limityquery_cache_size; -
innodb_file_formatyinnodb_file_format_max.
Para la verificación, utilizaremos la imagen de Docker de Percona Server. Colocaremos la configuración del servidor en el directorio mysql_config_test, y al lado crearemos directorios para los datos y los registros. Ejemplo de prueba de configuración de percona-server:
mkdir -p {mysql_config_test,mysql_data,mysql_logs}
cp -r /etc/mysql/conf.d/* mysql_config_test/
docker run --name some-percona -v $(pwd)/mysql_config_test:/etc/my.cnf.d/ -v $(pwd)/mysql_data/:/var/lib/mysql/ -v $(pwd)/mysql_logs/:/var/log/mysql/ -e MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} -d percona:8-centosConclusión: o en los registros de Docker, o en el directorio con los registros, dependiendo de tu configuración, aparecerá un archivo que describirá las directivas problemáticas.
Esto es lo que tuvimos:
2020-04-03T12:44:19.670831Z 0 [Advertencia] [MY-011068] [Servidor] La sintaxis 'expire-logs-days' está obsoleta y se eliminará en una futura versión. Por favor, usa binlog_expire_logs_seconds en su lugar.
2020-04-03T12:44:19.671678Z 0 [Advertencia] [MY-013242] [Servidor] --character-set-server: 'utf8' es actualmente un alias para el conjunto de caracteres UTF8MB3, pero será un alias para UTF8MB4 en una futura versión. Considera usar UTF8MB4 para ser claro.
2020-04-03T12:44:19.671682Z 0 [Advertencia] [MY-013244] [Servidor] --collation-server: 'utf8_general_ci' es una colación del conjunto de caracteres obsoleto UTF8MB3. Considera usar UTF8MB4 con una colación apropiada en su lugar. Por lo tanto, necesitábamos resolver las codificaciones y reemplazar la directiva obsoleta expire-logs-days.
Parte 2: Comprobación de instalaciones en funcionamiento
En la documentación de actualización hay 2 utilidades para verificar la base de datos por compatibilidad. Su uso ayuda al administrador a comprobar la compatibilidad de la estructura de datos existente.
Comencemos con la clásica utilidad mysqlcheck. Es suficiente con ejecutarla:
mysqlcheck -u root -p --all-databases --check-upgradeSi no se detectan problemas, la utilidad finalizará con el código 0:

Además, en las versiones modernas de MySQL está disponible la utilidad (en el caso de Percona es el paquete percona-mysql-shell). Es un reemplazo del clásico cliente mysql y combina las funciones de cliente, editor de código SQL y herramientas de administración de MySQL. Para comprobar el servidor antes de actualizar, se puede ejecutar el siguiente comando a través de ella:
mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=\/etc\/mysql\/my.cnfY aquí están los comentarios que recibimos:

En general, nada crítico, solo advertencias sobre las codificaciones. (ver más abajo)El resultado general de la ejecución:

Decidimos que la actualización debería ir sin problemas.
Observación sobre las advertencias mencionadas anteriormente, que indican problemas con las codificaciones. El hecho es que UTF-8 en MySQL hasta hace poco , ya que almacenaba solo 3 bytes en lugar de 4. En MySQL 8 finalmente : el alias utf8 pronto se dirigirá al conjunto de caracteres utf8mb4, y las antiguas columnas en las tablas se convertirán en utf8mb3.En el futuro, el conjunto de caracteres utf8mb3. será eliminado, pero no en esta versión. Por lo tanto, decidimos corregir las codificaciones ya en la instalación de la base de datos en funcionamiento, después de su actualización.
Parte 3: Actualización de servidores
¿Qué podría salir mal cuando hay un plan tan excelente?.. Comprendiendo perfectamente que siempre ocurren matices, realizamos el primer experimento en el clúster de desarrollo de MySQL.
Como ya se mencionó, aborda la cuestión de la actualización de servidores MySQL con réplicas. La esencia se reduce a que primero se deben actualizar todas las réplicas (slave), ya que MySQL 8 puede replicarse desde un maestro de la versión 5.7. Algunas dificultades radican en que utilizamos el modo master master, donde el máster remoto está en modo read-only. Es decir, el tráfico de producción llega a un centro de datos, mientras que el segundo es de respaldo.
La topología es la siguiente:

La actualización debe comenzar con las réplicas mysql replica dc 2, mysql master dc 2 y mysql replica dc 1, y finalizar con el servidor mysql master dc 1. Para mayor seguridad, detuvimos las máquinas virtuales, hicimos sus instantáneas y justo antes de la actualización detuvimos la replicación con el comando STOP SLAVE. En el resto, la actualización se ve así:
- Reiniciamos cada réplica, añadiendo 3 opciones a las configuraciones:
skip-networking,skip-slave-start,skip-log-bin. El hecho es que la actualización de la base genera registros binarios con la actualización de las tablas del sistema. Estas directivas garantizan que no habrá cambios en los datos de la aplicación en la base y que la información sobre la actualización de las tablas del sistema no se registrará en los registros binarios. Esto ayudará a evitar problemas al reanudar la replicación. - Instalamos el paquete
percona-server-server. Es importante señalar que en la versión MySQL 8 no es necesario ejecutar el comandomysqlupgradedespués de actualizar el servidor. - Después de un inicio exitoso, reiniciamos el servidor nuevamente, ya sin los parámetros que se añadieron en el primer punto.
- Nos aseguramos de que la replicación funcione correctamente: verificamos
SHOW SLAVE STATUSy observamos que se actualizan las tablas con los contadores en la base de la aplicación.
Todo esto se ve bastante sencillo: la actualización de dev fue exitosa. Bien, podemos planificar la actualización nocturna para producción con tranquilidad.
No hubo tristeza: prod actualizamos
Sin embargo, trasladar la experiencia exitosa de dev a producción no estuvo exento de sorpresas.
Afortunadamente, el proceso de actualización comienza con las réplicas, por lo que, al encontrar dificultades, detuvimos los trabajos y restauramos la réplica desde la instantánea. La investigación de los problemas se trasladó a la mañana siguiente. En los registros aparecieron las siguientes entradas:
2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] la tabla: t1 tiene 19 columnas pero el diccionario de InnoDB tiene 20 columnas
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Servidor] Error al corregir los datos de SE para db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Servidor] Falló al poblar las tablas de DD.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Servidor] Abortando La investigación de archivos de varios boletines en Google condujo a comprender que este problema surge debido a . Aunque probablemente sea incluso un error de las utilidades mysqlcheck y mysqlsh.
Resulta que en MySQL cambiaron la forma de representar los datos para los campos decimales (int, tinyint, etc.), así que dentro de mysql-server se utiliza otra forma de almacenamiento. Si su base de datos originalmente estaba en la versión 5.5 o 5.1, y luego actualizó a 5.7, es posible que se requiera realizar OPTIMIZE para algunas tablas. Entonces MySQL actualizará los archivos de datos, llevándolos al formato de almacenamiento actual.
Esto también se puede verificar con la utilidad mysqlfrm:
mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
'field_length': 8,
'field_type': 246, # formato del campo
'field_type_name': 'decimal',
'flags': 3,
'flags_extra': 67,
'interval_nr': 0,
'name': 'your_decimal_column',
... Si field_type si es igual a 0, entonces en la tabla se está utilizando el viejo tipo — se debe proceder con OPTIMIZE. Sin embargo, si tiene el valor 246 — ya tiene el nuevo tipo. Puede consultar más sobre los tipos en .
Además, en se considera una segunda posible causa, que nos pasó por alto, — es la ausencia de tablas InnoDB en la tabla del sistema INNODB_SYS_TABLESPACES, si dichas tablas fueron creadas en la versión 5.1. Para evitar problemas al actualizar, se puede utilizar .
¿Por qué no tuvimos tales problemas en dev? La base se copia periódicamente desde producción — así, las tablas se recrean.
Desafortunadamente, en una base de datos grande en funcionamiento, no se puede simplemente ejecutar un OPTIMIZE. Aquí ayuda percona-toolkit: para la operación online OPTIMIZE, la utilidad pt-online-schema-change es muy adecuada.
El plan actualizado se ha vuelto así:
- Realizar la optimización de todas las tablas.
- Realizar la actualización de las bases de datos.
Para verificarlo y también averiguar el tiempo de la actualización, desconectamos una de las réplicas y para todas las tablas ejecutamos el siguiente comando:
pt-online-schema-change --critical-load Threads_running=150 --alter "ENGINE=InnoDB" --execute --chunk-size 100 --quiet --alter-foreign-keys-method auto h=127.0.0.1,u=root,p=${MYSQL_PASSWORD},D=db1,t=t1La actualización de las tablas se realiza sin bloqueos prolongados gracias a que la herramienta crea una nueva tabla temporal en la que copia los datos de la tabla principal. En el momento en que ambas tablas son idénticas, se bloquea la tabla original y se sustituye por la nueva. En nuestro caso, la prueba mostró que la actualización de todas las tablas requerirá alrededor de un día, pero durante este proceso la copia de datos causó una carga excesiva en los discos.
Para evitar esto, en producción hemos agregado un argumento al comando --sleep con un valor de 10: este parámetro regula la duración de la espera después de mover un lote de datos a la nueva tabla. Esto puede reducir la carga si la aplicación en ejecución es exigente en cuanto al tiempo de respuesta.
Después de realizar la optimización, la actualización fue exitosa.
… pero no completamente.
Apenas media hora después de la actualización, el cliente llegó con un problema. La base de datos funcionaba de manera extraña: comenzaban periódicamente los reinicios de conexiones.Así es como se veía en monitoreo:

En la captura de pantalla se observa un gráfico en forma de sierra, relacionado con el hecho de que parte de los hilos del servidor MySQL caían periódicamente con un error. En la aplicación aparecieron errores:
[PDOException] SQLSTATE[HY000] [2002] Conexión rechazadaUna revisión rápida de los logs reveló que el demonio mysqld no podía obtener los recursos requeridos del sistema operativo. Al investigar los errores, descubrimos en el sistema archivos de políticas de apparmor "huérfanos".:
# dpkg -S /etc/apparmor.d/cache/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/cache/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/local/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/local/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/usr.sbin.mysqld
mysql-server-5.7: /etc/apparmor.d/usr.sbin.mysqld
# dpkg -l mysql-server-5.7
rc mysql-server-5.7 5.7.23-0ubuntu0.16.04.1 amd64Estos archivos se generaron durante la actualización a MySQL 5.7 hace un par de años y pertenecen a un paquete eliminado. La eliminación de los archivos y el reinicio del servicio apparmor resolvió el problema:
systemctl stop apparmor
rm /etc/apparmor.d/cache/usr.sbin.mysqld
rm /etc/apparmor.d/local/usr.sbin.mysqld
rm /etc/apparmor.d/usr.sbin.mysqld
systemctl start apparmorEn conclusión
Cualquier operación, incluso la más simple, puede llevar a problemas inesperados. Y tener un plan bien pensado no siempre garantiza el resultado esperado. Ahora en cualquier plan de actualización de nuestro equipo se incluye también la limpieza obligatoria de archivos innecesarios que pueden haber aparecido como resultado de acciones recientes.
Con este trabajo artístico no muy profesional, me gustaría agradecer enormemente a la empresa Percona por sus excelentes productos.

P.D.
También puedes leer en nuestro blog:
- «»;
- «»;
- «»;
- «»;
- «».
Fuente: habr.com
