Il y a plusieurs paramètres de configuration associés aux journaux de transaction qui affectent les performances de la base de données. Cette section explique leur utilisation. Consultez le Chapitre 19 pour des détails sur la mise en place de ces paramètres de configuration.
Dans la séquence des transactions, les points de contrôles (appelés checkpoints) sont des points qui garantissent que les fichiers de données table et index ont été mis à jour avec toutes les informations enregistrées dans le journal avant le point de contrôle. Au moment du point de contrôle, toutes les pages de données non propres sont écrites sur le disque et une entrée spéciale, pour le point de contrôle, est écrite dans le journal. (Les modifications étaient déjà envoyées dans les journaux de transactions.) En cas de défaillance, la procédure de récupération recherche le dernier enregistrement d'un point de vérification dans les traces (enregistrement connus sous le nom de « redo log ») à partir duquel il devra lancer l'opération REDO. Toute modification effectuée sur les fichiers de données avant ce point est garantie d'avoir été enregistrée sur disque. Du coup, après un point de vérification, tous les segments représentant des journaux de transaction précédant celui contenant le « redo record » ne sont plus nécessaires et peuvent être soit recyclés soit supprimés (quand l'archivage des journaux de transaction est activé, ces derniers doivent être archivés avant d'être recyclés ou supprimés).
CHECKPOINT doit écrire toutes les pages de données modifiées sur disque, ce qui peut causer une charge disque importante. Du coup, l'activité des CHECKPOINT est diluée de façon à ce que les entrées/sorties disque commencent au début du CHECKPOINT et se termine avant le démarrage du prochain CHECKPOINT ; ceci minimise la dégradation des performances lors des CHECKPOINT.
Le processus checkpointer lance automatiquement un point de
contrôle de temps en temps : toutes les checkpoint_timeout secondes ou si max_wal_size risque d'être dépassé, suivant ce qui arrive
en premier. La configuration par défaut de ces deux paramètres est,
respectivement, 5 minutes et 1 Go.
Si aucun enregistrement WAL n'a été écrit depuis le dernier checkpoint, les
nouveaux checkpoint ne seront pas effectués même si la durée
checkpoint_timeout
est dépassée.
(Si l'archivage des WAL est utilisé et que vous voulez définir une limite
basse correspondant à la fréquence à laquelle les fichiers sont archivés de
manière à limiter la perte potentielle de données, vous devez ajuster le
paramètre archive_timeout plutôt que les paramètres
affectant les checkpoints.)
Il est aussi possible de forcer un checkpoint en utilisant la commande SQL
CHECKPOINT
.
La réduction de checkpoint_timeout
et/ou
max_wal_size
implique
des points de contrôle plus fréquents. Cela permet une récupération
plus rapide après défaillance puisqu'il y a moins d'écritures à
synchroniser. Cependant, il faut équilibrer cela avec
l'augmentation du coût d'écriture des pages de données modifiées.
Si full_page_writes est configuré (ce qui est la
valeur par
défaut), il reste un autre facteur à considérer. Pour s'assurer de la
cohérence des pages de données, la première modification d'une page de
données après chaque point de vérification résulte dans le traçage du contenu
entier de la page. Dans ce cas, un intervalle de points de vérification
plus petit augmentera le volume en sortie des journaux de transaction,
diminuant légèrement l'intérêt d'utiliser un intervalle plus petit et
impliquant
de toute façon plus d'entrées/sorties au niveau disque.
Les points de contrôle sont assez coûteux, tout d'abord parce qu'ils
écrivent tous les tampons utilisés, et ensuite parce que cela suscite un
trafic supplémentaire dans les journaux de transaction, comme indiqué
ci-dessus. Du coup, il est conseillé
de configurer les paramètres en relation assez haut pour que ces points de
contrôle ne surviennent pas trop fréquemment. Pour une vérification
rapide de l'adéquation de vos paramètres, vous pouvez configurer le
paramètre checkpoint_warning. Si les points de contrôle arrivent plus
rapidement que checkpoint_warning
secondes, un message
est affiché dans les journaux applicatifs du serveur recommandant d'accroître
max_wal_size
. Une apparition occasionnelle d'un
message ne doit pas vous alarmer mais, s'il apparaît souvent, alors les
paramètres de contrôle devraient être augmentés. Les opérations en masse,
comme les transferts importants de données via COPY
,
pourraient être la cause
de l'apparition d'un tel nombre de messages d'avertissements si
vous n'avez pas configuré max_wal_size
avec une valeur
suffisamment haute.
Pour éviter de remplir le système disque avec de très nombreuses
écritures de pages, l'écriture des pages modifiés pendant un point de
vérification est étalée sur une période de temps. Cette période est
contrôlée par checkpoint_completion_target, qui
est donné comme une fraction de l'intervalle des points de vérification.
Le taux d'entrées/sorties est ajusté pour que le point de vérification
se termine quand la fraction donnée de
checkpoint_timeout
secondes s'est écoulée ou quand la
fraction donnée de max_wal_size
a été consommée (la
condition que se verra vérifiée la première). Avec une valeur par
défaut de 0,5, PostgreSQL peut s'attendre à
terminer chaque point de vérification en moitié moins de temps qu'il ne
faudra pour lancer le prochain point de vérification. Sur un système
très proche du taux maximum en entrée/sortie pendant des opérations
normales, vous pouvez augmenter
checkpoint_completion_target
pour réduire le chargement
en entrée/sortie dû aux points de vérification. L'inconvénient de ceci
est que prolonger les points de vérification affecte le temps de
récupération parce qu'il faudra conserver plus de journaux de transaction
si une récupération est nécessaire. Bien que
checkpoint_completion_target
puisse valoir 1.0, il
est bien mieux de la configurer à une valeur plus basse que ça (au
maximum 0,9) car les points de vérification incluent aussi d'autres
activités en dehors de l'écriture des pages modifiées. Une valeur de 1,0
peut avoir pour résultat des points de vérification qui ne se terminent
pas à temps, ce qui aurait pour résultat des pertes de performance à
cause de variation inattendue dans le nombre de journaux nécessaires.
Sur les plateformes Linux et POSIX, checkpoint_flush_after
permet de forcer le système d'exploitation à ce que les pages écrites par un
checkpoint soient enregistrées sur disque après qu'un nombre configurable
d'octets soit écrit. Dans le cas contraire, ces pages pourraient rester dans
le cache disque du système d'exploitation, pouvant provoquer des
ralentissements lorsque fsync
est exécuté à la fin d'un
checkpoint. Cette configuration aide souvent à réduire la latence des
transactions mais il peut aussi avoir un effet inverse sur les performances,
tout particulièrement lorsque le volume de données traitées dépasse la taille
indiquée par le paramètre shared_buffers, tout en
restant plus petite que la taille du cache disque du système d'exploitation.
Le nombre de fichiers de segments WAL dans le répertoire
pg_wal
dépend des paramètres
min_wal_size
, max_wal_size
et du
contenu des WAL générés par les cycles de checkpoints précédents. Quand les
anciens fichiers de segments ne sont plus nécessaires, ils sont supprimés
ou recyclés (autrement dit, renommés pour devenir les segments futurs dans
une séquence numérotée). Si, à cause d'un pic rapide sur le taux de sortie
des WAL, max_wal_size
est dépassé, les fichiers inutiles
de segments seront supprimés jusqu'à ce que le système revienne sous cette
limite. En dessous de cette limite, le système recycle suffisamment de
fichiers WAL pour couvrir le besoin estimé jusqu'au checkpoint suivant, et
supprime le reste. L'estimation est basée sur une moyenne changeante du
nombre de fichiers WAL utilisés dans les cycles de checkpoint précédents.
La moyenne changeante est augmentée immédiatement si l'utilisation actuelle
dépasse l'estimation, pour qu'il corresponde mieux à l'utilisation en pic
plutôt qu'à l'utilisation en moyenne, jusqu'à un certain point.
min_wal_size
place un minimum sur le nombre de fichiers
WAL recyclés pour une utilisation future même si le système est inutilisé
temporairement et que l'estimation de l'utilisation des WAL suggère que peu
de WAL sont nécessaires.
Indépendamment de max_wal_size
, les wal_keep_segments + 1 plus récents fichiers WAL sont conservés en
permanence. De plus, si l'archivage est activé, les anciens segments ne
sont ni supprimés ni recyclés jusqu'à la réussite de leur archivage. Si
l'archivage des WAL n'est pas assez rapide pour tenir le rythme soutenu de
la génération des WAL ou si la commande indiquée par
archive_command
échoue de manière répétée, les anciens
fichiers WAL s'accumuleront dans le répertoire pg_wal
jusqu'à ce que ce problème soit résolu. Un serveur standby lent ou en échec
qui utilise un slot de réplication aura le même effet (voir Section 26.2.6).
Dans le mode de restauration d'archive et dans le mode standby, le serveur
réalise périodiquement des restartpoints
(points de
redémarrage). C'est similaire aux checkpoints lors du fonctionnement
normal : le serveur force l'écriture de son état sur disque, met à
jour le fichier pg_control
pour indiquer que les
données déjà traitées des journaux de transactions n'ont plus besoin d'être
parcourues de nouveau, puis recycle les anciens journaux de transactions
trouvés dans le répertoire pg_wal
. Les restartpoints
ne peuvent être réalisés plus fréquemment que les checkpoints du maître car
les restartpoints peuvent seulement être réalisés aux enregistrements de
checkpoint.
Un restartpoint est déclenché lorsqu'un enregistement de checkpoint est
atteint si un minimum de checkpoint_timeout
secondes se
sont écoulées depuis le dernier restartpoint, ou si la taille totale des
journaux de transactions a dépassé max_wal_size
.
Néanmoins, à cause des limitations lors de la réalisation d'un
restartpoint, max_wal_size
est souvent dépassé lors
d'une restauration jusqu'à au plus un cycle de checkpoint de journaux
(max_wal_size
n'est de toute façon jamais une limite en
dur donc vous devriez toujours laisser plein d'espace pour éviter de
manquer d'espace disque).
Il existe deux fonctions WAL internes couramment
utilisées :
XLogInsertRecord
et XLogFlush
.
XLogInsertRecord
est utilisée pour placer une
nouvelle entrée à l'intérieur des tampons WAL en mémoire
partagée. S'il n'y a plus
d'espace pour une nouvelle entrée, XLogInsertRecord
devra écrire (autrement dit, déplacer dans le cache du noyau) quelques
tampons WAL remplis. Ceci n'est pas désirable parce que
XLogInsertRecord
est utilisée lors de chaque
modification bas niveau de la base (par exemple, lors de l'insertion d'une
ligne) quand un verrou exclusif est posé sur des pages de données
affectées. À cause de ce verrou, l'opération doit être aussi rapide
que possible. Pire encore, écrire des tampons WAL
peut forcer la création d'un nouveau journal, ce qui
peut prendre beaucoup plus de temps. Normalement, les tampons
WAL doivent être écrits et vidés par une requête
de XLogFlush
qui est faite, la plupart du
temps, au moment de la validation d'une transaction pour assurer
que les entrées de la transaction sont écrites vers un stockage
permanent. Sur les systèmes avec une importante écriture de journaux,
les requêtes de XLogFlush
peuvent ne pas
arriver assez souvent pour empêcher LogInsert
d'avoir
à écrire lui-même sur disque. Sur de tels systèmes, on devrait augmenter le
nombre de tampons
WAL en modifiant le paramètre de configuration wal_buffers. Quand full_page_writes est configuré
et que le système est très occupé, configurer wal_buffers
avec une valeur
plus importante aide à avoir des temps de réponse plus réguliers
lors de la période suivant chaque point de vérification.
Le paramètre commit_delay définit la durée
d'endormissement en micro-secondes qu'un processus maître du groupe de commit
va s'endormir après avoir obtenu un verrou avec XLogFlush
,
tandis que les autres processus du groupe de commit vont compléter la file
d'attente derrière le maître. Ce délai permet aux processus des autres serveurs
d'ajouter leurs enregistrements de commit aux buffers WAL de manière à ce
qu'ils soient tous mis à jour par l'opération de synchronisation éventuelle du
maître. Il n'y aura pas d'endormissement si fsync n'est
pas activé et si le nombre de sessions disposant actuellement de transactions
actives est inférieur à commit_siblings ; ce
mécanisme évite l'endormissement lorsqu'il est improbable que d'autres sessions
valident leur transactions peu de temps après. Il est à noter que, sur
certaines plateformes, la résolution d'une requête d'endormissement est de dix
millisecondes, ce qui implique que toute valeur comprise entre 1 et 10000 pour
le paramètre commit_delay
aura le même effet. Notez aussi
que les opérations d'endormissement peuvent être légérement plus longues que
ce qui a été demandé par ce paramètre sur certaines plateformes.
Comme l'objet de commit_delay
est de permettre d'amortir
le coût de chaque opération de vidage sur disque des transactions concurrentes
(potentiellement au coût de la latence des transactions), il est nécessaire de
quantifier ce coût pour choisir une bonne valeur pour ce paramètre. Plus ce
coût est élevé, plus il est probable que commit_delay
soit
optimal dans un contexte où les transactions sont de plus en plus nombreuses,
jusqu'à un certain point. Le programme pg_test_fsync peut être
utilisé pour mesurer le temps moyen en microsecondes qu'une seule mise à jour
WAL prends. Définir le paramètre à la moitié du temps moyen rapporté par ce
programme après une mise à jour d'une simple opération d'écriture de 8 Ko
est la valeur la plus souvent recommandée pour démarrer l'optimisation d'une
charge particulière. Alors que l'ajustement de la valeur de
commit_delay
est particulièrement nécessaire lorsque les
journaux WAL sont stockés sur des disques à latence élevée, le gain pourrait
aussi être significatif sur les supports de stockage avec des temps de
synchronisation très rapides, comme ceux s'appuyant sur de la mémoire flash
ou RAID avec des caches d'écriture dotés de batterie, mais dans tous les cas,
cela doit être testé avec un fonctionnement représentatif de la réalité. Des
valeurs plus élevées de commit_siblings
peuvent être
utilisées dans ce cas, alors que de plus petites valeurs de
commit_siblings
sont plutôt utiles sur des supports de
plus grande latence. À noter qu'il est possible qu'une valeur trop élevée de
commit_delay
puisse augmenter la latence des transactions
à tel point que l'ensemble des transactions pourraient en souffrir.
Lorsque commit_delay
est défini à zéro (il s'agit de la
valeur par défaut), il est toujours possible qu'un groupement de commit se
produise, mais chaque groupe ne consistera qu'en les sessions qui ont atteint
le point où il leur est nécessaire de mettre à jour leur enregistrement de
commit alors que la précédente opération de mise à jour opère. Avec un plus
grand nombre de clients, l'apparition d'un « effet tunnel » se
profile, car l'effet d'un groupement de commit devient plus lourd même
lorsque commit_delay
est à zéro, et dans ce cas
commit_delay
devient inutile. Définir
commit_delay
n'est alors réellement utile que quand
il existe des transactions concurrentes, et que le flux est limité en
fréquence par commit. Ce paramètre peut aussi être efficace avec une latence
élevée en augmentant le flux de transaction avec un maximum de deux clients
(donc un unique client avec une unique transaction en cours).
Le paramètre wal_sync_method détermine la façon dont
PostgreSQL demande au noyau de forcer les mises
à jour des journaux de transaction sur le disque. Toutes les options
ont un même comportement avec une exception,
fsync_writethrough
, qui peut parfois forcer une écriture
du cache disque même quand d'autres options ne le font pas. Néanmoins,
dans la mesure où la fiabilité ne disparaît pas, c'est avec des options
spécifiques à la plate-forme que la rapidité la plus importante sera
observée. Vous pouvez tester l'impact sur la vitesse provoquée par différentes
options en utilisant le programme pg_test_fsync. Notez que ce paramètre est ignoré si
fsync
a été désactivé.
Activer le paramètre de configuration wal_debug (à
supposer que PostgreSQL ait été compilé avec le
support de ce paramètre) permet d'enregistrer chaque appel
WAL à XLogInsertRecord
et
XLogFlush
dans les journaux applicatifs du serveur.
Cette option
pourrait être remplacée par un mécanisme plus général dans le futur.