Arquitetura real · Sênior
Cloudflare Pingora: substituindo o NGINX por Rust
Arquitetura real em produção. Pontos centrais: Balanceamento de Carga e Antipadrões de Desempenho.
Resposta curta
Arquitetura real em produção. Pontos centrais: Balanceamento de Carga e Antipadrões de Desempenho. O Pingora é um proxy HTTP que a Cloudflare construiu internamente em Rust. Ele atende mais de um trilhão de requisições por dia e, segundo a empresa, precisa de apenas um terço da CPU e da memória da infraestrutura de proxy anterior.
01 · CONTEXTO
O proxy entre a rede da Cloudflare e a Internet
O Pingora é um proxy HTTP que a Cloudflare construiu internamente em Rust. Ele atende mais de um trilhão de requisições por dia e, segundo a empresa, precisa de apenas um terço da CPU e da memória da infraestrutura de proxy anterior.
O serviço faz proxy do tráfego entre a rede da Cloudflare e os servidores na Internet, e alimenta o CDN, o fetch dos Workers, o Tunnel, o Stream, o R2 e outros produtos. O Pingora atende quase toda requisição HTTP que precisa falar com um servidor de origem, como numa falha de cache.
02 · LIMITES DO NGINX
Por que o NGINX deixou de servir
A Cloudflare afirma que, na escala dela, não conseguia mais o desempenho de que precisava, e que o NGINX também não tinha os recursos exigidos pelo ambiente complexo da empresa.
O primeiro limite é arquitetural. No NGINX cada requisição só pode ser atendida por um único worker, o que gera carga desbalanceada entre os núcleos de CPU e leva a lentidão. Além disso, requisições que fazem trabalho pesado de CPU ou IO bloqueante podem atrasar outras.
O problema mais crítico para a Cloudflare é o reúso ruim de conexões. Reusar conexões de um pool acelera o TTFB porque pula os handshakes de TCP e TLS de uma conexão nova. Só que o pool do NGINX é por worker: ao somar workers para escalar, as conexões se espalham por mais pools isolados e a taxa de reúso piora, o que resulta em TTFB mais lento e mais conexões para manter.
Uma requisição que chega é atendida por um único worker do NGINX.
Cada worker mantém o próprio pool de conexões com a origem.
Ao adicionar workers para escalar, as conexões ficam espalhadas por mais pools isolados e a taxa de reúso piora.
Há também o limite de funcionalidade. Ao refazer ou redirecionar uma requisição (retry ou failover), a empresa às vezes queria enviá-la a outra origem com outros cabeçalhos, algo que o NGINX não permite. A base do NGINX é só em C, que não é segura quanto à memória por projeto, e o Lua que a complementa é menos arriscado, porém menos performático.
03 · A DECISÃO
Três caminhos e uma reescrita
A empresa avaliou três opções a cada trimestre, por alguns anos. Durante esse período seguiu o caminho de menor resistência, aumentando o NGINX, e em algum momento o retorno de construir o próprio proxy pareceu valer a pena.
| Opção | O que a Cloudflare diz |
|---|---|
| Investir no NGINX e talvez fazer um fork | Seria preciso esforço significativo para reconstruí-lo e atender às necessidades da empresa |
| Migrar para outro proxy de terceiros | O mesmo ciclo poderia se repetir em alguns anos |
| Começar do zero | Exige o maior investimento inicial de engenharia |
04 · DECISÕES DE DESIGN
Rust, HTTP próprio, threads e fases programáveis
A linguagem escolhida foi Rust, por fazer o que C faz de forma segura quanto à memória, sem perder desempenho. A Cloudflare também construiu a própria biblioteca HTTP, para maximizar a flexibilidade no tratamento do tráfego, já que precisa suportar muito tráfego bizarro e fora do RFC.
No agendamento de trabalho, a empresa optou por multithreading em vez de multiprocessamento, para compartilhar recursos, em especial os pools de conexões. Também decidiu que work stealing era necessário para evitar algumas classes de problemas de desempenho, e o runtime assíncrono Tokio se encaixou nas necessidades.
Por fim, adotou uma interface programável baseada em eventos, similar à do NGINX/OpenResty. A fase de request filter, por exemplo, permite rodar código para modificar ou rejeitar a requisição quando um cabeçalho chega.
| Critério | NGINX | Pingora |
|---|---|---|
| Atendimento da requisição | Um único worker por requisição | Multithreading, com recursos compartilhados |
| Memória compartilhada | Todo acesso usa mutex, e só cabem strings e números | Maioria dos itens acessada por referências compartilhadas atrás de contadores atômicos |
| Linguagem | C, complementado por Lua | Rust |
05 · NO CAMINHO DA REQUISIÇÃO
Onde o Pingora entra
O Pingora cuida do trecho entre a rede da Cloudflare e os servidores na Internet.
Quando a requisição precisa falar com um servidor de origem, como numa falha de cache, é o Pingora quem a atende.
No Cache Reserve, o Pingora usa o armazenamento R2 como camada de cache.
Dentro do Pingora, as threads compartilham os pools de conexões com as origens.
A base nova também acelerou funcionalidades. A Cloudflare conseguiu adicionar suporte a HTTP/2 upstream sem grandes obstáculos, e isso permitiu oferecer gRPC. O Cache Reserve é outro exemplo, em que o Pingora usa o R2 como camada de cache.
06 · RESULTADOS
O que mudou em produção
| Medida | Resultado informado |
|---|---|
| TTFB | Redução de 5 ms na mediana e de 80 ms no percentil 95 |
| Novas conexões por segundo | Só um terço das do serviço antigo |
| Reúso de conexão de um grande cliente | De 87,1% para 99,92%, com 160 vezes menos novas conexões para as origens |
| CPU e memória | Cerca de 70% menos CPU e 67% menos memória com a mesma carga |
Segundo a Cloudflare, a economia de TTFB não vem de rodar código mais rápido, e sim da arquitetura nova, que compartilha conexões entre todas as threads, melhora a taxa de reúso e gasta menos tempo em handshakes de TCP e TLS.
Parte da economia de CPU vem de o código Rust rodar de forma mais eficiente que o antigo código Lua: em Lua, ler um cabeçalho exige ler da struct em C, alocar uma string Lua e copiá-la. Outra parte vem de abrir menos conexões novas, porque handshakes de TLS são caros frente a usar conexões já estabelecidas.
Em segurança, a empresa diz ter servido algumas centenas de trilhões de requisições sem nenhum crash causado pelo código do próprio serviço, e que a semântica segura de memória do Rust protege contra comportamento indefinido.
Perguntas frequentes
O que é Cloudflare Pingora: substituindo o NGINX por Rust?
Arquitetura real em produção. Pontos centrais: Balanceamento de Carga e Antipadrões de Desempenho.
O que o design de Cloudflare Pingora: substituindo o NGINX por Rust cobre?
Ele está organizado nestas seções: O proxy entre a rede da Cloudflare e a Internet, Por que o NGINX deixou de servir, Três caminhos e uma reescrita, Rust, HTTP próprio, threads e fases programáveis, Onde o Pingora entra e O que mudou em produção.
Quanto tempo leva Cloudflare Pingora: substituindo o NGINX por Rust e qual é o nível?
Leva cerca de 17 minutos para ler e tem nível Sênior.
Agora projete você mesmo
Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.