ERREUR PostgreSQL: annulation de l'instruction en raison d'un conflit avec la récupération


139

J'obtiens l'erreur suivante lors de l'exécution d'une requête sur une base de données PostgreSQL en mode veille. La requête qui provoque l'erreur fonctionne correctement pendant 1 mois, mais lorsque vous interrogez pendant plus d'un mois, une erreur se produit.

ERROR: canceling statement due to conflict with recovery
Detail: User query might have needed to see row versions that must be removed

Des suggestions sur la façon de résoudre? Merci


Veuillez trouver le document AWS qui mentionne cette erreur, il a également la solution aws.amazon.com/blogs/database/…
arunjos007

Réponses:


89

L'exécution de requêtes sur un serveur de secours automatique est quelque peu délicate - cela peut échouer, car pendant l'interrogation, certaines lignes nécessaires peuvent être mises à jour ou supprimées sur le serveur principal. Comme un primaire ne sait pas qu'une requête est lancée sur le secondaire, il pense pouvoir nettoyer (aspirer) les anciennes versions de ses lignes. Ensuite, secondaire doit rejouer ce nettoyage et doit annuler de force toutes les requêtes qui peuvent utiliser ces lignes.

Les requêtes plus longues seront annulées plus souvent.

Vous pouvez contourner ce problème en démarrant une transaction de lecture répétable sur le primaire qui effectue une requête factice, puis reste inactif pendant qu'une requête réelle est exécutée sur le secondaire. Sa présence empêchera l'aspiration des anciennes versions de rangées sur le primaire.

Plus d'informations sur ce sujet et d'autres solutions de contournement sont expliquées dans la section Hot Standby - Gestion des conflits de requêtes de la documentation.


10
Aux utilisateurs de PostgreSQL 9.1+: voir la réponse d' eradman ci-dessous pour une solution pratique.
Zoltán

3
Pour les utilisateurs de PostgreSQL 9.1+: la réponse de max-malysh est beaucoup plus saine. Ne faites pas la suggestion d'éradman si vous ne comprenez pas les risques.
Davos

91

Pas besoin de toucher hot_standby_feedback. Comme d'autres l'ont mentionné, le définir sur onpeut maîtriser le gonflement. Imaginez ouvrir une transaction sur un esclave et ne pas la fermer.

Au lieu de cela, définissez max_standby_archive_delayet max_standby_streaming_delaysur une valeur raisonnable:

# /etc/postgresql/10/main/postgresql.conf on a slave
max_standby_archive_delay = 900s
max_standby_streaming_delay = 900s

De cette façon, les requêtes sur les esclaves d'une durée inférieure à 900 secondes ne seront pas annulées. Si votre charge de travail nécessite des requêtes plus longues, définissez simplement ces options sur une valeur plus élevée.


1
C'est la solution que nous avons finalement utilisée. Cela semble être le meilleur compromis entre toutes les options présentées ici.
mohit6up

2
C'est la meilleure réponse. Notez que selon les documents, ceux-ci sont cumulatifs; si vous avez plusieurs requêtes sur le réplica qui bloquent la réplication, il se peut que vous arriviez à 899, puis une autre requête de 2 secondes soit annulée. Il est préférable de simplement implémenter un recul exponentiel dans votre code. En outre, le délai de diffusion est en vigueur pendant la réplication. Si la réplication ne peut pas suivre le streaming, elle passera à la réplication à partir de l'archive. Si vous répliquez à partir d'une archive, vous devriez probablement la laisser rattraper son retard, elle max_standby_archive_delaydevra peut-être être plus petite que l'autre.
Davos

2
C'est toujours la meilleure solution ici. Notez que dans Redshift, vous pouvez définir cela via les paramètres du groupe de paramètres, seulement qu'il devrait être en ms, c'est- à -dire 900s = 16 minutes = 900000ms.
NullDev

Pour mettre à jour cela sur GCP, également effectué dans ms cloud.google.com/sql/docs/postgres/…
howMuchCheeseIsTooMuchCheese

À condition que le but de la veille soit, par exemple, de générer des rapports et que ce ne soit pas une réserve à chaud qui doit être prête à gérer le basculement, c'est la meilleure réponse.
soupdog

77

Il n'est pas nécessaire de démarrer des transactions inactives sur le maître. Dans postgresql-9.1, le moyen le plus direct de résoudre ce problème est de définir

hot_standby_feedback = on

Cela rendra le maître conscient des requêtes de longue durée. À partir de la documentation :

La première option consiste à définir le paramètre hot_standby_feedback, qui empêche VACUUM de supprimer les lignes récemment mortes et ainsi les conflits de nettoyage ne se produisent pas.

Pourquoi n'est-ce pas la valeur par défaut? Ce paramètre a été ajouté après l'implémentation initiale et c'est la seule façon dont un standby peut affecter un maître.


11
Ce paramètre doit être défini en veille.
Steve Kehlet

3
Il y a quelques inconvénients pour le maître dans ce cas Hot-Standby-Feedback
Evgeny Liskovets

50

Comme indiqué ici à propos de hot_standby_feedback = on:

Eh bien, l'inconvénient est que la veille peut gonfler le maître, ce qui peut également surprendre certaines personnes.

Et ici :

Avec quel paramètre de max_standby_streaming_delay? Je préférerais que ce soit par défaut à -1 que par défaut hot_standby_feedback activé. De cette façon, ce que vous faites en veille n'affecte que la veille


Alors j'ai ajouté

max_standby_streaming_delay = -1

Et plus d' pg_dumperreur pour nous, ni de ballonnement maître :)

Pour l'instance AWS RDS, consultez http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.html


1
@lennard, cela a fonctionné pour moi. J'ai ajouté cette configuration sur le postgresql.conf de l'esclave, puis j'ai redémarré l'esclave.
Ardee Aram

13
Vous pouvez bien sûr obtenir un décalage de réplique illimité de cette façon. Et si vous utilisez un emplacement de réplication pour connecter le réplica au maître, cela peut entraîner une rétention xlog excessive sur le maître, ce n'est donc vraiment viable que si vous utilisez l'archivage WAL.
Craig Ringer

7
Comment définir cela sur AWS RDS?
Kris MP

1
@KrisMP Use psql
Yehonatan

4
@KrisMP dans le groupe de paramètres - docs.aws.amazon.com/AmazonRDS/latest/UserGuide/…
r3m0t

13

Les données de la table sur le serveur esclave de secours à chaud sont modifiées lors de l'exécution d'une requête de longue durée. Une solution (PostgreSQL 9.1+) pour s'assurer que les données de la table ne sont pas modifiées est de suspendre la réplication et de la reprendre après la requête:

select pg_xlog_replay_pause(); -- suspend
select * from foo; -- your query
select pg_xlog_replay_resume(); --resume

1
Cela nécessite des droits de superutilisateur. Ce n'est donc peut-être pas une solution dans certains cas.
Joao Baltazar le

1
Dans PostgreSQL 10, a xlogété remplacé par wal, vous voulez donc appeler pg_wal_replay_pause()et pg_wal_replay_resume().
womble

3

Il est peut-être trop tard pour la réponse, mais nous sommes confrontés au même genre de problème sur la production. Auparavant, nous n'avions qu'un seul RDS et à mesure que le nombre d'utilisateurs augmentait du côté de l'application, nous avons décidé d'ajouter un réplica en lecture pour celui-ci. Le réplica en lecture fonctionne correctement sur la mise en scène, mais une fois que nous sommes passés à la production, nous commençons à obtenir la même erreur.

Nous résolvons donc ce problème en activant la propriété hot_standby_feedback dans les propriétés Postgres. Nous avons référé le lien suivant

https://aws.amazon.com/blogs/database/best-practices-for-amazon-rds-postgresql-replication/

J'espère que cela aidera.


2

Je vais ajouter quelques informations mises à jour et des références à l'excellente réponse de @ max-malysh ci-dessus.

En bref, si vous faites quelque chose sur le maître, il doit être répliqué sur l'esclave. Postgres utilise pour cela des enregistrements WAL, qui sont envoyés après chaque action enregistrée sur le maître à l'esclave. L'esclave exécute alors l'action et les deux sont à nouveau synchronisés. Dans l'un des nombreux scénarios, vous pouvez être en conflit sur l'esclave avec ce qui arrive du maître dans une action WAL. Dans la plupart d'entre eux, il y a une transaction en cours sur l'esclave qui entre en conflit avec ce que l'action WAL veut changer. Dans ce cas, vous avez deux options:

  1. Retardez un peu l'application de l'action WAL pour permettre à l'esclave de terminer sa transaction conflictuelle, puis appliquez l'action.
  2. Annulez la requête conflictuelle sur l'esclave.

Nous sommes concernés par le n ° 1 et deux valeurs:

  • max_standby_archive_delay - c'est le délai utilisé après une longue déconnexion entre le maître et l'esclave, lorsque les données sont lues à partir d'une archive WAL, qui ne sont pas des données actuelles.
  • max_standby_streaming_delay - délai utilisé pour annuler les requêtes lorsque les entrées WAL sont reçues via la réplication en continu.

En règle générale, si votre serveur est destiné à la réplication à haute disponibilité, vous voulez garder ces chiffres courts. Le réglage par défaut de 30000(millisecondes si aucune unité n'est donnée) est suffisant pour cela. Si, cependant, vous souhaitez configurer quelque chose comme une archive, un rapport ou une réplique en lecture qui pourrait avoir des requêtes de très longue durée, vous voudrez le définir sur quelque chose de plus élevé pour éviter les requêtes annulées. Le 900sréglage recommandé ci-dessus semble être un bon point de départ. Je ne suis pas d'accord avec la documentation officielle sur la définition d'une valeur infinie -1comme étant une bonne idée - cela pourrait masquer du code bogué et causer de nombreux problèmes.

La seule mise en garde concernant les requêtes de longue durée et la définition de ces valeurs plus élevées est que les autres requêtes exécutées sur l'esclave en parallèle avec la requête de longue durée qui retarde l'action WAL verront les anciennes données jusqu'à ce que la longue requête soit terminée. Les développeurs devront comprendre cela et sérialiser les requêtes qui ne doivent pas s'exécuter simultanément.

Pour une explication complète de comment max_standby_archive_delayet de max_standby_streaming_delaytravail et pourquoi, allez ici .


1

De même, voici une deuxième mise en garde à @ Artif3x élaboration de l'excellente réponse de @ max-malysh, les deux ci-dessus.

Avec toute application retardée des transactions du maître, le ou les suiveurs auront une vue plus ancienne et obsolète des données. Par conséquent, tout en laissant le temps à la requête sur le suiveur de se terminer en définissant max_standby_archive_delay et max_standby_streaming_delay a du sens, gardez ces deux mises en garde à l'esprit:

Si la valeur de l'abonné pour la sauvegarde finit par être trop en conflit avec les requêtes d'hébergement, une solution serait de multiples abonnés, chacun optimisé pour l'un ou l'autre.

Notez également que plusieurs requêtes consécutives peuvent retarder l'application des entrées wal. Ainsi, lors du choix des nouvelles valeurs, ce n'est pas seulement le moment d'une seule requête, mais une fenêtre en mouvement qui commence chaque fois qu'une requête en conflit démarre et se termine lorsque l'entrée wal est finalement appliquée.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.