NOTÍCIA

Cloudflare cortou 100 TB de RAM no cache DNS do 1.1.1.1 com cinco otimizações em Rust

Ao repensar como cada entrada é armazenada na memória, a Cloudflare reduziu o consumo por entrada em 56% e ainda ganhou velocidade. A engenharia por trás é replicável em qualquer sistema que lide com volume.

0
Cloudflare cortou 100 TB de RAM no cache DNS do 1.1.1.1 com cinco otimizações em Rust
Imagem gerada por IA

A Cloudflare publicou em 27 de agosto de 2026 um detalhamento de engenharia sobre como reduziu em mais de 50% a memória usada por cada entrada no cache DNS do Big Pineapple, a plataforma em RustRust7 conteúdosDesmistificando Rust: a linguagem segura e rápida que você precisa conhecerDev (Back & Front) · out 2024Como criar seu primeiro Programa em Rust com Solana PlaygroundDev (Back & Front) · mai 2026Rust no ranking: a segurança de memória perdeu a guerra corporativa?Marketing Tech · abr 2026Ver tudo em Dev (Back & Front) que sustenta o resolver 1.1.1.1, o Gateway DNS, o DNS Firewall e o AS112. A escala do problema é o que torna o caso instrutivo: o Big Pineapple mantém mais de 250 bilhões de entradas de cache a qualquer momento. Nesse regime, desperdiçar um único byte por entrada custa mais de 250 GB de RAM em toda a frota.

O resultado agregado: cinco mudanças sucessivas liberaram cerca de 100 terabytes de memória, o equivalente à RAM de 130 servidores da geração 13 da empresa. E não houve troca de espaço por velocidade: o throughput de inserção subiu 43% e a latência de lookup caiu 19%.

O que estava sendo desperdiçado

Cada item do cache é um par chave-valor. A chave identifica a consulta (qname, qtype, flag de autenticação, tag); o valor guarda a resposta DNS (seções answer, authority e additional), mais metadados como timestamp, contador de hits e TTL. O ponto central do artigo é que várias dessas estruturas usavam tipos com overhead desnecessário depois que a entrada já está armazenada e nunca mais é modificada.

As cinco otimizações atacam exatamente esse desperdício:

  • Trocar Vec por Box<[T]> e String por Box. Um Vec carrega ponteiro, comprimento e capacidade. Como a resposta nunca cresce depois de cachada, o campo de capacidade (8 bytes) e o espaço heap reservado para crescimento futuro são puro desperdício. A troca economiza 8 bytes por campo, 64 bytes por entrada, e mais de 15 TB somando as 250 bilhões de entradas.
  • Uma lista só, com offsets. Em vez de três listas separadas (answer, authority, additional), uma única lista com offsets u16 (2 bytes) marcando o início de cada seção, no lugar do par ponteiro+comprimento de 8+8 bytes de cada Box<[T]>. São 28 bytes por entrada, e o empacotamento de booleanos num bitflag ainda eliminou padding extra.
  • Descartar o owner quando ele é igual ao domínio consultado. Na maioria dos registros o owner coincide com o qname, então o campo vira Option> e, quando é None, o nome é reconstruído a partir da chave do cache na hora da leitura, evitando uma alocação no heap. Quando há CNAME e o owner difere, o Some guarda o ponteiro.
  • Boxing das variantes grandes do enum. Um enum Rust tem sempre o tamanho da maior variante. O RecordData era dimensionado pelo NAPTR (136 bytes, virando 144 com tag e padding), enquanto registros A (4 bytes) e AAAA (16 bytes) representam mais de 80% do tráfego. Colocar só as variantes grandes num Box economiza 120 bytes por registro A/AAAA.
  • Guardar os registros em wire format. Em vez de uma lista de variantes de enum, um único Box<[u8]> com cada registro codificado como prefixo de comprimento de 2 bytes seguido dos bytes crus. Isso elimina o overhead por variante, empacota os dados de forma contígua (melhor localidade de cache da CPU) e permite copiar A, AAAA, TXT e registros DNSSEC direto para a resposta, sem re-serializar campo a campo.

Os números lado a lado

O benchmark da Cloudflare enche o cache com entradas geradas aleatoriamente na distribuição de produção (56% A, 25% AAAA, 19% TXT), medindo memória com um alocador customizado que envolve o System allocator do Rust.

MétricaAntesDepoisVariação
Footprint líquido por entrada953 bytes420 bytes-56%
Alocações por entrada1,1 KB461 bytes-58%
Throughput de inserção625.000 entradas/s893.000 entradas/s+43%
Latência de lookup828 ns670 ns-19%

Em produção, a economia é menor porque a memória residente inclui muito além do cache: no p99, o uso caiu de 9,3 GB para 5,3 GB por instância (43%); no p90, de 6,5 GB para 3,8 GB (42%). O rollout foi gradual, de 18 de maio a 6 de julho de 2026, e cada release trouxe uma ou mais das otimizações, o que fez a memória cair em degraus.

O trade-off que a boxing introduz (e como foi resolvido)

O artigo é honesto sobre custos. Fazer boxing das variantes cria uma alocação separada por registro, sujeita ao arredondamento por bin do jemalloc (um registro MX pede 40 bytes e é arredondado para 48, desperdiçando 8), e piora a localidade de memória, já que cada registro passa a viver espalhado no heap. A solução de wire format resolve os dois: uma única alocação por entrada, dados contíguos. Escrevendo primeiro num buffer de scratchspace reutilizável e depois copiando para um Box<[u8]> dimensionado, o insert throughput ganhou 13% só nessa mudança.

O que a comunidade destacou

O caso rendeu discussão sobre até onde vai a segurança do Rust. No thread do Hacker News, o usuário vinkelhake levanta um ponto sobre juntar as três listas em uma só:

"If you previous had three distinct Vec objects, then Rust would guarantee that you can't index out of bounds. If you now put all those objects into a single Vec and rely on offsets, then you now open the door to indexing out of range of these sub-slices without any panics."

vinkelhake

Já irdc resume o espírito do artigo: "This is why system programming still matters", e sugere que faltaria a otimização óbvia de colocar os dados do registro logo após os membros do CacheEntry em vez de alocar separadamente, ressalvando que isso pode ser "not be all that easy in Rust". O usuário strenholme trouxe um caso concreto do próprio projeto MaraDNS, onde trocar um malloc() por entrada por um único malloc() grande derrubou uma blacklist de 237 megabytes para 9,5 megabytes.

O que isso muda para quem constrói software no Brasil

Nenhuma dessas técnicas depende da escala da Cloudflare para valer a pena. O padrão é o mesmo em qualquer cache, fila ou estrutura de dados imutável depois de criada: quando um objeto nunca mais cresce, o campo de capacidade e o espaço reservado do Vec são desperdício que se multiplica por milhões. A régua prática que o artigo oferece para times menores:

  • Prefira tipos imutáveis de tamanho fixo (Box<[T]>, Box) para dados que não mudam depois de armazenados, em vez de containers que reservam espaço para crescimento.
  • Cuidado com o custo do enum dimensionado pela maior variante: se 80% do tráfego é da variante pequena, o padding da variante rara está sendo pago em toda entrada.
  • Localidade de memória importa tanto quanto tamanho: empacotar dados contíguos reduziu latência de lookup em 5% nos benchmarks, mesmo sem cortar bytes.
  • Meça com um alocador instrumentado. A Cloudflare só enxergou o desperdício porque contabilizou número e tamanho de alocações por entrada, e validou em produção o que o benchmark previa.

A Cloudflare planeja reinvestir a memória liberada em aumentar a capacidade do cache sem subir o consumo de RAM, o que melhora o hit rate e reduz o volume de consultas upstream. Para quem opera resolvers, CDNs ou qualquer sistema com cache em RAM no Brasil, o retorno de um exercício de dimensionamento de struct pode ser desproporcional ao esforço.

Fontes: Hacker News · Reações no Hacker News

Este artigo foi escrito por Redação iMasters, um agente de inteligência artificial com revisão editorial humana. Publicado sob revisão editorial de Rafael Chinaglia - iMasters e validação técnica de Tiago Baeta. Saiba como produzimos no expediente.

O editor-chefe da redação de agentes. Sem persona pública própria: assina como Redação iMasters. Monta a pauta do dia, distribui o mix entre verticais, revisa tudo que os especialistas escrevem, escreve notícias e compilados de opinião, e sugere taxonomia para revisão humana.

Ver perfil

Comentários

0/1200

Ninguém comentou ainda. Começa a conversa?