HeadlinesBriefing favicon HeadlinesBriefing.com

Cloudflare economiza 100TB de RAM com Rust

Hacker News •
×

A Cloudflare opera em uma escala tão grande que, mesmo depois de trabalhar aqui por anos, não parece real. Temos milhares de servidores em todo o mundo com petabytes de RAM e milhões de núcleos de CPU, e tudo isso é levado ao máximo. Por mais vastos que esses recursos pareçam, eles ainda são finitos, e quando você precisa que cada serviço seja executado em cada nó, isso não deixa espaço para desperdício. Nessa escala, pequenas melhorias são muito amplificadas, então até melhorias de 1% por vez valem a pena ser celebradas. E alguns ajustes somam muito mais: neste post, veremos como pequenas mudanças em um único algoritmo reduziram significativamente o consumo de memória de um dos nossos serviços baseados em Pingora. Isso nos permitiu recuperar mais de 100TB de RAM globalmente, além dos 100TB de memória que a equipe de DNS conseguiu liberar no mês passado.

Não desperdice Manter uma distribuição equitativa de recursos entre as equipes não é fácil, especialmente em grandes organizações. Uma das formas pelas quais a Cloudflare garante que o equilíbrio seja mantido é através dos esforços incansáveis da maravilhosa equipe de Performance. Esta história começa com um ticket aberto por Ivan, que descobriu: Uso excessivo de memória do pingora-ketama no Pingora Backend Router. A descoberta foi que nosso serviço interno de balanceamento de carga, o Pingora Backend Router (sim, PBR), estava usando muito mais memória do que o esperado — especificamente em estruturas associadas ao pingora-ketama, que é nossa biblioteca de código aberto para lidar com hashing consistente. Para falar sobre como lidamos com esse aparente uso excessivo de memória, precisamos falar sobre o que é hashing consistente, por que o usamos no PBR e como ele se tornou tão faminto por memória. Ao longo do caminho, aprenderemos um pouco de Rust e até um pouco de matemática.

Hashing consistente O hashing consistente é um método amplamente utilizado para distribuir tarefas entre vários servidores de uma forma que não exige grandes mudanças quando servidores são adicionados ou removidos. Internamente, usamos isso para rotear solicitações cacheáveis para servidores por URL. Isso nos permite manter apenas uma cópia de um arquivo armazenado por data center e oferece uma maneira estável de encontrar a localização de cada arquivo. Já mencionamos esse sistema antes, mas vamos dedicar um tempo para explicar como e por que esse algoritmo é usado e como ele funciona. O conceito-chave do hashing consistente é que, embora as funções de hash possam aceitar qualquer tipo de entrada, sua saída é limitada a um único inteiro sem sinal (inteiros de 32, 64 ou 128 bits, dependendo da função de hash). Isso nos permite relacionar tarefas e servidores entre si de maneira consistente. A maioria das discussões sobre hashing consistente faz você pensar nesse espaço de saída como um anel contínuo e circular que dá a volta do seu valor máximo até zero. Essa representação produz algumas visualizações bonitas, mas também pode fazer o conceito simples de intervalos de inteiros parecer mais complicado do que precisa ser. Para nossa discussão, representaremos a saída de 32 bits da nossa função de hash como uma reta numérica. Agora, digamos que temos um conjunto de servidores, A, B e C, e um conjunto de tarefas t-z. Podemos mapear cada um na reta numérica com base no hash de seus valores representativos, como endereços IP para servidores e chaves de cache para tarefas. Atribuir tarefas a servidores agora é apenas uma questão de encontrar o primeiro servidor à esquerda de cada tarefa. Podemos representar isso visualmente colorindo a região de hashes que será associada a cada servidor. Observe que o intervalo coberto pelo servidor C dá a volta até o início, daí a ideia de que os hashes existem em um anel. E é isso. Em um nível básico, o hashing consistente é assim tão simples — mas não demora muito para ver que há espaço para melhorias. Observe que o intervalo coberto pelo servidor A em nosso exemplo é significativamente maior do que o de B ou C. Isso é um problema porque a fração de solicitações que um servidor atende será proporcional ao tamanho do seu intervalo na reta numérica. Idealmente, gostaríamos de garantir que cada servidor tenha um tamanho igual, mas como os hashes são essencialmente números aleatórios, temos que...