Rustls: Estudo de Caso de Benchmarking Contínuo

Everett Pompeii

Everett Pompeii


O que é Rustls?

Rustls é uma biblioteca moderna de Transport Layer Security (TLS) escrita em Rust, com o objetivo de substituir alternativas não seguras para a memória, como o OpenSSL. O protocolo TLS é usado para fornecer comunicações seguras, tipicamente entre um servidor web e um cliente. TLS era anteriormente chamado de Secure Socket Layer (SSL). Ele garante que os dados transmitidos entre as duas partes são criptografados e protegidos contra interceptações ou adulterações. Portanto, é vital que uma biblioteca de TLS como Rustls seja rápida e segura.

🐰 O s em https significa que você está usando TLS para visualizar esta página!

Benchmarking do Rustls

O primeiro commit do Rustls foi feito pelo criador do projeto Joseph Birr-Pixton em 02 de maio de 2016 com a primeira conexão TLS bem-sucedida acontecendo apenas no dia 27 do mesmo mês. Em setembro daquele ano, ele já estava fazendo benchmarking do Rustls. Com melhorias substanciais de desempenho, ele fez uma comparação de benchmarking entre Rustls e OpenSSL em julho de 2019.

Os resultados dessa comparação de benchmark foram:

  • Rustls foi 15% mais rápido para enviar dados.
  • Rustls foi 5% mais rápido para receber dados.
  • Rustls foi 20-40% mais rápido para estabelecer uma conexão do cliente.
  • Rustls foi 10% mais rápido para estabelecer uma conexão do servidor.
  • Rustls foi 30-70% mais rápido para reativar uma conexão do cliente.
  • Rustls foi 10-20% mais rápido para reativar uma conexão do servidor.
  • Rustls usou menos da metade da memória do OpenSSL.

Em 2023, o Internet Security Research Group financiou os benchmarks de performance do projeto Rustls, e isso gerou uma nova comparação de benchmarking entre Rustls e OpenSSL. Embora esses resultados atualizados tenham sido informativos para o projeto Rustls em ambas as áreas - pontos fortes e áreas para melhoria - a maior preocupação quanto ao desempenho é garantir que o novo código não introduza uma regressão de desempenho.

Benchmarking Contínuo para Rustls

Para identificar regressões de desempenho antes de serem lançadas, o projeto Rustls decidiu investir em Benchmarking Contínuo.

O Benchmarking Contínuo é uma prática de desenvolvimento de software onde os membros de uma equipe avaliam seu trabalho com frequência, geralmente cada pessoa avalia pelo menos diariamente - resultando em várias avaliações por dia. Cada avaliação é verificada por uma build automatizada para detectar regressões de desempenho o mais rápido possível. Muitas equipes descobrem que esta abordagem resulta em uma redução significativa das regressões de desempenho e permite que a equipe desenvolva software performático de forma mais rápida.

A solução de benchmarking contínuo do projeto Rustls consiste em dois componentes principais:

  • CI Bench: Uma estrutura de avaliação personalizada projetada especificamente para a execução de avaliações em CI
  • Bench Runner: Um servidor de benchmarking contínuo personalizado, feito do zero e um aplicativo GitHub associado

Rustls CI Bench

CI Bench é um equipamento de referência de última geração para benchmarks contínuos. Ele executa o mesmo benchmark exato em dois modos diferentes: modo de contagem de instruções e modo de tempo de parede. Isso é realizado usando um runtime async personalizado e engenhoso. Para o modo de contagem de instruções, a I/O ainda é realmente bloqueante. Por debaixo dos panos, as tarefas simplesmente são concluídas em uma única pesquisa. Depois, para o modo de tempo de parede, a I/O é realmente não bloqueante. Isso permite a simulação de buffers compartilhados e em memória. O servidor e o cliente são pesquisados alternadamente. Isso permite que CI Bench elimine o ruído e o indeterminismo de um runtime async em seus benchmarks.

Rustls escolheu rastrear as instruções da CPU usando cachegrind. Essa decisão foi baseada na solução de benchmark contínuo do compilador Rust. As contagens de instruções fornecem uma forma muito consistente de comparar duas versões do mesmo software. Isso o torna ideal para benchmarking contínuo. No entanto, não é possível inferir o custo de tempo de execução real de um aumento na contagem de instruções. Um aumento de 10% nas instruções não resulta necessariamente em um aumento de 10% no desempenho do tempo de execução. Mas um aumento significativo nas instruções provavelmente significa que há algum aumento no desempenho do tempo de execução. Por esta razão, CI Bench também mede o tempo de parede.

O tempo de parede é o que o projeto Rustls realmente se preocupa. Medir as contagens de instruções é apenas um proxy útil. Benchmarks baseados na contagem de instruções não podem desambiguar mudanças que usam o mesmo número de instruções mas levam a um desempenho de tempo de parede muito diferente. Por exemplo, um novo algoritmo pode acontecer de ter o mesmo número exato de instruções, mas funciona duas vezes mais devagar.

Executador de Benchmarks Rustls

O Executador de Benchmarks Rustls é um servidor personalizado de benchmarking contínuo. Ele foi projetado para ser executado em um host de metal nú. E recebe eventos de um aplicativo complementar do GitHub via webhooks. A cada push para o branch main, o Executador de Benchmarks executa tanto os benchmarks de contagem de instrução quanto os de tempo real. Os resultados são armazenados localmente e enviados para o projeto Rustls no Bencher usando a API do Bencher.

Sempre que um pull request é aprovado ou um comentário contendo @rustls-benchmarking bench é deixado por um mantenedor do Rustls, o conjunto de benchmarks é executado. O Executador de Benchmarks recebe um webhook do GitHub, puxa o código do pull request, executa os benchmarks de contagem de instrução, executa os benchmarks de tempo real, compara os resultados do pull request com os resultados do branch mainalvo, e então posta os resultados como um comentário no pull request. O Executador de Benchmarks usa um modelo de Intervalo Interquartil Delta para seu limite estatístico para determinar se uma regressão de desempenho ocorreu. Resultados que excedem esse limite são destacados no comentário do pull request.

Servidor Bare Metal

Para obter uma resolução de 1% em seus benchmarks de tempo de parede, o projeto Rustls investiu em um servidor de benchmarking contínuo especialmente configurado, bare metal. Diferentemente da maioria dos runners de CI modernos, este servidor não é efêmero. Ou seja, o mesmo hardware de servidor subjacente e o sistema operacional são usados para cada execução. Não há virtualização.

O servidor bare metal foi especificamente configurado para criar os resultados mais consistentes possíveis. O escalonamento de frequência (TurboBoost da Intel) e a multithreading simultânea (Hyper-Threading da Intel) foram ambos desativados no BIOS. O escalonamento da CPU está definido para performance. Randomização do Layout do Espaço de Endereço (ASLR) e o watchdog do Interrupt Não-Mascarável (NMI) ambos são desabilitados ao definir kernel.randomize_va_space=0 e kernel.nmi_watchdog=0 no sysctl.conf, respectivamente. O servidor bare metal é hospedado pela OVHcloud.

Estante de Troféus

  • PR #1640: Uma das primeiras utilizações da integração contínua de benchmarking do Rustls para avaliar a transição de write_vectored para write. Esta mudança melhorou a transferência do Rustls nas direções de envio em quase 20% em alguns casos.
  • PR #1730: Encontrou regressões de desempenho ao randomizar a ordem das extensões do TLS ClientHello. Isso resultou em outra iteração de desenvolvimento e no uso de uma abordagem mais eficiente.
  • PR #1834: Ajudou a validar rapidamente que uma correção crítica de segurança não introduziu uma regressão de desempenho. Isso permitiu que a equipe se concentrasse em liberar rapidamente várias versões com correções de segurança.

Conclusão

Aproveitando a base estabelecida pelo criador do projeto, Adolfo Ochagavía construiu uma impressionante solução de benchmarking contínuo para o projeto Rustls. Isso inclui um arnês de benchmarking personalizado que executa tanto benchmarks de contagem de instrução quanto de tempo de parede para o mesmo teste, um runner de benchmark personalizado, um App do GitHub personalizado e um servidor dedicado e personalizado. É uma das mais impressionantes soluções de benchmarking contínuo específicas do projeto existentes. Se o seu projeto tem tempo e recursos para construir e manter uma solução de benchmarking contínuo feita sob medida, o projeto Rustls estabelece uma alta meta a ser atingida.

Um agradecimento muito especial a Adolfo Ochagavía por revisar este estudo de caso. Seus posts no blog sobre Benchmarking Contínuo para Rustls e Desempenho do Rustls foram a base para o seu conteúdo.

Bencher: Benchmarking Contínuo

🐰 Bencher

Bencher é um conjunto de ferramentas de benchmarking contínuas. Já teve algum impacto de regressão de desempenho nos seus usuários? Bencher poderia ter prevenido isso. Bencher permite que você detecte e previna regressões de desempenho antes que cheguem à produção.

  • Execute: Execute seus benchmarks localmente ou no CI usando suas ferramentas de benchmarking favoritas. O CLI bencher simplesmente envolve seu harness de benchmark existente e armazena seus resultados.
  • Rastreie: Acompanhe os resultados de seus benchmarks ao longo do tempo. Monitore, consulte e faça gráficos dos resultados usando o console web do Bencher baseado na branch de origem, testbed e medida.
  • Capture: Capture regressões de desempenho no CI. Bencher usa análises personalizáveis e de última geração para detectar regressões de desempenho antes que elas cheguem à produção.

Pelos mesmos motivos que os testes de unidade são executados no CI para prevenir regressões de funcionalidades, benchmarks deveriam ser executados no CI com o Bencher para prevenir regressões de desempenho. Bugs de desempenho são bugs!

Comece a capturar regressões de desempenho no CI — experimente o Bencher Cloud gratuitamente.

🤖 Este documento foi gerado automaticamente pelo OpenAI GPT-4. Pode não ser preciso e pode conter erros. Se você encontrar algum erro, abra um problema no GitHub.