Documentation PostgreSQL 9.5.25 > Administration du serveur > Fiabilité et journaux de transaction > Configuration des journaux de transaction | |
Validation asynchrone (Asynchronous Commit) | Vue interne des journaux de transaction |
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 18, Configuration du serveur 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.
Le nombre de fichiers de segments WAL dans le répertoire pg_xlog 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_xlog 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 25.2.6, « Slots de réplication »).
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_xlog. 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(1) 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(1). 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.