← Todos os casos
Diagnosticar

Metade da telemetria sumiu por 50 dias, e ninguém percebeu

50 diasde metade da telemetria perdida, até o shard voltar a gravar

Um alerta que ninguém via

A plataforma guardava logs, traces e métricas de produção no SigNoz, que roda sobre o ClickHouse com coordenação pelo ZooKeeper. Os dados eram distribuídos por hash entre dois shards.

Fazia dias que um alerta de volume quase cheio estava disparando, mas ele não chegava a ninguém. Só apareceu porque, em outro trabalho, eu tinha religado a entrega de alertas daquele ambiente. Quando fui olhar, o problema era bem maior do que um disco cheio: um dos dois shards não gravava nada fazia mais de 50 dias. Como a distribuição era por hash, cerca de metade de todo log, trace e métrica de produção estava sendo jogada fora em silêncio.

Antes de apagar, medir

O reflexo, nesse caso, é aumentar a retenção ou apagar dado antigo. Antes de qualquer coisa, inventariei o disco por banco de dados do ClickHouse. A telemetria dos clientes ocupava cerca de 241 MiB, ou 0,12% do disco. Os outros 186 GiB eram o log interno de operações do ZooKeeper, uma tabela do próprio banco que crescia sem controle.

Com autorização, expandi o volume do shard de 200 para 400 GiB com o pod no ar, sem reiniciar. O uso caiu de 100% para 50% e o shard voltou a gravar na hora. Deixei registrado o que não tinha volta: os 50 dias de dados daquele shard estavam perdidos.

A causa da causa

Pouco depois veio outro incidente crítico. O NOC limpou a tabela, e em menos de 10 horas ela tinha voltado a 85 GiB. Aquilo não era acúmulo: era uma torneira aberta. Reconstruí a cadeia inteira.

O coletor de telemetria inseria em micro-lotes, com o flush disparado a cada 200 ms e nunca por tamanho. Isso gerava cerca de 65 mil partes novas por hora no ClickHouse, e cada parte gerava dezenas de operações no ZooKeeper: uns 15 milhões de operações por hora por pod. Cada operação gravava duas linhas no log interno, perto de 9 GiB por hora. O TTL da tabela era de 30 dias, mas o disco enchia em dois.

Para piorar, o ZooKeeper rodava com o heap igual ao limite de memória do container, sem margem nenhuma. Sob pressão, o liveness probe falhava e o pod era morto, centenas de vezes. A cada queda, o ClickHouse refazia as operações em massa e alimentava o ciclo de novo.

Propus as correções na ordem de impacto e risco. Primeiro, aumentar a janela do flush, a alavanca mais forte e mais segura. Depois, encurtar o TTL do log interno no arquivo de configuração que já estava versionado, dar margem de memória ao ZooKeeper e afrouxar o probe. Por fim, como solução definitiva, migrar para o ClickHouse Keeper, que já rodava estável no mesmo cluster.

Observar quem observa

O ClickHouse era o maior consumidor de CPU do cluster e o único componente grande sem nenhuma métrica. Descobri que os exporters já estavam lá e ninguém coletava fazia 160 dias. Bastou criar os ServiceMonitors.

Montei o monitoramento pelo método USE (utilização, saturação e erros) para cada recurso do ClickHouse, com limiares tirados de uma baseline medida no próprio ambiente. Na primeira leitura da parte de erros apareceram 57 entradas presas na fila de replicação, algumas com mais de 100 dias, gerando cerca de 142 mil falhas de busca por dia. Eram partes perdidas nos incidentes de disco cheio que o ClickHouse tentava recuperar em loop.

Também deixei documentada uma armadilha: a métrica de atraso de replicação marcava 124 dias em todas as tabelas, mas isso era só a idade da entrada presa mais antiga. Um alerta em cima dela dispararia para sempre, sem nenhuma ação possível.

O que mudou

O shard voltou a gravar e a perda de metade da telemetria parou, depois de 50,6 dias. A cadeia completa da causa ficou documentada, com um plano de correção ordenado. O ClickHouse e o ZooKeeper passaram de nenhuma métrica para um monitoramento com limiares medidos, que na primeira leitura já revelou um problema escondido havia meses.

O que eu levo disso

Quando o disco de um banco enche, a primeira pergunta é o que está ocupando o espaço, e não o que apagar. Aqui, a "falta de retenção" era sintoma: a causa estava no ZooKeeper e no jeito de inserir os dados.

E a observabilidade também precisa ser observada. A ferramenta que devia avisar sobre problemas estava perdendo metade dos dados, e o único alerta sobre isso não chegava a ninguém.