Sorpresa fsync () PostgreSQL

Los desarrolladores de DBMS, por necesidad, están preocupados de que los datos caigan de forma segura en un almacenamiento permanente. Por lo tanto, cuando la comunidad PostgreSQL descubrió que la forma en que el núcleo maneja los errores de E / S puede conducir a la pérdida de datos sin que se informe ningún error al espacio del usuario, surgió un gran descontento. El problema, que se ve agravado por el hecho de que PostgreSQL realiza E / S con búfer, no es exclusivo de Linux y no será fácil de resolver incluso allí.

Craig Ringer informó por primera vez el problema a la lista de correo pgsql-hackers a fines de marzo. En resumen, PostgreSQL supone que una llamada fsync() exitosa indica que todos los datos grabados desde la última llamada exitosa se transfirieron de forma segura al almacenamiento persistente. Cuando falla un registro de E / S almacenado debido a un error de hardware, los sistemas de archivos reaccionan de manera diferente, pero este comportamiento generalmente implica eliminar datos en las páginas correspondientes y marcarlos como limpios. Por lo tanto, los bloques de lectura que se acaban de escribir probablemente devolverán algo más, pero no datos grabados.

¿Qué pasa con el informe de errores? Hace un año, la cumbre de Linux Filesystem, Storage and Memory-Management Summit (LSFMM) incluyó una sesión de informe de errores en la que todo se llamó un "desastre"; los errores pueden perderse fácilmente, por lo que ninguna aplicación los verá nunca. Algunos parches incluidos en 4.13 mejoraron un poco la situación durante el ciclo de desarrollo (y en 4.16 hubo algunos cambios para mejorarlo aún más), sin embargo, hay formas de perder notificaciones de error, como se describe a continuación. Si esto sucede en un servidor PostgreSQL, puede provocar daños automáticos en la base de datos.

Los desarrolladores de PostgreSQL no estaban contentos. Tom Lane describió esto como " daño cerebral al núcleo " , mientras que Robert Haas lo llamó " 100% estúpido ". Al comienzo de la discusión, los desarrolladores de PostgreSQL entendieron muy claramente cómo, en su opinión, el núcleo debería funcionar: las páginas que no podían escribirse deberían almacenarse en la memoria en un estado "sucio" (para intentos posteriores), y el descriptor de archivo correspondiente debería traducirse a Estado de error permanente para que el servidor PostgreSQL no pueda omitir el problema.

¿Dónde salió algo mal?


Sin embargo, incluso antes de que la comunidad del núcleo entrara en la discusión, quedó claro que la situación no era tan simple como podría parecer. Thomas Munro dijo que Linux no es único en este comportamiento; OpenBSD y NetBSD tampoco pueden informar errores de escritura en el espacio del usuario. Y, como resultó, la forma en que PostgreSQL maneja las operaciones de E / S almacenadas en búfer complica enormemente la imagen.

Este mecanismo ha sido descrito en detalle por Haas. Un servidor PostgreSQL funciona como un conjunto de procesos, muchos de los cuales pueden realizar E / S en archivos de base de datos. Sin embargo, el fsync() llamada fsync() se maneja en un solo proceso de puntero de verificación (proceso de "puntero de verificación"), que consiste en mantener el almacenamiento en disco en un estado consistente para recuperarse de las fallas. Checkpointer generalmente no mantiene abiertos todos los archivos relevantes, por lo que a menudo tiene que abrir el archivo antes de llamar a fsync() . Aquí es donde surge el problema: incluso en los núcleos 4.13 y versiones posteriores, el puntero de control no verá ningún error antes de que se abriera el archivo. Si sucede algo malo antes de llamar a open() checkpointer-a, la siguiente llamada a fsync() devolverá el éxito. Hay varias formas de causar un error de E / S fuera de fsync() ; por ejemplo, el kernel puede encontrar uno de ellos mientras realiza una reescritura en segundo plano. Alguien que llama a sync() también puede encontrar un error de E / S y "absorber" el estado de error resultante.

Haas describió este comportamiento como incapaz de cumplir con las expectativas de PostgreSQL:
Todo lo que usted (o alguien) tiene es básicamente una suposición no comprobada de que
qué descriptores de archivo pueden ser relevantes para un error en particular, pero sucedió que PostgreSQL nunca coincidió. Puede continuar diciendo que el problema está en nuestras conjeturas, pero me parece erróneo suponer que somos el único programa que los ha hecho.

Como resultado, Joshua Drake trasladó la conversación a la lista de desarrollo para ext4, incluida parte de la comunidad de desarrollo del kernel. Dave Chinner describió rápidamente este comportamiento como "una receta para el desastre, especialmente en el código multiplataforma, donde cada plataforma del sistema operativo se comporta de manera diferente y casi nunca coincide con lo que se esperaba ". En cambio, Ted Tso explicó por qué las páginas afectadas se marcan como limpias después de un error de E / S; en resumen, la causa más común de errores de E / S es cuando el usuario no retira la unidad USB a tiempo. Si un proceso copió una gran cantidad de datos en este disco, el resultado será la acumulación de páginas sucias en la memoria, posiblemente hasta el punto de que el sistema no tenga suficiente memoria para otras tareas. Por lo tanto, estas páginas no se pueden guardar y se borrarán si el usuario desea que el sistema siga siendo utilizable después de tal evento.

Tanto Chinner como Tso, junto con otros, dijeron que PostgreSQL tenía la solución correcta: cambiar a E / S directa (DIO). El uso de DIO proporciona un mayor nivel de control sobre la reescritura y la E / S en general; Esto incluye el acceso a la información sobre las operaciones de E / S que pueden haber fallado. Andres Freund, como otros desarrolladores de PostgreSQL, reconoció que DIO es la mejor solución a largo plazo. Pero también señaló que no se debe esperar que los desarrolladores se sumerjan profundamente en la implementación de esta tarea. Mientras tanto, dijo que hay otros programas (mencionó dpkg) que también son propensos a este comportamiento.

Hacia una solución a corto plazo


Durante la discusión, se prestó considerable atención a la idea de que una falla de escritura debería conducir al hecho de que las páginas afectadas se almacenarán en la memoria en su estado sucio. Pero los desarrolladores de PostgreSQL se alejaron rápidamente de esta idea y no la exigieron. Lo que realmente necesitan es, en última instancia, una forma confiable de averiguar si algo salió mal. Con esto en mente, los mecanismos habituales de manejo de errores de PostgreSQL pueden manejar esto; Sin embargo, poco se puede hacer en su ausencia.

En algún momento de la discusión, Tso mencionó que Google tiene su propio mecanismo de manejo de errores de E / S. El kernel recibió instrucciones de informar errores de E / S a través del socket de enlace de red; El proceso dedicado recibe estas notificaciones y responde en consecuencia. Sin embargo, este mecanismo nunca hizo esto en la entrada. Freind señaló que este mecanismo sería "ideal" para PostgreSQL, por lo que podría aparecer en el dominio público en un futuro próximo.

Mientras tanto, Jeff Leighton estaba pensando en otra idea: establecer un indicador en el superbloque del sistema de archivos cuando se produce un error de E / S. Una llamada a syncfs() borrará este indicador y devolverá un error si se configuró. El syncfs() PostgreSQL puede llamar periódicamente a syncfs() para sondear los errores en el sistema de archivos que contiene la base de datos. Freund estuvo de acuerdo en que esta podría ser una solución viable al problema.

Por supuesto, cualquier mecanismo de este tipo aparecerá solo en los nuevos núcleos; Mientras tanto, las instalaciones de PostgreSQL generalmente se ejecutan en núcleos más antiguos compatibles con distribuciones empresariales. En estos núcleos, parece que ni siquiera hay mejoras que se incluyeron en 4.13. Para estos sistemas, se puede hacer poco para ayudar a PostgreSQL a detectar errores de E / S. Puede ser suficiente iniciar un demonio que escanee el registro del sistema y busque mensajes de error de E / S allí. No es la solución más elegante, y es complicado por el hecho de que diferentes controladores de bloques y sistemas de archivos, como regla, informan errores de diferentes maneras, pero esta puede ser la mejor opción disponible.

Es probable que el próximo paso sea una discusión en el evento LSFMM 2018 el 23 de abril. Si tiene suerte, habrá algún tipo de solución que funcione para las partes interesadas. Sin embargo, una cosa que no cambiará es el simple hecho de que el manejo de errores es difícil de hacer correctamente.

Source: https://habr.com/ru/post/472684/


All Articles