Diagnosticando e Resolvendo Problemas Comuns de Atraso na Replicação do MongoDB

Navegue pelas complexidades do atraso na replicação do MongoDB com este guia abrangente. Aprenda a identificar, diagnosticar e resolver problemas comuns que comprometem a consistência dos dados e a alta disponibilidade em seus conjuntos de réplicas. O artigo aborda desde a compreensão do oplog e a detecção de atraso com `rs.status()` até soluções práticas para tamanho insuficiente do oplog, gargalos de rede, restrições de recursos e índices ausentes. Equipe-se com estratégias acionáveis e melhores práticas para manter um ambiente MongoDB saudável, performático e resiliente.

Diagnosticando e Resolvendo Problemas Comuns de Atraso na Replicação do MongoDB

O atraso na replicação do MongoDB não é apenas um número em um painel. Ele muda como sua aplicação se comporta. Um usuário atualiza um perfil, outra solicitação lê de um secundário e o valor antigo retorna. Um nó falha, mas o melhor secundário ainda está atrasado, então o failover leva mais tempo do que o esperado. Uma consulta de relatório cai no membro errado e, de repente, o conjunto de réplicas parece saudável, exceto por um secundário que continua se distanciando do primário.

A maneira útil de pensar sobre o atraso na replicação é simples: o primário está produzindo entradas de oplog mais rápido do que um ou mais secundários podem buscá-las e aplicá-las. A correção depende de qual lado dessa frase é verdadeiro no seu ambiente. Às vezes, o primário está escrevendo demais em rajadas. Às vezes, o secundário é subdimensionado. Às vezes, a rede está lenta. Às vezes, o atraso é intencional porque o membro está configurado com secondaryDelaySecs. Seu primeiro trabalho é separar esses casos antes de fazer alterações.

Comece com a Forma Real do Atraso

Não comece redimensionando o oplog ou reiniciando o mongod. Primeiro, descubra se o atraso é constante, irregular, limitado a um membro ou afeta todos os secundários.

No mongosh, comece com:

rs.status()

Observe os campos stateStr, optimeDate, lastHeartbeatMessage e health de cada membro. Se um secundário está atrasado e os outros estão atualizados, você provavelmente tem um problema específico do membro: disco, CPU, leituras locais, manutenção local ou um caminho de rede ruim. Se todos os secundários estão atrasados, investigue mais a fundo o volume de gravação do primário, a taxa de transferência de rede saindo do primário ou uma operação excepcionalmente grande.

Para uma verificação rápida da janela do oplog, execute:

rs.printReplicationInfo()

A janela do oplog informa quanto tempo é coberto pelo oplog atual. Isso não significa que a replicação está saudável. Indica o quão atrás um secundário pode ficar antes de correr o risco de precisar de uma sincronização inicial. Se sua janela de oplog é de 6 horas e suas janelas de manutenção rotineiramente levam 8 horas, você tem um risco operacional real, mesmo quando o atraso atual é zero.

Para secundários, isso também é útil:

rs.printSecondaryReplicationInfo()

Em exemplos mais antigos, você pode ver rs.printSlaveReplicationInfo(). A terminologia mais recente usa "secondary", mas helpers de shell mais antigos e postagens de blog mais antigas ainda podem usar "slave". Os campos importam mais do que o nome.

Se você quiser um pequeno script para um shell ao vivo, compare o optime do primário com cada secundário:

const status = rs.status();
const primary = status.members.find(m => m.stateStr === "PRIMARY");

status.members
  .filter(m => m.stateStr === "SECONDARY")
  .forEach(m => {
    const lagSeconds = (primary.optimeDate - m.optimeDate) / 1000;
    print(`${m.name}: ${lagSeconds}s atrás do primário`);
  });

Trate isso como um instantâneo, não como um diagnóstico. Um secundário que está 20 segundos atrás durante uma importação em lote pode estar bem se ele alcançar rapidamente. Um secundário que está sempre 20 segundos atrás durante o tráfego normal merece atenção.

Verifique se o Atraso é Intencional

Antes de perseguir um incidente falso, inspecione a configuração do conjunto de réplicas:

rs.conf()

Um membro atrasado é configurado para ficar atrás do primário por design. Na configuração moderna do MongoDB, procure por secondaryDelaySecs em um membro. Esse membro é útil para alguns cenários de recuperação porque pode preservar uma visão mais antiga dos dados por um curto período. Ele não deve ser usado para leituras recentes, e seu atraso esperado deve ser excluído dos alertas normais de atraso.

O erro que vejo em operações reais é alertar sobre cada membro atrasado como se estivesse quebrado. Alerte sobre atraso além do atraso configurado. Se um membro está atrasado em 1 hora e mostra 1 hora e 5 minutos de atraso, o atraso real é de cerca de 5 minutos.

Quando a Janela do Oplog é Muito Pequena

O oplog é uma coleção limitada no banco de dados local. Os secundários o leem e aplicam as operações em ordem. Se um secundário ficar tão atrasado que o primário não possui mais as entradas de oplog necessárias, a recuperação normal não é mais possível. O membro geralmente precisa de uma sincronização inicial ou de uma restauração a partir de um backup adequado.

É por isso que a janela do oplog é importante. Você quer que ela cubra mais do que seu tempo de inatividade esperado, manutenção, interrupção de rede e picos de gravação. Não existe um tamanho de oplog "correto" universal. Um cluster silencioso pode manter dias de histórico em um oplog pequeno. Um cluster ocupado com atualizações pesadas pode consumir o mesmo tamanho em um curto período.

Se a janela do oplog está diminuindo durante o tráfego de pico, aumente-a antes da próxima janela de manutenção. Em versões suportadas do MongoDB, use replSetResizeOplog em vez de descartar e recriar local.oplog.rs. Descartar o oplog em um membro do conjunto de réplicas é uma manobra de recuperação de alto risco, não uma etapa de ajuste normal.

Execute o comando de redimensionamento no membro cujo oplog você deseja redimensionar:

use admin
db.adminCommand({ replSetResizeOplog: 1, size: 10240 })

O valor size está em megabytes. Um valor de 10240 significa aproximadamente 10 GB. Redimensione cada membro conforme necessário. Em ambientes gerenciados, como MongoDB Atlas, use o caminho de configuração suportado pela plataforma em vez de assumir controle direto do sistema de arquivos ou processo.

Após redimensionar, verifique a nova janela sob carga de gravação real. Um oplog maior reduz a chance de cair do oplog, mas não faz um secundário lento aplicar operações mais rapidamente.

Quando um Secundário é Lento

Se apenas um secundário está atrasado, faça login nesse host e observe os sintomas comuns do sistema. O MongoDB é frequentemente culpado pelo que é realmente saturação de disco.

Use ferramentas como:

iostat -xz 1
vmstat 1
top
mongostat --host secondary.example.com:27017
mongotop --host secondary.example.com:27017

Alta utilização de disco, altos tempos de espera ou uma longa fila de E/S geralmente significam que o secundário não consegue escrever rápido o suficiente. Isso pode acontecer quando um tipo de instância mais barato é usado para secundários, quando o EBS ou armazenamento de rede tem taxa de transferência provisionada menor, ou quando backups e snapshots do sistema de arquivos são executados ao mesmo tempo que as gravações de pico da aplicação.

A CPU também pode importar, especialmente com compressão, criptografia, movimentação de documentos, manutenção de índices ou uma carga de trabalho com muitas pequenas atualizações. A pressão de memória se manifesta como page faults, rotatividade de cache e um secundário que continua lendo do disco enquanto tenta aplicar entradas de oplog.

A correção prática é geralmente entediante: dê ao secundário armazenamento e CPU comparáveis ao primário, reduza o trabalho concorrente nesse host ou mova leituras pesadas para outro lugar. Um membro do conjunto de réplicas não é capacidade de relatório gratuita. Ele ainda precisa acompanhar a replicação.

Quando Leituras em Secundários Causam o Problema

O dimensionamento de leitura com secundários é útil, mas é fácil exagerar. Uma consulta de painel que varre uma grande coleção pode competir com a aplicação do oplog. O secundário ainda pode aceitar leituras, mas a replicação fica para trás porque a mesma CPU, cache e disco estão sendo usados para consultas de usuário.

Verifique o profiler e as operações atuais no membro atrasado:

db.currentOp({ active: true })

Se você vir leituras longas, trabalhos de agregação ou scripts de manutenção, decida se esse secundário realmente deve atender a essa carga de trabalho. Para relatórios, um secundário oculto ou dedicado pode ser mais adequado. Para leituras de aplicação, defina maxStalenessSeconds para que o driver evite secundários que estão muito atrasados.

Para caminhos críticos de consistência, use leituras do primário. Exemplos incluem estado de login, confirmação de checkout, alterações de senha, configurações de conta e qualquer coisa onde um usuário espera ler sua própria gravação imediatamente. Leituras secundárias são melhores para dados onde a desatualização breve é aceitável.

Quando o Primário Produz Rajadas

Gravações grandes podem fazer secundários saudáveis parecerem quebrados. Importações em massa, atualizações amplas de vários documentos, limpeza de TTL, exclusões grandes e alterações de índice podem produzir uma rajada de atividade de oplog que leva tempo para ser aplicada.

Procure por operações recentes no primário:

db.currentOp({ active: true })

Verifique também deploys de aplicação, trabalhos de reparo de dados, backfills e tarefas agendadas. O atraso na replicação que começa exatamente às 02:00 geralmente não é misterioso. É um trabalho em lote.

Quando você controla o trabalho, divida-o em partes menores. Por exemplo, atualize documentos por intervalos de _id, pause entre os lotes e observe o atraso enquanto o trabalho é executado. Com bulkWrite, gravações não ordenadas podem melhorar a taxa de transferência, mas o tratamento de erros precisa ser explícito porque as falhas podem ser parciais. O objetivo nem sempre é fazer o primário terminar o mais rápido possível. O objetivo é permitir que o conjunto de réplicas absorva o trabalho sem perder sua margem de recuperação.

Índices e Aplicação do Oplog

Em um conjunto de réplicas normal, os índices são replicados. Se os índices diferirem entre os membros devido a trabalho manual, manutenção com falha ou um nó que foi restaurado incorretamente, um secundário pode se tornar dolorosamente lento ao aplicar atualizações e exclusões. A operação do oplog pode precisar encontrar um documento e, sem o índice esperado, o secundário pode fazer muito mais trabalho do que o primário fez.

Compare as definições de índice nas coleções afetadas:

db.orders.getIndexes()

Execute o mesmo comando no primário e no secundário atrasado. Se eles diferirem, descubra o porquê antes de fazer mais alterações. Reconstruir um índice grande pode, por si só, criar carga, então planeje-o durante um período tranquilo ou reconstrua o membro a partir de uma fonte conhecida e boa se a divergência for ampla.

Não use conselhos antigos que dizem que as construções de índice em segundo plano resolvem todas as preocupações de replicação. O comportamento de construção de índice do MongoDB mudou entre versões, e a escolha operacional correta depende da sua versão e topologia. Use a documentação atual do servidor para a versão exata que você executa.

Problemas de Rede Geralmente São Visíveis em Outro Lugar

O atraso de rede tende a se manifestar como heartbeats instáveis, erros intermitentes ou baixa taxa de transferência entre hosts ou regiões específicas. Verificações básicas ainda ajudam:

ping primary.example.com
traceroute primary.example.com

Mas baixa latência de ping não prova largura de banda suficiente. A replicação pode ser limitada pela taxa de transferência, perda de pacotes, inspeção de firewall, links entre regiões ou rede compartilhada ruidosa. Se o atraso aparecer apenas para um secundário remoto, compare-o com um secundário na mesma região do primário. Se os membros da mesma região estão bem e o membro remoto está atrasado, a topologia pode estar exigindo demais do link.

Para conjuntos de réplicas entre regiões, seja honesto sobre a compensação. Eles podem ajudar na recuperação de desastres, mas estão mais expostos a limites de latência e largura de banda. Se o membro remoto é destinado a leituras, use controles de desatualização e teste o comportamento de failover em vez de assumir que ele se comportará como um secundário local.

Tenha Cuidado com Conselhos de Reinicialização e Ressincronização

Reiniciar o mongod pode limpar um problema transitório, mas também pode piorar um incidente se o nó estiver perto de cair do oplog. Antes de reiniciar, verifique a janela do oplog e o atraso atual. Se o nó precisar de duas horas para alcançar e a janela do oplog for de apenas três horas durante o tráfego de pico, uma reinicialização longa pode deixá-lo com uma sincronização inicial em vez de uma recuperação.

A sincronização inicial é uma opção de reparo válida quando um secundário está desatualizado, corrompido ou sem o histórico de oplog necessário. Também é cara. Ela copia dados, constrói índices e consome recursos de rede e disco das fontes de sincronização. Em produção, prefira adicionar ou reconstruir um membro de cada vez para que o conjunto de réplicas mantenha membros votantes e portadores de dados suficientes para tolerar falhas.

Se um membro está tão atrasado que não consegue alcançar, siga um caminho baseado em backup ou snapshot fresco que corresponda aos seus padrões operacionais. Não exclua um diretório de dados porque uma lista de verificação diz isso. Confirme que o membro é descartável, confirme que o conjunto de réplicas pode tolerar a reconstrução e confirme que você tem janela de oplog suficiente ou uma fonte de sincronização inicial confiável.

Alerte sobre o que Usuários e Operadores se Importam

Um bom alerta não é "o atraso na replicação é maior que 1 segundo" para todos os sistemas. Algumas aplicações podem tolerar 30 segundos em leituras de análise. Outras não podem tolerar leituras desatualizadas no estado da conta. Os limites de alerta devem refletir o caso de uso.

Alertas úteis incluem:

  • Atraso na replicação acima da tolerância da aplicação por um período sustentado.
  • Janela do oplog abaixo do maior intervalo esperado de manutenção ou recuperação.
  • Um secundário em estado RECOVERING, STARTUP2 ou não saudável por mais tempo que o esperado.
  • Saturação de E/S de disco em qualquer membro portador de dados.
  • Falhas de heartbeat ou erros de rede entre membros.

Os painéis devem mostrar o atraso ao lado do volume de gravação, latência de disco, CPU, pressão de memória e taxa de transferência de rede. O atraso por si só diz que há um problema. Os gráficos vizinhos geralmente dizem qual problema.

Uma Ordem de Triagem Prática

Quando você está de plantão, use esta ordem:

  1. Confirme quais membros estão atrasados com rs.status().
  2. Verifique se algum atraso é intencional devido a secondaryDelaySecs.
  3. Verifique a janela do oplog com rs.printReplicationInfo().
  4. Compare o atraso com picos de gravação, trabalhos em lote e deploys recentes.
  5. Inspecione o disco, CPU, memória e carga de consulta local do secundário atrasado.
  6. Verifique erros de rede e latência entre os membros afetados.
  7. Decida se o membro pode alcançar, precisa de carga removida, precisa de mais recursos ou deve ser reconstruído.

O melhor resultado geralmente não é um comando dramático. É encontrar o gargalo e removê-lo sem criar divergência de dados. O atraso na replicação do MongoDB é gerenciável quando você o trata como um sinal de capacidade e topologia, não como uma falha genérica do MongoDB.