Solução de Problemas de Atraso na Replicação do MongoDB: Causas e Soluções
Aprenda a diagnosticar e resolver o atraso na replicação em conjuntos de réplicas do MongoDB. Este guia aborda causas comuns, incluindo altas cargas de escrita, gargalos de hardware e problemas de rede. Descubra técnicas de monitoramento acionáveis usando `rs.printReplicationInfo()` e soluções práticas para manter a sincronização de dados, garantindo alta disponibilidade e consistência de leitura em todos os nós do banco de dados.
Solução de Problemas de Atraso na Replicação do MongoDB: Causas e Soluções
O atraso na replicação do MongoDB geralmente começa como um pequeno incômodo operacional. Um gráfico começa a subir. Um secundário fica 15 segundos atrás, depois 2 minutos. Alguém pergunta se as leituras estão desatualizadas. Outra pessoa sugere reiniciar o nó. Antes de fazer isso, vá com calma e descubra qual parte da replicação está perdendo terreno.
Os secundários do MongoDB copiam operações do oplog do primário e as aplicam localmente. O atraso na replicação significa que um secundário não aplicou operações tão recentemente quanto o primário. Isso pode afetar leituras secundárias, backups feitos a partir de secundários, trabalhos de análise e failover. Também pode esconder um risco maior: se o secundário ficar mais atrás do que a janela do oplog, pode não conseguir alcançar o oplog.
O caminho mais rápido para solucionar problemas é responder a três perguntas:
- Todos os secundários estão atrasados, ou apenas um?
- O atraso é temporário, constante ou crescente?
- O secundário ainda está dentro da janela do oplog?
Essas respostas decidem o que fazer a seguir.
Meça o Atraso Sem Adivinhar
Comece no mongosh:
rs.status()
Encontre o primário e compare seu optimeDate com o optimeDate de cada secundário. Também procure por membros não saudáveis, mensagens de heartbeat e membros presos em estados como RECOVERING ou STARTUP2.
Para um resumo mais amigável, execute:
rs.printSecondaryReplicationInfo()
Alguns materiais mais antigos usam rs.printSlaveReplicationInfo(). Se você mantém sistemas antigos, ainda pode ver esse helper. A redação moderna é "secondary".
Em seguida, verifique a janela do oplog:
rs.printReplicationInfo()
A janela do oplog é a quantidade de histórico atualmente retida no oplog. Se o seu secundário está 40 minutos atrás e a janela do oplog é de vários dias, você tem espaço para solucionar problemas. Se o seu secundário está 40 minutos atrás e a janela do oplog é de 1 hora durante o pico de tráfego, você está perto de uma situação de reconstrução.
Não confie apenas em valores do tipo SecondsBehind de uma única ferramenta. Diferença de clock, membros atrasados e picos breves podem tornar um número enganoso. Compare a saída de status com gráficos de monitoramento para volume de escrita, latência de disco, CPU e throughput de rede.
Se Todos os Secundários Estão Atrasados
Quando todos os secundários ficam atrás aproximadamente ao mesmo tempo, a causa geralmente está a montante de qualquer secundário. Observe primeiro a carga de trabalho de escrita do primário.
Gatilhos comuns incluem:
- Importações em massa ou backfills.
- Operações grandes de
updateManyoudeleteMany. - Limpeza TTL após um período de backlog.
- Implantações de aplicativos que alteraram o volume de escrita.
- Construções de índice ou manutenção de esquema.
- Um aumento repentino em pequenas escritas que criam muitas entradas de oplog.
Pergunte o que mudou ao mesmo tempo em que o atraso começou. Um pico que começa exatamente quando um trabalho noturno começa raramente é um mistério do MongoDB.
No primário, inspecione as operações ativas:
db.currentOp({ active: true })
Se você encontrar um trabalho em lote, considere limitá-lo em vez de deixá-lo terminar na velocidade máxima. Por exemplo, processe documentos em intervalos de _id, durma entre os lotes e observe o atraso. Isso é especialmente útil para trabalhos de limpeza onde terminar em 30 minutos é menos importante do que manter o conjunto de réplicas saudável.
Se o volume de escrita sustentado é simplesmente maior do que o conjunto de réplicas pode suportar, você precisa de uma mudança de capacidade ou arquitetura. Discos melhores, mais CPU, uma classe de instância diferente, otimização do caminho de escrita ou sharding podem ser a resposta certa. Alterar a preferência de leitura não corrigirá um primário que está produzindo mais trabalho do que o conjunto pode aplicar.
Se Apenas Um Secundário Está Atrasado
Um secundário atrasado geralmente aponta para um problema local. Faça login nesse host e verifique o básico:
iostat -xz 1
vmstat 1
top
Dentro do MongoDB, use:
mongostat --host secondary.example.com:27017
mongotop --host secondary.example.com:27017
O disco é um culpado comum. Um secundário usando armazenamento mais lento que o primário pode ficar bem durante o tráfego normal e depois ficar para trás durante picos. Volumes em nuvem também podem atingir limites de throughput ou IOPS. Procure por alta utilização, altos tempos de espera e filas.
A CPU pode importar quando a carga de trabalho inclui muitas atualizações, compressão, criptografia ou tráfego pesado de consultas no mesmo membro. A pressão de memória importa quando o secundário não consegue manter dados quentes e índices em cache enquanto aplica escritas.
Verifique também o que mais está sendo executado no host. Backups, varreduras de antivírus, snapshots de sistema de arquivos, compressão de logs e consultas de relatórios podem competir com a replicação. Se o nó atrasado também é o "lugar seguro" onde todos executam análises ad-hoc, você provavelmente encontrou o problema.
Leituras em Secundários Podem Criar Atraso
Leituras secundárias não são gratuitas. Elas usam o mesmo cache, CPU e disco que a replicação precisa. Uma única agregação que varre uma grande coleção pode ser suficiente para fazer um secundário ficar para trás durante um período movimentado.
Procure por leituras de longa duração:
db.currentOp({ active: true })
Se o aplicativo envia leituras para secundários, revise a preferência de leitura. secondary pode forçar leituras para membros atrasados. secondaryPreferred ainda pode retornar dados desatualizados. Para fluxos de usuário que devem ler suas próprias escritas, use o primário. Para leituras eventualmente consistentes, defina maxStalenessSeconds para que o driver evite secundários que estão muito atrasados.
Para cargas de trabalho de relatórios, considere um secundário oculto ou um pipeline de análise separado. Membros ocultos ainda podem replicar, mas os drivers não os escolherão para leituras normais. Isso os torna um lugar melhor para backups ou trabalhos de relatórios controlados, desde que você os dimensione adequadamente.
O Tamanho do Oplog é uma Margem de Recuperação, Não uma Correção de Velocidade
Um oplog muito pequeno geralmente não causa atraso por si só. Ele torna o atraso perigoso. Se um secundário ficar para trás e as entradas de oplog necessárias forem sobrescritas, ele não conseguirá alcançar normalmente.
Sua janela de oplog deve ser maior do que seus cenários realistas de interrupção e manutenção. Se um secundário pode ficar offline por 6 horas durante a aplicação de patches, uma janela de oplog de 4 horas não é suficiente. Se uma importação trimestral queima o oplog em algumas horas, dimensione para essa carga de trabalho ou mude como a importação é executada.
Em versões suportadas, redimensione com replSetResizeOplog em cada membro que precisa de um oplog maior:
use admin
db.adminCommand({ replSetResizeOplog: 1, size: 20480 })
Esse exemplo solicita cerca de 20 GB. Em plataformas gerenciadas, use o método de configuração gerenciada. Evite conselhos antigos que descartam e recriam o oplog, a menos que você esteja seguindo um procedimento de recuperação cuidadosamente testado.
Após aumentar o oplog, continue solucionando o atraso subjacente. Um oplog maior lhe dá mais tempo; ele não remove saturação de disco, limites de rede ou picos excessivos de escrita.
Verificações de Rede Que Realmente Ajudam
Problemas de rede são mais prováveis quando o atraso afeta um secundário remoto, uma zona de disponibilidade ou um caminho de datacenter. Comece simples:
ping primary.example.com
traceroute primary.example.com
Em seguida, olhe além da latência. A replicação precisa de throughput confiável. Perda de pacotes, inspeção de firewall, limites de VPN, limites de largura de banda entre regiões ou interfaces de rede sobrecarregadas podem criar atraso mesmo quando o ping parece aceitável.
Se apenas o membro entre regiões está atrasado, compare-o com um secundário local sob a mesma carga de escrita. Você pode precisar de uma topologia diferente, um link maior ou uma expectativa mais clara de que membros remotos são para recuperação de desastres, não para leituras recentes.
Deriva de Dados e Índices
Membros de um conjunto de réplicas devem ter os mesmos índices. Se não tiverem, a aplicação do oplog pode ficar mais lenta ou falhar. Isso geralmente vem de alterações manuais, manutenção com falha ou um membro restaurado de uma fonte inconsistente.
Compare índices em coleções quentes:
db.orders.getIndexes()
Execute no primário e no secundário atrasado. Se as definições diferirem, corrija a deriva deliberadamente. Reconstruir um índice grande pode adicionar mais carga, então agende com cuidado ou reconstrua o membro a partir de uma fonte limpa se as diferenças forem generalizadas.
A divergência de dados é mais séria. Se os erros de replicação mostram registros ausentes ou chaves duplicadas, o atraso não é mais o único problema. Você precisa inspecionar o erro, comparar dados e decidir se um reparo no nível da tabela, ressincronização ou reconstrução completa é o caminho mais seguro.
Seja Conservador com Reinicializações e Sincronização Inicial
Reiniciar um secundário atrasado às vezes ajuda se o processo estiver preso atrás de um problema transitório. Não é uma correção universal. Se o membro está perto da borda da janela do oplog, uma reinicialização pode custar tempo suficiente para empurrá-lo para um estado irrecuperável.
Antes de reiniciar, verifique:
- Atraso atual.
- Janela atual do oplog.
- Se o membro está sincronizando.
- Se existem outros secundários saudáveis.
- Se o conjunto de réplicas pode tolerar o membro ficar inativo.
A sincronização inicial é a resposta limpa quando um secundário não consegue alcançar ou seus dados não são confiáveis. Também é pesada. Ela copia dados, constrói índices e consome recursos de outro membro. Reconstrua um membro de cada vez e certifique-se de que sua configuração de votação ainda suporta eleições seguras enquanto o nó está sendo reconstruído.
Quando Você Não Deve se Apressar para Corrigir
Algum atraso é esperado durante trabalhos controlados. Se você está executando um backfill planejado, restaurando um secundário ou importando dados históricos, a pergunta útil é se o secundário está alcançando a uma taxa aceitável. Um gráfico de atraso que sobe por 20 minutos e depois cai constantemente pode não precisar de intervenção. Um gráfico de atraso que sobe todos os dias e nunca retorna à linha de base, sim.
Essa distinção é importante porque algumas correções são disruptivas. Matar um trabalho em lote pode deixar dados do aplicativo parcialmente atualizados. Reiniciar um secundário pode custar calor de cache e tornar o alcance mais lento. Reconstruir um membro pode consumir mais rede e disco do que simplesmente deixá-lo aplicar o backlog.
Para trabalhos planejados, defina um orçamento de atraso antes do trabalho começar. Por exemplo, você pode decidir que um backfill de manutenção pode criar até 10 minutos de atraso em um secundário de relatórios, mas não em um candidato a failover. Observe o atraso, a janela do oplog e a taxa de escrita enquanto o trabalho é executado. Se o trabalho se aproximar do orçamento, pause-o ou reduza o tamanho do lote.
Também ajuda separar réplicas voltadas para o usuário de réplicas de manutenção. Um secundário usado para leituras de aplicativo deve ter uma tolerância de atraso mais restrita do que um membro oculto usado para backups. Se cada secundário tem um trabalho diferente, os limites de alerta devem refletir esses trabalhos em vez de usar um número para todo o conjunto.
O Que Registrar Durante um Incidente
Incidentes de replicação são muito mais fáceis de entender depois do fato se você salvar a evidência certa. Antes de alterar a configuração, capture:
rs.status()
rs.conf()
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()
Também salve métricas no nível do host do primário e do secundário atrasado: latência de disco, CPU, memória e throughput de rede. Se um trabalho em lote ou implantação estava em execução, registre sua hora de início e comando ou versão do release.
Isso não é papelada por si só. Sem uma linha do tempo, o próximo incidente começa do zero. Com uma linha do tempo, você pode notar que o atraso sempre segue uma exportação, backup ou tarefa de limpeza específica. Isso transforma um vago problema de banco de dados em um problema de capacidade agendável.
Um Mapa Prático de Correções
Use o sintoma para escolher o próximo movimento:
| Sintoma | Área provável | Próxima ação |
|---|---|---|
| Todos os secundários atrasam durante trabalho em lote | Pico de escrita | Limitar ou dividir o trabalho |
| Um secundário sempre atrasa | Problema de recurso local | Verificar disco, CPU, memória e leituras locais |
| Atraso cresce apenas no membro remoto | Rede/topologia | Verificar throughput, perda de pacotes e design entre regiões |
| Atraso está perto da janela do oplog | Risco de recuperação | Aumentar oplog e reduzir fonte de atraso |
| Secundário serve leituras desatualizadas | Preferência de leitura | Usar primário para leituras recentes ou definir maxStalenessSeconds |
| Membro não consegue alcançar após inatividade | Histórico de oplog ausente | Reconstruir a partir de backup ou sincronização inicial |
A boa solução de problemas de replicação do MongoDB é principalmente observação disciplinada. Descubra se o primário está produzindo muito trabalho, o secundário está aplicando muito lentamente ou o link entre eles está limitado. Em seguida, mude a coisa que está realmente limitando a replicação em vez de aplicar uma reinicialização, ressincronização ou ajuste de configuração genérico.