O que é a otimização do cache DNS da Cloudflare

Cache DNS é a memória que guarda respostas de consultas de nomes, como o endereço associado a um domínio. Em vez de consultar servidores autoritativos a cada requisição, um resolvedor pode reaproveitar a resposta enquanto o TTL ainda é válido.

Em 27 de agosto de 2026, a Cloudflare publicou um artigo sobre o Big Pineapple, a plataforma por trás do 1.1.1.1, do Gateway DNS, do DNS Firewall e de outros serviços DNS da empresa. O sistema mantém mais de 250 bilhões de entradas de cache em determinado momento.

O texto não informa uma data de lançamento do Big Pineapple. O marco documentado é a otimização descrita pela equipe de engenharia: cinco mudanças na forma de armazenar os dados reduziram em mais de 50% o espaço por entrada, liberaram aproximadamente 100 terabytes de memória e ainda melhoraram o desempenho.

Como funciona

Uma entrada de cache pode ser entendida como um par de chave e valor. A chave identifica o nome consultado, o tipo do registro, o estado de autenticação e uma etiqueta. O valor contém a resposta DNS, metadados como TTL, instante de criação e contador de acessos.

Quando uma instância começa, o cache está vazio. As consultas preenchem a estrutura até o limite configurado. Quando não há mais espaço, o sistema remove entradas antigas ou menos populares para abrir lugar para novas respostas.

O cenário fica mais difícil quando o EDNS Client Subnet participa da consulta. O servidor autoritativo pode entregar respostas diferentes conforme a rede do cliente, então o resolvedor precisa manter várias versões da mesma consulta. Cada cópia extra aumenta a pressão sobre a memória.

Principais recursos da estratégia

A solução não depende de uma única compressão agressiva. Ela reduz custos pequenos e repetidos no caminho quente do sistema, sempre medindo memória, inserção e consulta para conferir se uma economia não trouxe uma regressão.

  • Estruturas imutáveis: trocar Vec e String por representações sem capacidade de crescimento elimina espaço reservado que não é usado depois da inserção.
  • Menos listas: respostas, autoridade e dados adicionais podem compartilhar uma lista, com deslocamentos compactos para indicar o início de cada seção.
  • Nome do registro opcional: quando o proprietário do registro é igual ao domínio consultado, o cache pode inferir o nome e não armazená-lo novamente.
  • Enumerações menores: variantes grandes de um enum podem ir para o heap, evitando que registros comuns ocupem o tamanho do maior caso possível.
  • Dados contíguos: uma área de bytes com o conteúdo codificado reduz alocações e melhora a localidade de memória na leitura.

O diferencial está na combinação. Cada ajuste economiza poucos bytes ou reduz uma alocação, mas o efeito acumulado aparece quando a estrutura tem centenas de bilhões de entradas.

Como começar: instalação ou acesso passo a passo

Você não instala o Big Pineapple para acompanhar o caso. A forma mais simples de estudar a ideia é ler o artigo técnico, observar o modelo de cache do seu próprio serviço e medir o custo real de cada entrada.

Comece escolhendo uma consulta segura para teste, como example.com A. Depois repita a consulta, compare o tempo informado pelo cliente DNS e observe como o TTL diminui. Em um serviço próprio, registre também o tamanho médio da chave, da resposta e das alocações.

Um roteiro curto para laboratório é: documentar o layout atual, criar uma versão compacta em uma branch, encher as duas estruturas com uma distribuição semelhante à produção e comparar memória residente, vazão de inserção e latência de consulta.

dig example.com A
dig +stats example.com A
# Repita a consulta e compare o TTL e as estatísticas
# Meça o serviço real com dados anonimizados e uma carga controlada

Exemplo prático

Imagine um resolvedor que recebe uma consulta para api.exemplo.com A. A chave guarda o nome e o tipo consultados. A resposta pode conter vários registros, além de autoridade, dados adicionais, TTL e contagem de acessos.

O modelo simplificado abaixo mostra por que um layout imutável faz sentido depois que a resposta entrou no cache. Os campos que não precisam mais crescer não devem carregar capacidade extra apenas porque foram construídos com uma coleção expansível.

pub struct CacheKey {
    qname: Name,
    qtype: Rtype,
    authenticated: bool,
    tag: Vec<u8>,
}

pub struct CacheEntry {
    timestamp: UnixTimeStamp,
    pub inception: Instant,
    pub ttl: Ttl,
    pub hits: u32,
    pub answers: Vec<Record>,
    pub authority: Vec<Record>,
    pub additional: Vec<Record>,
}

Na implementação relatada pela Cloudflare, o benchmark reduziu o footprint líquido por entrada de 953 para 420 bytes. Em produção, a memória residente no percentil 99 caiu de 9,3 GB para 5,3 GB por instância, mas o efeito varia conforme tráfego, ocupação do cache e memória usada fora dele.

Comparação com alternativas

O caminho mais óbvio para um cache pressionado é adicionar máquinas ou aumentar a memória. Isso pode resolver o sintoma, mas não elimina o custo recorrente de carregar bytes desnecessários em cada entrada.

Outra alternativa é comprimir tudo no formato de resposta DNS. A abordagem pode economizar espaço, mas complica casos como DNSSEC e pode exigir parsing completo a cada consulta. A estratégia da Cloudflare fica no meio: mantém metadados estruturados e armazena os dados de registros em um buffer compacto.

  • Mais memória: indicada quando a demanda cresceu rapidamente e o prazo é curto, mas aumenta o custo operacional.
  • Cache externo: útil quando a equipe quer delegar operação, porém adiciona rede, serialização e dependência de outro componente.
  • Compressão total: interessante para armazenamento, mas pode ampliar o trabalho no caminho de leitura.
  • Layout orientado ao acesso: indicado quando a escala torna alocações e ponteiros um custo mensurável, como no caso do Big Pineapple.

Para sistemas menores, uma estrutura simples pode ser a melhor escolha. A técnica avançada só vale a complexidade quando a medição mostra que memória, alocações ou localidade estão limitando o serviço.

Pontos positivos e limitações

O principal ponto positivo é obter economia de memória sem trocar espaço por lentidão. A Cloudflare relatou aumento de 43% na vazão de inserção e redução de 19% na latência de consulta após as mudanças.

Também há um ganho de capacidade operacional. A memória liberada pode ser reinvestida em mais entradas de cache, o que tende a ampliar a taxa de acertos e reduzir consultas aos servidores de origem, desde que o padrão de tráfego justifique essa capacidade.

A limitação é a complexidade. Buffers contíguos podem exigir iteração sequencial, variantes empacotadas podem dificultar a indexação e qualquer mudança no layout precisa preservar TTL, DNSSEC, compressão de nomes e formatos de registro.

⚠️
Atenção

Os números do artigo vêm de benchmarks e medições do ambiente da Cloudflare. Eles são uma referência técnica, não uma promessa de ganho igual em qualquer servidor.

Casos de uso reais

Para uma equipe de SRE, o caso ajuda a investigar instâncias cujo consumo de memória cresce junto com a ocupação do cache. Em vez de aumentar a máquina imediatamente, a equipe pode identificar campos repetidos e alocações que sobrevivem sem necessidade.

Para quem mantém um backend com cache de respostas, a lição é observar o caminho de leitura e escrita em conjunto. Reduzir bytes por entrada é útil, mas somente se o custo de reconstruir a resposta e a latência continuarem dentro do objetivo do serviço.

Para uma equipe que usa Rust, o artigo oferece um estudo prático sobre Box, enumerações, padding, alocadores e localidade de memória. Para estudantes, ele mostra como uma otimização de baixo nível pode ter impacto operacional quando multiplicada pela escala.

Dicas e boas práticas

O primeiro passo é medir o que realmente está ocupando espaço. Antes de trocar tipos, capture uma linha de base com a mesma distribuição de registros e a mesma quantidade aproximada de dados que o serviço recebe.

💡
Dica

Separe o footprint da entrada das demais áreas do processo. Memória residente inclui cache, alocador, pilhas e outros componentes, então não atribua toda redução ao layout sem isolar as variáveis.

⚠️
Atenção

Não remova um campo apenas porque ele parece repetido. Em DNS, um nome diferente por causa de CNAME, NS, MX ou SOA precisa continuar disponível para a resposta correta.

🚀
Pro tip

Compare memória, vazão de inserção e latência de consulta em cada mudança. Uma representação compacta que espalha dados pelo heap pode perder para uma estrutura um pouco maior, porém contígua.

Por fim, faça rollout gradual e observe produção. O artigo relata que a implantação aconteceu em etapas, porque instâncias reiniciadas começam com cache vazio e só revelam o consumo estável depois que voltam a aquecer.

Vale a pena?

Vale a pena estudar essa abordagem quando o cache é grande, o custo de alocação aparece nos perfis e a equipe consegue reproduzir uma carga próxima da produção. O ganho não está em copiar cada struct, mas em tratar a representação dos dados como parte do desempenho.

Para um projeto pequeno, começar com uma estrutura clara e medir depois costuma ser suficiente. Para uma plataforma distribuída com bilhões de entradas, pequenas escolhas como capacidade de um vetor, ponteiros extras e padding podem virar terabytes.

O próximo passo é ler o estudo da Cloudflare, desenhar o layout do seu cache e testar uma mudança por vez. Se os números confirmarem o gargalo, a otimização deixa de ser opinião e passa a ser uma decisão técnica sustentada por dados.