Como soluciono o erro “cancelamento de instrução devido a conflito com a recuperação” ao consultar a réplica de leitura da minha instância de banco de dados do RDS para PostgreSQL?

6 minuto de leitura
0

Eu configurei uma réplica de leitura para minha instância do Amazon Relational Database Service (Amazon RDS) para PostgreSQL. Recebo o erro “cancelando declaração devido a conflito com a recuperação” quando consulto a réplica de leitura.

Breve descrição

Esse erro pode ocorrer devido à falta de visibilidade da instância primária durante a atividade que está acontecendo na réplica de leitura. O conflito com a recuperação ocorre quando as informações WAL não podem ser aplicadas na réplica de leitura porque as alterações podem obstruir uma atividade que está acontecendo na réplica de leitura.

Por exemplo, suponha que você execute uma instrução DROP na instância primária quando uma instrução SELECT de longa duração estiver sendo executada na réplica de leitura na tabela descartada na instância primária. Em seguida, a réplica de leitura tem duas opções:

  • Aguarde até que a instrução SELECT seja concluída antes de aplicar o registro WAL. Nesse caso, o atraso de replicação aumenta.
  • Aplique o registro WAL e cancele a instrução SELECT. Nesse caso, você recebe o erro "cancelamento de declaração devido a conflito com a recuperação".

A réplica de leitura resolve esses conflitos de replicação com base no valor dos parâmetros max_standby_streaming_delay e max_standby_archive_delay. O parâmetromax_standby_streaming_delay determina quanto tempo a réplica de leitura deve esperar antes de cancelar consultas stand-by que estejam em conflito com as entradas WAL que estão prestes a ser aplicadas. Se a instrução conflitante ainda estiver em execução após esse período, o PostgreSQL cancelará a instrução e emitirá a seguinte mensagem de erro:

ERROR: canceling statement due to conflict with recovery

Esse erro geralmente ocorre devido a consultas de longa duração na réplica de leitura.

No exemplo anterior com a instrução DROP, a solicitação DROP é armazenada no arquivo WAL para aplicação posterior na réplica de leitura para consistência. Suponha que uma instrução SELECT já esteja em execução na réplica de leitura que tenta recuperar dados do objeto descartado com um tempo de execução maior que o valor em max_standby_streaming_delay. Em seguida, a instrução SELECT é cancelada para que a instrução DROP possa ser aplicada.

Sessão 1 (Réplica de leitura) Execute uma instrução SELECT em example_table:

postgres=> SELECT * from example_table;

Sessão 2 (Primária) Execute uma instrução DROP emexample_table:

postgres=> DROP TABLE example_table;

Você recebe o seguinte erro:

postgres@postgres:[27544]:ERROR:  canceling statement due to conflict with recovery
postgres@postgres:[27544]:DETAIL:  User was holding a relation lock for too long.
postgres@postgres:[27544]:STATEMENT:  select * from example_table;

Além disso, o conflito na consulta pode ocorrer quando uma transação na réplica de leitura está lendo tuplas definidas para exclusão na instância primária. A exclusão de tuplas seguida de limpeza na instância primária causa um conflito com a consulta SELECT que ainda está em execução na réplica. Nesse caso, a consulta SELECT na réplica é encerrada com a seguinte mensagem de erro:

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

Resolução

Quando uma réplica de leitura encontra um conflito e você recebe o erro “cancelando instrução devido a conflito com a recuperação” no log de erros, você pode definir determinados parâmetros personalizados com base na mensagem de erro para reduzir o impacto do conflito. Observe que os parâmetros personalizados devem ser definidos na réplica de leitura.

Você recebe o erro “cancelando declaração devido a conflito com a recuperação” com “DETALHE: o usuário estava mantendo um bloqueio de relação por muito tempo”

max_standby_streaming_delay/max_standby_archive_delay: você pode usar esses parâmetros para permitir mais tempo antes de cancelar instruções stand-by que entrem em conflito com as entradas WAL prestes a serem aplicadas. Esses valores representam o tempo total permitido para a aplicação de dados WAL depois que os dados são recebidos da instância primária. Esses parâmetros são especificados dependendo de onde os dados WAL são lidos. Se os dados WAL forem lidos da replicação de streaming, use o parâmetro max_standby_streaming_delay. Se os dados WAL forem lidos do local de arquivamento no Amazon Simple Storage Service (Amazon S3), use o parâmetro max_standby_archive_delay.

Lembre-se do seguinte ao definir esses parâmetros:

  • Se você definir os valores desses parâmetros como -1, a instância de réplica poderá esperar para sempre pela conclusão de consultas conflitantes, aumentando o atraso na replicação.
  • Se você definir os valores desses parâmetros como 0, as consultas conflitantes serão canceladas e as entradas WAL serão aplicadas à instância de réplica.
  • O valor padrão para esses parâmetros é definido como 30 segundos.
  • Se você não especificar a unidade ao definir esses parâmetros, milissegundo será considerado como a unidade.

Ajuste os valores desses parâmetros para equilibrar o cancelamento da consulta ou o atraso da replicação com base no seu caso de uso.

Observação: Se você estiver aumentando max_standby_archive_delay para evitar o cancelamento de consultas que entram em conflito com a leitura de entradas de arquivo WAL, considere aumentarmax_standby_streaming_delay também para evitar cancelamentos vinculados a conflitos com entradas WAL de streaming.

Você recebe o erro “cancelando declaração devido a conflito com recuperar” com “DETALHE: a consulta do usuário pode ter sido necessária para ver as versões de linha que devem ser removidas”

hot_standby_feedback: se você ativar esse parâmetro, as mensagens de feedback serão enviadas para a instância primária a partir da réplica de leitura com informações da transação ativa mais antiga. Portanto, a instância primária não remove registros de que a transação possa precisar.

Quando você ativa esse parâmetro na réplica de leitura, consultas de longa duração na réplica de leitura podem levar ao excesso de tabela na instância primária. Isso ocorre porque as operações de limpeza não removem as tuplas mortas que podem ser exigidas pelas consultas executadas na réplica de leitura. Esse parâmetro é desativado por padrão. Portanto, tenha cuidado ao ativar esse parâmetro.

Você também pode inspecionar a exibiçãopg_stat_database_conflicts na réplica de leitura em busca de estatísticas sobre instruções canceladas devido a conflitos com a recuperação na réplica de leitura.