2 pontos por GN⁺ 2025-08-23 | Ainda não há comentários. | Compartilhar no WhatsApp
  • Para criar um servidor web de alto desempenho, tradicionalmente eram usados vários modelos baseados em eventos, como select(), poll() e epoll
  • Porém, devido aos limites de desempenho dessas chamadas de sistema, surgiu o io_uring, que introduz uma abordagem em que as requisições são colocadas em uma fila para o kernel processá-las de forma assíncrona
  • O kTLS coloca o kernel como responsável pelo processamento da criptografia TLS, permitindo otimizações adicionais como uso de sendfile() e offloading por hardware
  • A introdução de Descriptorless files oferece uma forma de acesso otimizada para o io_uring sem repassar diretamente descritores de arquivo
  • Por meio do projeto open source tarweb, que combina Rust, io_uring e kTLS, é possível oferecer HTTPS sem chamadas de sistema adicionais por requisição, além de discutir questões de segurança e gerenciamento de memória

A evolução da arquitetura de servidores web de alto desempenho

  • Desde o início dos anos 2000, cresceu a demanda por servidores web de alta capacidade
  • No começo, era comum criar um novo processo para cada requisição, mas, devido ao alto custo, surgiu a técnica de preforking
  • Depois vieram as threads e o uso de select() e poll(), evoluindo para uma forma de reduzir o custo de troca de contexto
  • Ainda assim, select() e poll() têm limites de escalabilidade, porque, à medida que o número de conexões cresce, é necessário passar com frequência grandes arrays ao kernel

O surgimento do epoll

  • No ambiente Linux, o epoll foi introduzido para permitir um tratamento de múltiplas conexões mais eficiente do que os métodos anteriores
  • O epoll processa apenas as mudanças (delta), reduzindo o consumo desnecessário de recursos
  • Nem todas as chamadas de sistema desaparecem completamente, mas o custo cai de forma significativa

Visão geral do io_uring

  • O io_uring adiciona requisições a filas em memória para que o kernel possa processá-las de forma assíncrona, em vez de fazer uma chamada de sistema a cada solicitação
  • Por exemplo, se accept() for colocado na fila, o kernel processa a operação e devolve o resultado na fila de conclusão
  • O servidor web funciona adicionando solicitações à fila e verificando os resultados em uma região de memória separada
  • Para evitar um busy loop, quando não há mudanças na fila, tanto o servidor web quanto o kernel chamam chamadas de sistema apenas quando necessário, economizando energia
  • Com bibliotecas adequadas, um servidor ativo pode operar sem chamadas de sistema adicionais durante o processamento das requisições

Ambiente multicore e NUMA

  • Considerando o ambiente multicore dos CPUs modernos, uma estratégia eficaz é executar uma única thread por núcleo e minimizar o compartilhamento de estruturas de dados
  • Em ambientes NUMA, cada thread pode ser otimizada para acessar apenas a memória do seu nó local
  • O balanceamento perfeito da distribuição de requisições ainda exige mais pesquisa

Alocação de memória

  • A alocação de memória continua existindo tanto no kernel quanto no servidor web, e as alocações no espaço do usuário acabam se conectando a chamadas de sistema
  • Do lado do servidor web, blocos de memória de tamanho fixo podem ser pré-alocados por conexão para evitar fragmentação e falta de memória
  • Do lado do kernel, também são necessários buffers de entrada e saída por conexão, com algum ajuste possível por meio de opções de socket
  • Quando ocorre falta de memória, isso pode levar a falhas graves

Introdução ao kTLS (TLS no kernel)

  • O kTLS é um recurso em que o kernel Linux assume as operações de criptografia e descriptografia
  • O handshake é tratado pela aplicação, mas, depois disso, o kernel passa a tratar a transmissão dos dados como se fossem texto puro
  • Isso permite usar sendfile(), reduzindo cópias de memória entre o espaço do usuário e o do kernel
  • Se a placa de rede der suporte, há ainda a vantagem de fazer offloading das operações de criptografia para o hardware

Descriptorless Files

  • Essa abordagem surgiu para reduzir o overhead gerado ao repassar diretamente descritores de arquivo do espaço do usuário para o espaço do kernel
  • Com register_files, usa-se um número de arquivo separado, válido apenas para o io_uring, que não aparece em /proc/pid/fd
  • O limite de ulimit do sistema ainda se aplica

Introdução ao projeto tarweb

  • O tarweb é um projeto open source de servidor web que aplica todas as tecnologias acima como exemplo
  • Ele serve o conteúdo de um único arquivo tar, combinando tecnologias modernas de alto desempenho como Rust, io_uring e kTLS
  • No uso prático, houve problemas de compatibilidade entre io_uring e kTLS (como falta de suporte a setsockopt), e algumas dessas questões foram resolvidas por meio de Pull Requests
  • O projeto ainda está incompleto, e a biblioteca rustls do Rust pode fazer alocação de memória durante o processo de handshake
  • O ponto principal é que é possível oferecer serviço HTTPS sem chamadas de sistema adicionais por requisição

Benchmark e medição de desempenho

  • O autor ainda não realizou benchmarks suficientes e pretende testar o desempenho depois de organizar melhor o código

Problemas de segurança em io_uring e Rust

  • Diferentemente das chamadas de sistema síncronas, no io_uring os buffers de memória não podem ser liberados antes do evento de conclusão
  • O crate io-uring não garante a segurança em tempo de compilação do Rust, e as verificações em tempo de execução também são insuficientes
  • Se usado incorretamente, isso pode causar problemas graves semelhantes aos de C++, enfraquecendo a segurança inerente do Rust
  • É necessário um crate separado, como o safer-ring, que aproveite ativamente pinning e o borrow checker
  • Esse tema já está sendo discutido na comunidade

Referências e links adicionais

  • Este conteúdo é um post discutido no HackerNews em 2025-08-22

Ainda não há comentários.

Ainda não há comentários.