PostgreSQL ERROR: cancelando declaração devido a conflito com recuperação

139

Estou recebendo o seguinte erro ao executar uma consulta em um banco de dados PostgreSQL no modo de espera. A consulta que causa o erro funciona bem por 1 mês, mas quando você consulta por mais de 1 mês, ocorre um erro.

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

Alguma sugestão sobre como resolver? obrigado

Um aprendiz
fonte
Encontre o documento da AWS que mencionou esse erro. Ele também tem a solução aws.amazon.com/blogs/database/…
arunjos007

Respostas:

89

A execução de consultas no servidor em espera ativa é um pouco complicada - pode falhar, porque durante a consulta, algumas linhas necessárias podem ser atualizadas ou excluídas no primário. Como o primário não sabe que uma consulta foi iniciada no secundário, ele acha que pode limpar (aspirar) versões antigas de suas linhas. Em seguida, o secundário precisa repetir essa limpeza e cancelar forçosamente todas as consultas que podem usar essas linhas.

Consultas mais longas serão canceladas com mais frequência.

Você pode contornar isso iniciando uma transação de leitura repetível no primário, que faz uma consulta fictícia e fica ociosa enquanto uma consulta real é executada no secundário. Sua presença impedirá a limpeza de versões antigas de linha no primário.

Mais sobre esse assunto e outras soluções alternativas são explicadas na seção Hot Standby - Manipulando conflitos de consulta na documentação.

Tometzky
fonte
10
Para usuários do PostgreSQL 9.1+: veja a resposta do eradman abaixo para uma solução prática.
Zoltán
3
Para os usuários do PostgreSQL 9.1+: a resposta de max-malysh é muito mais saudável. Não faça a sugestão de erradman, a menos que compreenda os riscos.
Davos
91

Não há necessidade de tocar hot_standby_feedback. Como outros já mencionaram, configurá-lo para onpode inchar o mestre. Imagine abrir uma transação em um escravo e não fechá-la.

Em vez disso, defina max_standby_archive_delaye max_standby_streaming_delaycom algum valor sensato:

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

Dessa forma, consultas em escravos com duração inferior a 900 segundos não serão canceladas. Se sua carga de trabalho exigir consultas mais longas, basta definir essas opções para um valor mais alto.

Max Malysh
fonte
1
Esta é a solução que acabamos usando. Parece o melhor compromisso entre todas as opções apresentadas aqui.
mohit6up
2
Esta é a melhor resposta. Observe de acordo com os documentos que são cumulativos; se você tiver várias consultas na réplica que sustentam a replicação, pode ser que você chegue ao 899 e outra consulta de 2 segundos será cancelada. É melhor implementar apenas um retorno exponencial no seu código. Além disso, o atraso da transmissão está em vigor enquanto a replicação está sendo transmitida. Se a replicação não conseguir acompanhar o fluxo, ela passará para a replicação do arquivo morto. Se você estiver replicando a partir do arquivo morto, provavelmente deverá deixá-lo em dia, max_standby_archive_delaytalvez seja necessário que seja menor que o outro.
Davos
2
Essa ainda é a melhor solução aqui. Observe que no Redshift, você pode definir isso através das configurações do grupo de parâmetros, apenas que ele deve estar ms, ou seja, 900s = 16 minutos = 900000ms.
NullDev
Para atualizar isso no GCP, também feito em ms cloud.google.com/sql/docs/postgres/…
howMuchCheeseIsTooMuchCheese
Desde que o objetivo do modo de espera seja, por exemplo, relatórios e não seja um modo de espera quente que precise estar pronto para lidar com o failover, esta é absolutamente a melhor resposta.
18269 sopadog
77

Não é necessário iniciar transações inativas no mestre. No postgresql-9.1, a maneira mais direta de resolver esse problema é configurando

hot_standby_feedback = on

Isso tornará o mestre ciente de consultas de longa duração. Dos documentos :

A primeira opção é definir o parâmetro hot_standby_feedback, que evita que o VACUUM remova linhas recentemente mortas e, portanto, não ocorrem conflitos de limpeza.

Por que esse não é o padrão? Este parâmetro foi adicionado após a implementação inicial e é a única maneira que um modo de espera pode afetar um mestre.

eradman
fonte
11
Este parâmetro deve ser definido no modo de espera.
precisa saber é o seguinte
3
Existem algumas desvantagens para o mestre nesse caso Hot-Standby-Feedback
Evgeny Liskovets
50

Como afirmado aqui sobre hot_standby_feedback = on:

Bem, a desvantagem disso é que o modo de espera pode inchar o mestre, o que também pode ser surpreendente para algumas pessoas

E aqui :

Com que configuração de max_standby_streaming_delay? Eu prefiro que -1 como padrão do que hot_standby_feedback ativado. Dessa forma, o que você faz no modo de espera afeta apenas o modo de espera


Então eu adicionei

max_standby_streaming_delay = -1

E nada mais pg_dump erro para nós, nem mestre inchaço :)

Para uma instância do AWS RDS, consulte http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.html

Gilles Quenot
fonte
1
@ennard, isso funcionou para mim. Eu adicionei essa configuração no postgresql.conf do escravo, depois reiniciei o escravo.
Ardee Aram
13
É possível obter lag de réplica ilimitada dessa maneira, é claro. E se você estiver usando um slot de replicação para conectar a réplica ao mestre, isso pode resultar em retenção excessiva de xlog no mestre, portanto, só é realmente viável se você estiver usando o arquivamento WAL.
Craig Ringer
7
Como definir isso no AWS RDS?
Kris MP
1
@KrisMP Use psql
Yehonatan
4
@KrisMP no grupo de parâmetros - docs.aws.amazon.com/AmazonRDS/latest/UserGuide/…
r3m0t:
13

Os dados da tabela no servidor escravo de espera quente são modificados enquanto uma consulta de execução longa está em execução. Uma solução (PostgreSQL 9.1+) para garantir que os dados da tabela não sejam modificados é suspender a replicação e continuar após a consulta:

select pg_xlog_replay_pause(); -- suspend
select * from foo; -- your query
select pg_xlog_replay_resume(); --resume
David Jaspers
fonte
1
Isso requer direitos de superusuário. Portanto, pode não ser uma solução em alguns casos.
João Baltazar
1
No PostgreSQL 10, xlogfoi substituído por wal, então você deseja chamar pg_wal_replay_pause()e pg_wal_replay_resume().
Womble 13/02/19
3

Pode ser tarde demais para a resposta, mas enfrentamos o mesmo tipo de problema na produção. Antes, possuímos apenas um RDS e, à medida que o número de usuários aumenta no lado do aplicativo, decidimos adicionar a Read Replica. A réplica de leitura funciona corretamente na preparação, mas depois que passamos para a produção, começamos a receber o mesmo erro.

Portanto, resolvemos isso ativando a propriedade hot_standby_feedback nas propriedades do Postgres. Referimos o seguinte link

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

Eu espero que isso ajude.

Tushar.k
fonte
2

Vou adicionar algumas informações e referências atualizadas à excelente resposta do @ max-malysh acima.

Em resumo, se você fizer algo no mestre, ele precisará ser replicado no escravo. O Postgres usa registros WAL para isso, que são enviados após cada ação registrada no mestre para o escravo. O escravo então executa a ação e os dois estão novamente sincronizados. Em um dos vários cenários, você pode entrar em conflito com o escravo com o que vem do mestre em uma ação WAL. Na maioria deles, há uma transação acontecendo no escravo que entra em conflito com o que a ação do WAL deseja alterar. Nesse caso, você tem duas opções:

  1. Atrase um pouco a aplicação da ação WAL, permitindo que o escravo termine sua transação conflitante e aplique a ação.
  2. Cancele a consulta conflitante no escravo.

Estamos preocupados com o número 1 e dois valores:

  • max_standby_archive_delay - este é o atraso usado após uma longa desconexão entre o mestre e o escravo, quando os dados estão sendo lidos de um arquivo WAL, que não são dados atuais.
  • max_standby_streaming_delay - atraso usado para cancelar consultas quando entradas WAL são recebidas via replicação de streaming.

Geralmente, se o seu servidor se destina à replicação de alta disponibilidade, você deseja manter esses números curtos. A configuração padrão de 30000(milissegundos se nenhuma unidade for fornecida) é suficiente para isso. Se, no entanto, você deseja configurar algo como um arquivo, réplica ou réplica de leitura que possa ter consultas muito demoradas, defina isso como algo mais alto para evitar consultas canceladas. A 900sconfiguração recomendada acima parece ser um bom ponto de partida. Não concordo com os documentos oficiais sobre como definir um valor infinito-1 como uma boa idéia - que pode mascarar algum código de buggy e causar muitos problemas.

A única ressalva sobre consultas de longa execução e configuração desses valores mais altos é que outras consultas em execução no escravo em paralelo com a de longa execução que está causando o atraso da ação do WAL verão os dados antigos até que a longa consulta seja concluída. Os desenvolvedores precisarão entender isso e serializar consultas que não devem ser executadas simultaneamente.

Para obter uma explicação completa de como max_standby_archive_delaye como max_standby_streaming_delayfunciona e por que, clique aqui .

Artif3x
fonte
1

Da mesma forma, aqui está uma segunda ressalva à elaboração do @ Artif3x da excelente resposta do @ max-malysh, ambas acima.

Com qualquer aplicação atrasada de transações do mestre, o (s) seguidor (es) terá uma visão antiga e obsoleta dos dados. Portanto, ao mesmo tempo em que fornece tempo para a consulta do seguidor, definindo max_standby_archive_delay e max_standby_streaming_delay faz sentido, lembre-se de ambas as advertências:

Se o valor do seguidor para backup acabar entrando em conflito com as consultas de hospedagem, uma solução seria vários seguidores, cada um otimizado para um ou outro.

Além disso, observe que várias consultas seguidas podem fazer com que o aplicativo de entradas wal fique atrasado. Portanto, ao escolher os novos valores, não é apenas o tempo para uma única consulta, mas uma janela em movimento que inicia sempre que uma consulta conflitante é iniciada e termina quando a entrada wal é finalmente aplicada.

prumo
fonte