sql >> Base de Datos >  >> RDS >> Mysql

Cómo fallar o bloquear sus instancias de MySQL para la prueba

Puede eliminar una base de datos MySQL de varias maneras. Algunas formas obvias son apagar el host, desconectar el cable de alimentación o eliminar el proceso mysqld con SIGKILL para simular un comportamiento de apagado impuro de MySQL. Pero también hay formas menos sutiles de bloquear deliberadamente su servidor MySQL y luego ver qué tipo de reacción en cadena desencadena. Por qué querrías hacer esto? La falla y la recuperación pueden tener muchos casos de esquina, y comprenderlos puede ayudar a reducir el elemento de sorpresa cuando suceden cosas en la producción. Idealmente, desearía simular fallas en un entorno controlado y luego diseñar y probar los procedimientos de conmutación por error de la base de datos.

Hay varias áreas en MySQL que podemos abordar, dependiendo de cómo desee que falle o se bloquee. Puede corromper el tablespace, desbordar los búferes y cachés de MySQL, limitar los recursos para privar al servidor y también perder el tiempo con los permisos. En esta publicación de blog, le mostraremos algunos ejemplos de cómo bloquear un servidor MySQL en un entorno Linux. Algunos de ellos serían adecuados para, p. Instancias de Amazon RDS, donde no tendría acceso al host subyacente.

Matar, matar, matar, morir, morir, morir

La forma más fácil de fallar en un servidor MySQL es simplemente matar el proceso o el host, y no darle a MySQL la oportunidad de hacer un apagado correcto. Para simular un bloqueo de mysqld, simplemente envíe la señal 4, 6, 7, 8 u 11 al proceso:

$ kill -11 $(pidof mysqld)

Al mirar el registro de errores de MySQL, puede ver las siguientes líneas:

11:06:09 UTC - mysqld got signal 11 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
Attempting to collect some information that could help diagnose the problem.
As this is a crash and something is definitely wrong, the information
collection process might fail.
..
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...

También puede usar kill -9 (SIGKILL) para terminar el proceso inmediatamente. Puede encontrar más detalles sobre la señal de Linux aquí. Alternativamente, puede usar una forma más cruel en el lado del hardware, como desconectar el cable de alimentación, presionar el botón de restablecimiento completo o usar un dispositivo de cerca para STONITH.

Activación de OOM

Las ofertas populares de MySQL en la nube como Amazon RDS y Google Cloud SQL no tienen una forma sencilla de bloquearlas. En primer lugar, porque no obtendrá ningún acceso a nivel de sistema operativo a la instancia de la base de datos y, en segundo lugar, porque el proveedor utiliza un servidor MySQL parcheado patentado. Una forma es desbordar algunos búferes y dejar que el administrador de memoria insuficiente (OOM) elimine el proceso de MySQL.

Puede aumentar el tamaño del búfer de clasificación a algo más grande que lo que la RAM puede manejar, y disparar una serie de consultas de clasificación mysql contra el servidor MySQL. Vamos a crear una tabla de 10 millones de filas usando sysbench en nuestra instancia de Amazon RDS, para que podamos construir una ordenación enorme:

$ sysbench \
--db-driver=mysql \
--oltp-table-size=10000000 \
--oltp-tables-count=1 \
--threads=1 \
--mysql-host=dbtest.cdw9q2wnb00s.ap-tokyo-1.rds.amazonaws.com \
--mysql-port=3306 \
--mysql-user=rdsroot \
--mysql-password=password \
/usr/share/sysbench/tests/include/oltp_legacy/parallel_prepare.lua \
run

Cambiar el sort_buffer_size a 5G (nuestra instancia de prueba es db.t2.micro - 1GB, 1vCPU) yendo a Amazon RDS Dashboard -> Grupos de parámetros -> Crear grupo de parámetros -> especificar el nombre del grupo -> Editar parámetros -> elegir "sort_buffer_size" y especificar el valor como 5368709120.

Aplique los cambios del grupo de parámetros yendo a Instancias -> Acción de instancia -> Modificar -> Opciones de base de datos -> Grupo de parámetros de base de datos -> y elija nuestro grupo de parámetros recién creado. Luego, reinicie la instancia de RDS para aplicar los cambios.

Una vez arriba, verifique el nuevo valor de sort_buffer_size :

MySQL [(none)]> select @@sort_buffer_size;
+--------------------+
| @@sort_buffer_size |
+--------------------+
|         5368709120 |
+--------------------+

Luego active 48 consultas simples que requieren clasificación de un cliente:

$ for i in {1..48}; do (mysql -urdsroot -ppassword -h dbtest.cdw9q2wnb00s.ap-tokyo-1.rds.amazonaws.com -e 'SELECT * FROM sbtest.sbtest1 ORDER BY c DESC >/dev/null &); done

Si ejecuta lo anterior en un host estándar, notará que el servidor MySQL se cerrará y podrá ver que aparecen las siguientes líneas en el syslog o dmesg del sistema operativo:

[164199.868060] Out of memory: Kill process 47060 (mysqld) score 847 or sacrifice child
[164199.868109] Killed process 47060 (mysqld) total-vm:265264964kB, anon-rss:3257400kB, file-rss:0kB

Con systemd, MySQL o MariaDB se reiniciarán automáticamente, al igual que Amazon RDS. Puede ver que el tiempo de actividad de nuestra instancia de RDS se restablecerá a 0 (en el estado de mysqladmin) y el valor de 'Último tiempo de restauración' (en el Panel de RDS) se actualizará al momento en que se cayó.

Corrupción de los datos

InnoDB tiene su propio espacio de tablas del sistema para almacenar diccionarios de datos, búferes y segmentos de reversión dentro de un archivo llamado ibdata1. También almacena el tablespace compartido si no configura innodb_file_per_table (habilitado de forma predeterminada en MySQL 5.6.6+). Podemos poner a cero este archivo, enviar una operación de escritura y vaciar tablas para bloquear mysqld:

# empty ibdata1
$ cat /dev/null > /var/lib/mysql/ibdata1
# send a write
$ mysql -uroot -p -e 'CREATE TABLE sbtest.test (id INT)'
# flush tables
$ mysql -uroot -p -e 'FLUSH TABLES WITH READ LOCK; UNLOCK TABLES'

Después de enviar una escritura, en el registro de errores, notará:

2017-11-15T06:01:59.345316Z 0 [ERROR] InnoDB: Tried to read 16384 bytes at offset 98304, but was only able to read 0
2017-11-15T06:01:59.345332Z 0 [ERROR] InnoDB: File (unknown): 'read' returned OS error 0. Cannot continue operation
2017-11-15T06:01:59.345343Z 0 [ERROR] InnoDB: Cannot continue operation.

En este punto, mysql se colgará porque no puede realizar ninguna operación, y después del lavado, obtendrá líneas "mysqld got signal 11" y mysqld se cerrará. Para limpiar, debe eliminar el ibdata1 dañado, así como ib_logfile* porque los archivos de registro de rehacer no se pueden usar con un nuevo espacio de tablas del sistema que mysqld generará en el próximo reinicio. Se espera pérdida de datos.

Para las tablas MyISAM, podemos jugar con .MYD (archivo de datos MyISAM) y .MYI (índice MyISAM) en el directorio de datos MySQL. Por ejemplo, el siguiente comando reemplaza cualquier ocurrencia de la cadena "F" con "9" dentro de un archivo:

$ replace F 9 -- /var/lib/mysql/sbtest/sbtest1.MYD

Luego, envíe algunas escrituras (por ejemplo, usando sysbench) a la tabla de destino y realice el vaciado:

mysql> FLUSH TABLE sbtest.sbtest1;

Lo siguiente debería aparecer en el registro de errores de MySQL:

2017-11-15T06:56:15.021564Z 448 [ERROR] /usr/sbin/mysqld: Incorrect key file for table './sbtest/sbtest1.MYI'; try to repair it
2017-11-15T06:56:15.021572Z 448 [ERROR] Got an error from thread_id=448, /export/home/pb2/build/sb_0-24964902-1505318733.42/rpm/BUILD/mysql-5.7.20/mysql-5.7.20/storage/myisam/mi_update.c:227

La tabla MyISAM se marcará como bloqueada y es necesario ejecutar la instrucción REPAIR TABLE para que vuelva a estar accesible.

Limitación de los recursos

También podemos aplicar el límite de recursos del sistema operativo a nuestro proceso mysqld, por ejemplo, el número de descriptores de archivos abiertos. El uso de la variable open_file_limit (el valor predeterminado es 5000) permite que mysqld reserve descriptores de archivos mediante el comando setrlimit(). Puede configurar esta variable relativamente pequeña (lo suficiente para que mysqld se inicie) y luego enviar varias consultas al servidor MySQL hasta que alcance el límite.

Si mysqld se está ejecutando en un servidor systemd, podemos configurarlo en el archivo de la unidad systemd ubicado en /usr/lib/systemd/system/mysqld.service, y cambiar el siguiente valor a algo más bajo (el valor predeterminado de systemd es 6000):

# Sets open_files_limit
LimitNOFILE = 30

Aplique los cambios a systemd y reinicie el servidor MySQL:

$ systemctl daemon-reload
$ systemctl restart mysqld

Luego, comience a enviar nuevas conexiones/consultas que cuentan en diferentes bases de datos y tablas, por lo que mysqld tiene que abrir varios archivos. Notará el siguiente error:

2017-11-16T04:43:26.179295Z 4 [ERROR] InnoDB: Operating system error number 24 in a file operation.
2017-11-16T04:43:26.179342Z 4 [ERROR] InnoDB: Error number 24 means 'Too many open files'
2017-11-16T04:43:26.179354Z 4 [Note] InnoDB: Some operating system error numbers are described at http://dev.mysql.com/doc/refman/5.7/en/operating-system-error-codes.html
2017-11-16T04:43:26.179363Z 4 [ERROR] InnoDB: File ./sbtest/sbtest9.ibd: 'open' returned OS error 124. Cannot continue operation
2017-11-16T04:43:26.179371Z 4 [ERROR] InnoDB: Cannot continue operation.
2017-11-16T04:43:26.372605Z 0 [Note] InnoDB: FTS optimize thread exiting.
2017-11-16T04:45:06.816056Z 4 [Warning] InnoDB: 3 threads created by InnoDB had not exited at shutdown!

En este punto, cuando se alcance el límite, MySQL se congelará y no podrá realizar ninguna operación. Al intentar conectarse, verá lo siguiente después de un tiempo:

$ mysql -uroot -p
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104

Error con los permisos

El proceso mysqld lo ejecuta el usuario "mysql", lo que significa que todos los archivos y directorios a los que necesita acceder son propiedad del usuario/grupo mysql. Al estropear el permiso y la propiedad, podemos hacer que el servidor MySQL sea inútil:

$ chown root:root /var/lib/mysql
$ chmod 600 /var/lib/mysql

Genere algunas cargas en el servidor y luego conéctese al servidor MySQL y vacíe todas las tablas en el disco:

mysql> FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;

En este momento, mysqld todavía se está ejecutando pero es un poco inútil. Puede acceder a él a través de un cliente mysql pero no puede realizar ninguna operación:

mysql> SHOW DATABASES;
ERROR 1018 (HY000): Can't read dir of '.' (errno: 13 - Permission denied)

Para limpiar el desorden, establezca los permisos correctos:

$ chown mysql:mysql /var/lib/mysql
$ chmod 750 /var/lib/mysql
$ systemctl restart mysqld

Bloquearlo

FLUSH TABLE CON READ LOCK (FTWRL) puede ser destructivo en varias condiciones. Como, por ejemplo, en un clúster de Galera donde todos los nodos pueden procesar escrituras, puede usar esta declaración para bloquear el clúster desde dentro de uno de los nodos. Esta declaración simplemente detiene otras consultas para que sean procesadas por mysqld durante el vaciado hasta que se libera el bloqueo, lo cual es muy útil para los procesos de copia de seguridad (tablas MyISAM) y las instantáneas del sistema de archivos.

Si bien esta acción no bloqueará ni deshabilitará su servidor de base de datos durante el bloqueo, la consecuencia puede ser enorme si la sesión que mantiene el bloqueo no lo libera. Para probar esto, simplemente:

mysql> FLUSH TABLES WITH READ LOCK;
mysql> exit

Luego envíe un montón de consultas nuevas a mysqld hasta que alcance las max_connections valor. Obviamente, no puede volver a la misma sesión que la anterior una vez que esté fuera. Entonces, el bloqueo se ejecutará infinitamente y la única forma de liberar el bloqueo es eliminar la consulta, por otro usuario con SUPER privilegios (usando otra sesión). O elimine el proceso mysqld en sí mismo, o realice un reinicio completo.

Descargo de responsabilidad

Este blog está escrito para brindar alternativas a los administradores de sistemas y administradores de bases de datos para simular escenarios de falla con MySQL. No intente esto en su servidor de producción :-)