Introducción
En este post vamos a ver cómo solucionar el siguiente error que nos encontramos al trabajar con bases de datos MySQL utilizando el servicio EFS de AWS para el almacenamiento:
ERROR 1030 (HY000) at line 1744: Got error 168 from storage engine
Situación de partida
Nuestro caso de uso consistía en un cluster de Kubernetes EKS, en el que necesitábamos crear y destruir nuevos entornos para desarrollo lo más rápido posible. Cada uno de estos entornos debían contener varias bases de datos MySQL, además de otras herramientas como Redis, RabbitMQ, etc.
Para ello decidimos utilizar Charts de Helm que levantasen estas herramientas como StatefulSets. En un primer momento, no especificamos ningún StorageClass, por lo que se utilizaba la de por defecto de EKS, que levanta volúmenes EBS gp2 (General Purpose SSD) al crear los PersistentVolumeClaims.
El problema de usar volúmenes EBS, es que cada volumen se encuentra disponible en una zona de disponibilidad concreta, por lo que si el cluster de Kubernetes necesita mover un pod de, por ejemplo, MySQL, no podrá levantarlo a no ser que encuentre recursos disponibles en otro nodo worker que este en la misma zona de disponibilidad que dicho volumen EBS.
Por este motivo, decidimos utilizar un nuevo StorageClass que utilizase EFS en lugar de EBS. De esta forma, teniendo el EFS montado en cada nodo worker del cluster de Kubernetes, los pods podían moverse sin ningún problema entre nodos, aunque estos estuviesen en distintas zonas de disponibilidad.
Error con EFS
Dado que nuestro caso de uso requería crear nuevos entornos de la forma mas rápida posible, al levantar una nueva base de datos MySQL, también ejecutábamos un importado de datos a partir de ficheros sql para disponer de un set de datos inicial por defecto.
Fue en este momento en el que empezamos a detectar el error, ya que al importar estos datos iniciales, empezamos a ver de forma continuada el siguiente error en los logs:
ERROR 1030 (HY000) at line 1744: Got error 168 from storage engine ERROR 1030 (HY000) at line 1744: Got error 168 from storage engine ERROR 1030 (HY000) at line 1744: Got error 168 from storage engine ...
Este error comenzaba a aparecer a partir de un determinado número de instrucciones sql ejecutadas, y a partir de ese momento, se repetía hasta terminar de leer el fichero sql.
Resolución
Tras realizar una investigación, descubrimos que el problema residía en un límite del servicio EFS. Concretamente era el límite de 256 ficheros únicos bloqueados. Podemos ver este límite en las cuotas descritas en la documentación de AWS:
https://docs.aws.amazon.com/efs/latest/ug/limits.html#limits-client-specific
Debido a que nuestro importado de datos intentaba crear más de 256 tablas, este límite se alcanzaba y comenzaba a aparecer el error. Este límite no puede modificarse, pero pudimos evitarlo modificando los parámetros de MySQL para, en la medida de lo posible, no alcanzar esos 256 ficheros bloqueados.
El parámetro MySQL a modificar es innodb_file_per_table. En nuestras bases de datos MySQL, este parámetro venía activado por defecto. Esto hace que se cree un fichero de datos .idb por cada tabla de la base de datos en lugar de crear un solo fichero de datos. Podemos modificar este parámetro en el fichero de configuración de MySQL de la siguiente forma:
[mysqld] innodb_file_per_table=OFF
https://dev.mysql.com/doc/refman/5.7/en/innodb-file-per-table-tablespaces.html
Tras desactivar este parámetro, no volvimos a encontrarnos con el error.
Queremos agradecer al blog ops.tips su trabajo realizando el post que os enlazamos, ya que nos ayudó mucho a entender este error, de forma que pudimos encontrar esta solución.
https://ops.tips/blog/limits-aws-efs-nfs-locks/
Conclusión
Al trabajar con bases de datos MySQL usando EFS para el almacenamiento, podemos encontrarnos errores al alcanzar el límite de 256 ficheros bloqueados siempre que tengamos esquemas con gran cantidad de tablas o en definitiva cualquier sistema que requiera bloquear simultáneamente grandes cantidades de ficheros como por ejemplo seria el caso de MongoDB, Oracle, etc.
Para evitar alcanzar ese límite, podemos desactivar el parámetro de MySQL innodb_file_per_table para que no se cree un fichero de datos por cada tabla.
Espero que hayas disfrutado de este post y te animo a que revises nuestro blog para leer otros posts que puedan ser de tu interés. No dudes en contactarnos si deseas que te ayudemos en tus proyectos.
¡Nos vemos en la próxima entrada!