PostgreSQL ERROR: отмена оператора из-за конфликта с восстановлением

139

Я получаю следующую ошибку при выполнении запроса к базе данных PostgreSQL в режиме ожидания. Запрос, который вызывает ошибку, работает нормально в течение 1 месяца, но при запросе более 1 месяца возникает ошибка.

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

Любые предложения о том, как решить? Спасибо

AnApprentice
источник
Пожалуйста , найдите документ AWS , в котором упоминается эта ошибка также имеет решение aws.amazon.com/blogs/database/...
arunjos007

Ответы:

89

Выполнение запросов на сервере с горячим резервированием несколько сложно - это может привести к сбою, поскольку во время запроса некоторые необходимые строки могут быть обновлены или удалены на первичном сервере. Поскольку первичный сервер не знает, что запрос запущен на вторичном сервере, он считает, что может очистить (очистить) старые версии своих строк. Затем вторичный сервер должен воспроизвести эту очистку и принудительно отменить все запросы, которые могут использовать эти строки.

Более длинные запросы будут отменяться чаще.

Вы можете обойти это, запустив повторяющуюся транзакцию чтения на первичном сервере, который выполняет фиктивный запрос, а затем бездействует, пока реальный запрос выполняется на вторичном сервере. Его наличие предотвратит очистку старых версий рядов от первичных.

Подробнее об этом и других обходных путях рассказывается в разделе « Горячий резерв - обработка конфликтов запросов » в документации.

Tometzky
источник
10
Для пользователей PostgreSQL 9.1+: см. Ответ eradman ниже для практического решения.
Золтан
3
Для пользователей PostgreSQL 9.1+: ответ max-malysh гораздо более разумный. Не делайте предложение Эрадман, если вы не понимаете риски.
Давос
91

Не нужно трогать hot_standby_feedback. Как уже упоминали другие, установка его onможет раздуть мастер. Представьте, что вы открываете транзакцию на подчиненном устройстве, а не закрываете ее.

Вместо этого установите max_standby_archive_delayи max_standby_streaming_delayв какое-то вменяемое значение:

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

Таким образом, запросы к рабам продолжительностью менее 900 секунд не будут отменены. Если ваша рабочая нагрузка требует более длинных запросов, просто установите для этих параметров более высокое значение.

Макс Малыш
источник
1
Это решение, которое мы в конечном итоге использовали. Похоже, лучший компромисс между всеми вариантами, представленными здесь.
mohit6up
2
Это лучший ответ. Обратите внимание, что в соответствии с документами они накапливаются; если у вас есть несколько запросов к реплике, удерживающей репликацию, возможно, вы получите 899, тогда еще 2-секундный запрос будет отменен. Лучше всего реализовать некоторую экспоненциальную задержку в вашем коде. Кроме того, задержка потоковой передачи действует во время репликации потоковой передачи. Если репликация не успевает за потоковой передачей, она перейдет к репликации из архива. Если вы выполняете репликацию из архива, вам, вероятно, следует позволить ему наверстать упущенное, max_standby_archive_delayвозможно, оно должно быть меньше, чем у другого.
Давос
2
Это все еще лучшее решение здесь. Обратите внимание, что в Redshift вы можете установить это с помощью настроек группы параметров, только в том случае, если оно должно быть ms, т.е. 900 с = 16 минут = 900 000 мс.
NullDev
Чтобы обновить это в GCP, также ms сделайте
howMuchCheeseIsTooMuchCheese
При условии, что целью режима ожидания является, например, создание отчетов, и это не горячий резерв, который должен быть готов к обработке отказа, это абсолютно лучший ответ.
борщ
77

Нет необходимости запускать незанятые транзакции на мастере. В postgresql-9.1 самый прямой способ решить эту проблему - установить

hot_standby_feedback = on

Это позволит мастеру знать о длительных запросах. Из документов :

Первый вариант - установить параметр hot_standby_feedback, который не позволяет VACUUM удалять недавно мертвые строки, поэтому конфликты очистки не возникают.

Почему это не по умолчанию? Этот параметр был добавлен после первоначальной реализации, и это единственный способ, которым резервный режим может повлиять на мастер.

eradman
источник
11
Этот параметр должен быть установлен в режиме ожидания.
Стив Кехлет
3
В этом случае у мастера есть некоторые недостатки Hot-Standby-Feedback
Евгений Лисковец
50

Как сказано здесь о hot_standby_feedback = on:

Ну, недостатком этого является то, что в режиме ожидания может раздуть мастер, что также может быть удивительно для некоторых людей

И здесь :

С какой настройкой max_standby_streaming_delay? Я бы предпочел по умолчанию это -1, чем по умолчанию hot_standby_feedback on. Таким образом, то, что вы делаете в режиме ожидания, влияет только на режим ожидания.


И я добавил

max_standby_streaming_delay = -1

И не более pg_dump ошибок для нас, ни мастер блат :)

Для экземпляра AWS RDS проверьте http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.html

Жиль Квено
источник
1
@lennard, это сработало для меня. Я добавил эту конфигурацию в postgresql.conf ведомого, затем перезапустил ведомое.
Арди Арам
13
Конечно, вы можете получить неограниченную задержку реплики. И если вы используете слот репликации для подключения реплики к ведущему устройству, это может привести к чрезмерному сохранению xlog на ведущем устройстве, поэтому это действительно возможно только при использовании архивации WAL.
Крейг Рингер
7
Как установить это на AWS RDS?
Крис М.П.
1
@KrisMP Использование PSQL
Йехонатан
4
@KrisMP в группе параметров - docs.aws.amazon.com/AmazonRDS/latest/UserGuide/…
r3m0t
13

Данные таблицы на подчиненном сервере с горячим резервированием изменяются во время выполнения длинного запроса. Решение (PostgreSQL 9.1+), чтобы убедиться, что данные таблицы не изменены, - приостановить репликацию и возобновить работу после запроса:

select pg_xlog_replay_pause(); -- suspend
select * from foo; -- your query
select pg_xlog_replay_resume(); --resume
Дэвид Ясперс
источник
1
Это требует прав суперпользователя. Так что это может быть не решение в некоторых случаях.
Жоао Балтазар
1
В PostgreSQL 10 xlogбыл заменен на wal, поэтому вы хотите позвонить pg_wal_replay_pause()и pg_wal_replay_resume().
Уомбл
3

Возможно, уже слишком поздно для ответа, но мы сталкиваемся с такой же проблемой производства. Ранее у нас была только одна RDS, и по мере увеличения числа пользователей на стороне приложения мы решили добавить для нее Read Replica. Реплика чтения корректно работает на стадии подготовки, но как только мы перешли в производство, мы начинаем получать ту же ошибку.

Таким образом, мы решаем это, включив hot_standby_feedback свойство в свойствах Postgres. Мы ссылались на следующую ссылку

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

Надеюсь, это поможет.

Tushar.k
источник
2

Я собираюсь добавить обновленную информацию и ссылки на отличный ответ @ max-malysh выше.

Короче говоря, если вы делаете что-то на ведущем устройстве, его необходимо скопировать на ведомое устройство. Для этого Postgres использует записи WAL, которые отправляются после каждого зарегистрированного действия на ведущем устройстве на ведомое устройство. Затем подчиненное устройство выполняет действие, и оба снова синхронизируются. В одном из нескольких сценариев вы можете вступать в конфликт на подчиненном с тем, что поступает от мастера в действии WAL. В большинстве из них на ведомом устройстве происходит транзакция, которая конфликтует с тем, что хочет изменить действие WAL. В этом случае у вас есть два варианта:

  1. Немного задержите применение действия WAL, позволяя ведомому устройству завершить конфликтующую транзакцию, затем примените действие.
  2. Отмените конфликтующий запрос на подчиненном.

Мы имеем дело с # 1 и двумя значениями:

  • max_standby_archive_delay - это задержка, используемая после длительного разъединения между ведущим и ведомым, когда данные считываются из архива WAL, который не является текущими данными.
  • max_standby_streaming_delay - задержка, используемая для отмены запросов при получении записей WAL посредством потоковой репликации.

Как правило, если ваш сервер предназначен для репликации высокой доступности, вы хотите, чтобы эти цифры были короткими. Для этого достаточно значения по умолчанию 30000(миллисекунды, если не указано ни одной единицы). Однако, если вы хотите настроить что-то вроде архива, реплик-отчета или реплики чтения, у которых могут быть очень долго выполняющиеся запросы, вам нужно установить это значение выше, чтобы избежать отмененных запросов. Рекомендуемая 900sнастройка выше кажется хорошей отправной точкой. Я не согласен с официальными документами об установке бесконечного значения -1в качестве хорошей идеи - это может замаскировать некоторый глючный код и вызвать множество проблем.

Единственное предупреждение о длительных запросах и более высоких значениях этих параметров заключается в том, что другие запросы, выполняющиеся на ведомом устройстве параллельно с длительным запросом, который вызывает задержку действия WAL, будут видеть старые данные до тех пор, пока длинный запрос не будет завершен. Разработчики должны понимать это и сериализовать запросы, которые не должны выполняться одновременно.

Для полного объяснения того, как max_standby_archive_delayи как max_standby_streaming_delayработать и почему, перейдите сюда .

Artif3x
источник
1

Точно так же, вот второе предостережение к @ Artif3x о превосходном ответе @ max-malysh, оба выше.

При любом отложенном применении транзакций от мастера у последователей будет более старое, устаревшее представление данных. Поэтому, предоставляя время для завершения запроса на последователе, установив max_standby_archive_delay и max_standby_streaming_delay, имеет смысл учитывать оба этих предостережения:

Если значение подписчика для резервного копирования оказывается слишком конфликтующим с запросами хостинга, одним из решений будет несколько подписчиков, каждый из которых оптимизирован для одного или другого.

Кроме того, обратите внимание, что несколько запросов подряд могут привести к задержке применения записей wal. Таким образом, при выборе новых значений, это не просто время для отдельного запроса, а движущееся окно, которое начинается всякий раз, когда начинается конфликтующий запрос, и заканчивается, когда наконец-то применяется запись wal.

боб
источник