Postgres contient un horizon d'événements mobile, qui est en fait d'environ 2 milliards de transactions en avance ou en retard sur l'identifiant de transaction actuel. Les transactions jusqu'à 2 milliards en avance ou plus de 2 milliards en retard par rapport à l'identifiant de transaction actuel sont considérées comme étant dans le futur et seront donc invisibles pour les transactions en cours.
Postgres évite cette perte de données catastrophique en marquant spécialement les anciennes lignes afin que, peu importe où elles se trouvent par rapport à l'identifiant de transaction actuel, elles soient visibles.
Le gel est ce processus de marquage d'anciens tuples en direct (c'est-à-dire des lignes de base de données) afin qu'ils ne soient pas écrasés par l'horizon des événements en mouvement qui les ferait autrement apparaître dans le futur. Cela contraste avec le nettoyage, qui est la libération de l'espace consommé par les anciens tuples morts qui ne sont plus visibles pour aucune transaction.
Les deux processus sont gérés par le vide.
Il existe un certain nombre de paramètres qui régissent la façon dont le gel est effectué.
Tout d'abord, vacuum_freeze_min_age
régit si un tuple sera gelé ou non alors que vacuum regarde déjà une page pour voir s'il y a des tuples morts qui peuvent être nettoyés. Tuples plus anciens que vacuum_freeze_min_age
sera gelé dans ce cas. Définir ce niveau bas signifie qu'il y aura moins de travail à faire plus tard, mais au prix possible d'un effort supplémentaire à la fois dans l'activité CPU et IO ou WAL. En règle générale, vous souhaitez probablement que cet ensemble corresponde à au moins quelques heures de transactions. Supposons que vous vous attendiez à effectuer jusqu'à 2 000 transactions par seconde à un rythme soutenu. 2000 TPS représentent 7,2 millions de transactions par heure. Ainsi, un réglage assez agressif pour ce cas pourrait être, par exemple, 20 m. Le réglage par défaut est 50 m. De même pour vacuum_multixact_freeze_min_age
. Notez que les compteurs transaction_id et multixid sont indépendants ; vous devez les suivre tous les deux.
Deuxièmement, il y a vacuum_freeze_table_age
et vacuum_multixact_freeze_table_age
. Ces paramètres régissent le moment où l'autovacuum ne regardera pas seulement les pages qui pourraient avoir des lignes mortes, mais toute page qui pourrait avoir des lignes non figées. Les valeurs par défaut pour ces paramètres sont 150 m. Si vous avez réduit vacuum_freeze_min_age
assez, dans de nombreux cas, cet aspirateur plus agressif aura peu ou pas de travail à faire. Dans tous les cas, ce processus n'est plus aussi chargé qu'avant, car les versions modernes de Postgres (9.6 et supérieures) conservent une carte des pages où tous les tuples sont gelés et ne visitent que les pages qui ne sont pas toutes gelées. Cela signifie qu'il ne s'agit plus d'une analyse complète de la table.
Le dernier est autovacuum_freeze_max_age
. Si la dernière analyse complète de la table à la recherche de lignes non figées remonte à plus de ce nombre de transactions, autovacuum lancera un vide anti-bouclage sur la table. La valeur par défaut est 200 m. De même pour autovacuum_multixact_freeze_max_age
pour lequel la valeur par défaut est 400m. C'est quelque chose que vous voulez vraiment éviter. Il y a deux choses qui peuvent être faites. Premièrement, il est très courant d'augmenter ces paramètres à quelque chose comme 1 milliard, pour se donner plus de marge, en particulier sur les systèmes qui sont de gros consommateurs de transactions. Vous pourriez en faire plus, mais vous voulez avoir beaucoup d'espace de transaction entre votre tuple le plus ancien et l'horizon des événements. Deuxièmement, il est important de surveiller vos systèmes et de prendre des mesures correctives avant que les bases de données ne se heurtent à cela. Cette action corrective comprend souvent l'aspiration manuelle.
Un problème qui peut survenir est lorsque vous avez un DDL qui provoque l'annulation de l'autovacuum normal (c'est-à-dire non anti-bouclage). Si vous le faites suffisamment, vous finirez par obtenir un vide anti-enroulement forcé, et tout DDL se mettra alors en file d'attente derrière le processus de vide, ce qui à son tour bloquera tout autre DML. À ce stade, votre table est effectivement illisible jusqu'à la fin du vide. Cela dépend du modèle d'utilisation de votre base de données, mais ce n'est pas seulement une possibilité théorique et les déploiements Postgres et les DBA doivent en tenir compte.
La surveillance de votre cluster de bases de données est essentielle pour gérer cela. En particulier, vous devez surveiller le datfrozenxid
et datminmxid
de chaque base de données du cluster, et si celles-ci deviennent trop anciennes, prenez des mesures correctives avant qu'un vide anti-wraparound ne soit requis. Le problème vient souvent d'une ou de quelques tables de la base de données. Lesquels sont le problème peuvent être découverts en examinant le relfrozenxid
et relminmxid
des tables de la base de données. L'age()
et mxid_age()
sont utiles pour découvrir l'âge des compteurs d'ID de transaction et de multixid respectivement.
Le gel n'est pas quelque chose que vous pouvez éviter, c'est une activité de maintenance essentielle dans Postgres qui doit être gérée activement.