Envoyer une surprise à fsync () PostgreSQL

Les développeurs de SGBD, par nécessité, craignent que les données ne tombent en toute sécurité dans un stockage permanent. Par conséquent, lorsque la communauté PostgreSQL a découvert que la façon dont le noyau gère les erreurs d'E / S peut entraîner une perte de données sans qu'aucune erreur ne soit signalée à l'espace utilisateur, un grand mécontentement est apparu. Un problème qui est aggravé par le fait que PostgreSQL effectue des E / S tamponnées n'est pas unique à Linux et ne sera pas facile à résoudre même là-bas.

Craig Ringer a signalé le problème pour la première fois à la liste de diffusion pgsql-hackers fin mars. En bref, PostgreSQL suppose qu'un appel fsync() réussi indique que toutes les données enregistrées depuis le dernier appel réussi ont été transférées en toute sécurité vers un stockage persistant. Lorsque les écritures d'E / S mises en mémoire tampon échouent en raison d'une erreur matérielle, les systèmes de fichiers réagissent différemment, mais ce comportement implique généralement la suppression de données sur les pages correspondantes et leur marquage comme propres. Par conséquent, la lecture de blocs qui viennent d'être écrits retournera très probablement quelque chose d'autre, mais pas de données enregistrées.

Qu'en est-il du rapport d'erreurs? Il y a un an, le sommet du système de fichiers, du stockage et de la gestion de la mémoire Linux (LSFMM) comprenait une session de rapport de bogues au cours de laquelle tout cela était appelé un «désordre»; les erreurs peuvent facilement être perdues, donc aucune application ne les verra jamais. Certains correctifs inclus dans 4.13 ont quelque peu amélioré la situation pendant le cycle de développement (et dans 4.16 il y a eu quelques changements pour l'améliorer davantage), cependant, il existe des moyens de perdre les notifications d'erreur, comme décrit ci-dessous. Si cela se produit sur un serveur PostgreSQL, cela peut entraîner une corruption automatique de la base de données.

Les développeurs de PostgreSQL n'étaient pas satisfaits. Tom Lane a décrit cela comme des « lésions cérébrales au noyau », tandis que Robert Haas l'a appelé « 100% stupide ». Au début de la discussion, les développeurs de PostgreSQL ont compris assez clairement comment, à leur avis, le noyau devrait fonctionner: les pages qui ne pouvaient pas être écrites devaient être stockées en mémoire dans un état «sale» (pour les tentatives ultérieures), et le descripteur de fichier correspondant devait être traduit en Statut d'erreur permanent afin que le serveur PostgreSQL ne puisse pas ignorer le problème.

Où quelque chose s'est-il mal passé


Cependant, avant même que la communauté du noyau n'entre dans la discussion, il est devenu clair que la situation n'était pas aussi simple qu'elle y paraissait. Thomas Munro a déclaré que Linux n'est pas unique dans ce comportement; OpenBSD et NetBSD peuvent également ne pas signaler d'erreurs d'écriture dans l'espace utilisateur. Et, comme il s'est avéré, la façon dont PostgreSQL gère les opérations d'E / S tamponnées complique considérablement l'image.

Ce mécanisme a été décrit en détail par Haas. Un serveur PostgreSQL fonctionne comme un ensemble de processus, dont beaucoup peuvent effectuer des E / S sur des fichiers de base de données. Le fsync() appel fsync() , cependant, est géré dans un seul processus de fsync() vérification («processus de point de contrôle»), qui consiste à maintenir le stockage sur disque dans un état cohérent pour récupérer des échecs. Checkpointer ne garde généralement pas tous les fichiers pertinents ouverts, il doit donc souvent ouvrir le fichier avant d'appeler fsync() . C'est là que le problème se pose: même dans les noyaux 4.13 et versions ultérieures, checkpointer ne verra aucune erreur survenue avant l'ouverture du fichier. Si quelque chose de mauvais se produit avant d'appeler open() checkpointer-a, le prochain appel à fsync() renverra le succès. Il existe plusieurs façons de provoquer une erreur d'E / S en dehors de fsync() ; par exemple, le noyau peut rencontrer l'un d'eux lors de l'écriture en arrière-plan. Une personne appelant sync() peut également rencontrer une erreur d'E / S et «absorber» l'état d'erreur résultant.

Haas a décrit ce comportement comme étant incapable de répondre aux attentes de PostgreSQL:
Tout ce que vous (ou quelqu'un) avez est essentiellement une hypothèse non prouvée que
quels descripteurs de fichiers peuvent être pertinents pour une erreur particulière, mais il s'est avéré que PostgreSQL ne l'a jamais fait correspondre. Vous pouvez continuer à dire que le problème est dans nos suppositions, mais il me semble erroné de supposer que nous sommes le seul programme à les avoir fait.

En conséquence, Joshua Drake a déplacé la conversation vers la liste de développement pour ext4, y compris une partie de la communauté de développement du noyau. Dave Chinner a rapidement décrit ce comportement comme "une recette pour un désastre, en particulier dans le code multiplateforme, où chaque plate-forme de système d'exploitation se comporte différemment et ne correspond presque jamais à ce qui était attendu ". Au lieu de cela, Ted Tso a expliqué pourquoi les pages affectées sont marquées comme propres après une erreur d'E / S; en bref, la cause la plus courante d'erreurs d'E / S est lorsque l'utilisateur éjecte la clé USB au mauvais moment. Si un processus a copié beaucoup de données sur ce disque, le résultat sera l'accumulation de pages sales dans la mémoire, peut-être au point que le système n'a pas assez de mémoire pour d'autres tâches. Ainsi, ces pages ne peuvent pas être enregistrées et seront effacées si l'utilisateur souhaite que le système reste utilisable après un tel événement.

Chinner et Tso, ainsi que d'autres, ont déclaré que PostgreSQL avait la bonne solution - passer aux E / S directes (DIO). L'utilisation de DIO offre un plus grand niveau de contrôle sur l'écriture différée et les E / S en général; cela inclut l'accès aux informations sur les opérations d'E / S qui peuvent avoir échoué. Andres Freund, comme un certain nombre d'autres développeurs PostgreSQL, a reconnu que DIO est la meilleure solution à long terme. Mais il a également noté qu'il ne faut pas s'attendre à ce que les développeurs plongent profondément dans la mise en œuvre de cette tâche. Pendant ce temps, il a déclaré qu'il existe d'autres programmes (il a mentionné dpkg) qui sont également sujets à ce comportement.

Vers une solution à court terme


Au cours de la discussion, une attention considérable a été accordée à l'idée qu'un échec d'écriture devrait conduire au fait que les pages affectées seront stockées en mémoire dans leur état sale. Mais les développeurs de PostgreSQL se sont rapidement éloignés de cette idée et ne l'ont pas exigée. Ce dont ils ont vraiment besoin, c'est finalement un moyen fiable de savoir si quelque chose s'est mal passé. Dans cet esprit, les mécanismes habituels de gestion des erreurs de PostgreSQL peuvent gérer cela; cependant, peu de choses peuvent être faites en son absence.

À un moment donné de la discussion, Tso a mentionné que Google avait son propre mécanisme de gestion des erreurs d'E / S. Le noyau a été chargé de signaler les erreurs d'E / S via le socket netlink; Le processus dédié reçoit ces notifications et répond en conséquence. Pourtant, ce mécanisme n'a jamais fait cela à l'entrée. Freind a souligné que ce mécanisme serait "idéal" pour PostgreSQL, donc il pourrait apparaître dans le domaine public dans un avenir proche.

Pendant ce temps, Jeff Leighton réfléchissait à une autre idée: définir un indicateur dans le superbloc du système de fichiers lorsqu'une erreur d'E / S se produit. Un appel à syncfs() alors cet indicateur et retournera une erreur s'il a été défini. Le pointeur de contrôle PostgreSQL peut périodiquement appeler syncfs() pour rechercher les erreurs sur le système de fichiers contenant la base de données. Freund a convenu que cela pourrait être une solution viable au problème.

Bien sûr, un tel mécanisme n'apparaîtra que dans les nouveaux noyaux; Parallèlement, les installations PostgreSQL s'exécutent généralement sur des noyaux plus anciens pris en charge par les distributions d'entreprise. Dans ces noyaux, il semble qu'il n'y ait même pas les améliorations incluses dans 4.13. Pour ces systèmes, rien ne peut être fait pour aider PostgreSQL à détecter les erreurs d'E / S. Il peut être suffisant de démarrer un démon qui analyse le journal système et y recherche des messages d'erreur d'E / S. Ce n'est pas la solution la plus élégante, et elle est compliquée par le fait que différents pilotes de blocs et systèmes de fichiers, en règle générale, signalent les erreurs de différentes manières, mais cela peut être la meilleure option disponible.

La prochaine étape sera probablement une discussion lors de l'événement LSFMM 2018 le 23 avril. Si vous êtes chanceux, il y aura une sorte de solution qui fonctionnera pour les parties intéressées. Cependant, une chose qui ne changera pas est le simple fait que la gestion des erreurs est difficile à faire correctement.

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


All Articles