PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 17.1 » Administration du serveur » Fiabilité et journaux de transaction » Fiabilité

28.1. Fiabilité #

La fiabilité est une propriété importante de tout système de base de données sérieux. PostgreSQL fait tout son possible pour garantir un fonctionnement fiable. Un des aspects de la fiabilité est de stocker toutes les données validées par une transaction dans un espace non volatile, insensible aux coupures de courant, aux bogues du système d'exploitation et aux problèmes matériels (sauf en cas de problème sur l'espace non volatile, bien sûr). Pour cela, il est habituellement suffisant d'écrire avec succès les données sur le stockage permanent de l'ordinateur (disque dur ou un équivalent). En fait, même si un ordinateur est irrémédiablement hors d'usage, si le disque dur survit, ces données peuvent être déplacées vers un autre ordinateur au matériel similaire et toutes les transactions validées resteront intactes.

Bien que forcer l'enregistrement des données périodiquement sur le disque semble être une opération simple, ce n'est pas le cas. Comme les disques durs sont beaucoup plus lents que la mémoire principale et les processeurs, plusieurs niveaux de cache existent entre la mémoire principale de l'ordinateur et les disques. Tout d'abord, il y a le tampon cache du système d'exploitation, qui met en cache les blocs disque fréquemment utilisés et combine les écritures. Heureusement, tous les systèmes d'exploitation fournissent aux applications un moyen de forcer les écritures du cache vers le disque et PostgreSQL utilise ces fonctions (voir le paramètre wal_sync_method pour en ajuster le fonctionnement).

Ensuite, il peut y avoir un cache dans le contrôleur du disque dur ; ceci est assez courant sur les cartes contrôleur RAID. Certains de ces caches sont write-through, ce qui signifie que les écritures sont envoyées au disque dès qu'elles arrivent. D'autres sont write-back, ce qui veut dire que les données sont envoyées au lecteur un peu plus tard. De tels caches peuvent être un danger car la mémoire cache du contrôleur du disque est volatile  elle perdra donc son contenu à la prochaine coupure de courant. Des cartes contrôleur de meilleure qualité ont des caches avec batterie (BBU), c'est-à-dire que la carte dispose d'une batterie qui maintient l'alimentation du cache en cas de coupure de courant. Une fois celui-ci revenu, les données seront écrites sur les disques durs.

Et enfin, la plupart des disques durs ont des caches. Certains sont write-through alors que d'autres sont write-back, et les mêmes problèmes se posent pour les caches write-back des disques que pour ceux de contrôleurs. Les disques IDE et SATA grand public en particulier sont susceptibles d'avoir des caches « write-back » qui ne survivront pas à une perte de courant. De nombreux SSD sont aussi dotés de caches « write-back » volatiles.

Ces caches peuvent généralement être désactivés. Néanmoins, la méthode pour le faire dépend du système d'exploitation et du type de disque :

  • Sur Linux, on peut interroger les disques IDE et SATA avec la commande hdparm -I ; le cache en écriture est activé si une étoile (*) se trouve derrière le texte Write cache. hdparm -W 0 peut être utilisé pour désactiver le cache en écriture. Les disques SCSI peuvent être vérifiés en utilisant sdparm. Utilisez sdparm --get=WCE pour voir si le cache en écriture est activé et sdparm --clear=WCE pour le désactiver.

  • Sur FreeBSD, les disques IDE peuvent être interrogés avec camcontrol et le cache en écriture désactivé avec hw.ata.wc=0 dans le fichier de configuration /boot/loader.conf ; les disques SCSI peuvent être interrogés avec camcontrol identify, et le cache en écriture peut être consulté et modifié en utilisant sdparm quand cette commande est disponible.

  • Sur Solaris, le cache disque en écriture est contrôlé par format -e. (Le système de fichiers Solaris ZFS est sûr même quand le cache disque en écriture est activé car il exécute ses propres commandes de vidage du cache.)

  • Sur Windows, si wal_sync_method vaut open_datasync (la valeur par défaut), le cache en écriture peut être désactivé en décochant My Computer\Open\disk drive\Properties\Hardware\Properties\Policies\Enable write caching on the disk. Ou bien configurez wal_sync_method à fdatasync (NTFS seulement) ou fsync pour désactiver le cache en écriture.

  • Sur macOS, le cache en écriture peut être évité en configurant wal_sync_method à fsync_writethrough.

Les disques SATA récents (ceux compatibles ATAPI-6 ou supérieurs) proposent une commande pour vider le cache sur le disque (FLUSH CACHE EXT) alors que les disques SCSI proposent depuis longtemps une commande similaire, SYNCHRONIZE CACHE. Ces commandes ne sont pas directement accessibles à PostgreSQL, mais certains systèmes de fichiers (comme ZFS, ext4) peuvent les utiliser pour vider les données sur disque pour les disques au cache en écriture activé. Malheureusement, ces systèmes de fichiers se comportent de façon non optimale avec des contrôleurs disque équipés de batterie (BBU, acronyme de Battery-Backed Unit). Dans ce type de configuration, la commande de synchronisation force l'écriture de toutes les données comprises dans le cache sur les disques, éliminant ainsi tout l'intérêt d'un cache protégé par une batterie. Vous pouvez lancer l'outil pg_test_fsync, disponible dans le code source de PostgreSQL, pour vérifier si vous êtes affecté. Si vous l'êtes, les améliorations de performance du cache BBU peuvent être de nouveaux obtenues en désactivant les barrières d'écriture dans la configuration du système de fichiers ou en reconfigurant le contrôleur de disque, si cela est possible. Si les barrières d'écriture sont désactivées, assurez-vous que la batterie reste active. Une batterie défectueuse peut être une cause de perte de données. Il reste à espérer que les concepteurs de systèmes de fichiers et de contrôleurs disque finissent par corriger ce comportement gênant.

Quand le système d'exploitation envoie une demande d'écriture au système de stockage, il ne peut pas faire grand chose pour s'assurer que les données sont arrivées dans un espace de stockage réellement non volatile. C'est plutôt la responsabilité de l'administrateur de s'assurer que tous les composants de stockage garantissent l'intégrité des données et des métadonnées du système de fichier. Évitez les contrôleurs disques ne disposant pas de caches protégés par batterie. Au niveau du disque, désactivez le cache « write-back » si le disque ne peut garantir que les données seront écrites avant un arrêt. Si vous utilisez des disques SSD, sachez que beaucoup n'honorent pas les commandes de vidage de cache par défaut. Vous pouvez tester la fiabilité du comportement du système disque en utilisant diskchecker.pl.

Un autre risque de perte de données est dû aux opérations d'écriture sur les plateaux du disque. Les plateaux sont divisés en secteurs de 512 octets généralement. Chaque opération de lecture ou écriture physique traite un secteur entier. Quand une demande d'écriture arrive au lecteur, sa taille peut être un multiple de 512 octets (PostgreSQL écrit généralement 8192 octets, soit 16 secteurs, à la fois) et le processus d'écriture peut échouer à cause d'une coupure de courant à tout moment, ce qui implique que certains octets peuvent être écrits et les autres perdus. Pour se prévenir contre ce type d'échec, PostgreSQL écrit périodiquement des pages complètes dans le stockage permanent des journaux de transactions avant de modifier la page réelle sur disque. Ainsi, lors d'une récupération après un arrêt brutal, PostgreSQL peut restaurer les pages écrites partiellement à partir des journaux de transactions. Si vous avez un système de fichiers qui vous protège contre les écritures de pages incomplètes (par exemple ZFS), vous pouvez désactiver la création des images de page en utilisant le paramètre full_page_writes. Les contrôleurs disques disposant d'une batterie (BBU pour Battery-Backed Unit) n'empêchent pas les écritures de pages partielles sauf s'ils garantissent que les données sont écrites par pages complètes de 8 ko.

PostgreSQL protège aussi de certaines corruptions de données au niveau du support de stockage qui peuvent se produire suite à des erreurs au niveau matériel ou des problèmes d'usure au fil du temps, comme la lecture ou l'écriture de données invalides.

  • Dans un journal de transaction, chaque enregistrement est protégé par une somme de contrôle CRC-32C (32 bits) qui nous dit si le contenu de l'enregistrement est correct. La valeur CRC est définie à l'écriture de chaque enregistrement dans le journal et vérifiée durant une récupération après arrêt brutal, la récupération d'une archive et la réplication.

  • Par défaut, les pages de données ne disposent pas de sommes de contrôle, mais les images des pages complètes stockées dans les enregistrements des journaux de transactions seront protégées. Voir initdb pour les détails sur l'activation des sommes de contrôle sur les pages de données.

  • Les structures de données internes comme pg_xact, pg_subtrans, pg_multixact, pg_serial, pg_notify, pg_stat, pg_snapshots n'ont pas de sommes de contrôle, et leurs pages de données ne sont pas protégées par les écritures de pages complètes. Cependant, lorsque de telles structures de données sont persistantes, les enregistrements des journaux de transactions sont écrits de manière à ce que les modifications récentes puissent être rapidement reconstruites lors d'une restauration après incident, et ces enregistrements sont protégés comme décrit plus haut.

  • Les fichiers d'état de pg_twophase sont protégés chacun par une somme de contrôle CRC-32C.

  • Les fichiers de données temporaires utilisés lors de grosses requêtes SQL pour le tri, la matérialisation ou des résultats intermédiaires ne font pas actuellement l'objet d'une somme de contrôle, et la modification de ces fichiers n'est pas non plus consignée dans les enregistrements des journaux de transactions.

PostgreSQL ne protége pas contre les erreurs mémoires et il est supposé que vous travaillez avec de la RAM avec correction d'erreur (ECC) aux standards de l'industrie, ou une meilleure protection.