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\
.
Ou bien configurez disk
drive
\Properties\Hardware\Properties\Policies\Enable
write caching on the diskwal_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.