NOTÍCIA

Kino: o servidor web para Ruby 4.0 que usa Ractors para rodar em paralelo sem forks

Novo servidor Rack combina front-end em Rust com Ractors paralelos e promete usar todos os núcleos num único processo, mas ainda esbarra no Rails.

0
Kino: o servidor web para Ruby 4.0 que usa Ractors para rodar em paralelo sem forks
Imagem gerada por IA

Um novo servidor web para RubyRuby3 conteúdosComo migrei meus testes automatizados de Java para Ruby… Será que fiz bem?Dev (Back & Front) · jun 2019Refatoração em RubyDev (Back & Front) · mai 20197 exemplos de linguagens de programação server-sideGestão Dev & TI · jun 2024Ver tudo em Dev (Back & Front) chamado Kino apareceu no topo do Hacker News propondo resolver um problema antigo da linguagem: como usar todos os núcleos de CPU sem pagar o custo de memória do modelo de fork por processo. O projeto, publicado no GitHub no repositório yaroslav/kino, exige Ruby 4.0+ e usa os Ractors para rodar código Ruby de fato em paralelo dentro de um único processo.

O problema que ele ataca

A GVL (Global VM Lock) do Ruby permite que apenas uma thread execute código Ruby por vez. Por isso, servidores como o Puma em produção fazem fork de um processo por núcleo, e cada cópia paga o custo de memória do app inteiro. Os Ractors, introduzidos como recurso experimental no Ruby 3.0 e retrabalhados no Ruby 4.0 (com Ractor::Port, shareable_proc e menos contenção de lock), não têm essa limitação: cada Ractor tem seu próprio lock, então um processo consegue rodar Ruby em paralelo.

Segundo o README do projeto, o que faltava era um servidor que soubesse despachar requisições para esses Ractors, e as mudanças do Ruby 4.0 tornaram isso viável de construir.

Como funciona por dentro

A arquitetura é híbrida. Um front-end escrito em Rust (usando tokio + hyper) cuida da rede, enquanto Ractors paralelos executam a aplicação Rack 3. Há também um modo de fallback baseado em threads tradicionais para tudo que ainda não roda em Ractor, incluindo Rails.

São três modos de operação:

  • :ractor: workers Ractors, cada um com threads threads. Exige que o app seja Ractor.shareable? (middleware congelado, endpoints via shareable_proc). Forçar esse modo com um app não compartilhável levanta Kino::UnshareableAppError.
  • :threaded: a mesma máquina, mas com Threads comuns. Roda qualquer app Rack, inclusive Rails, mas serializado pela GVL para trabalho de CPU.
  • :auto (padrão): usa :ractor quando o app é compartilhável, senão emite um aviso e cai para :threaded.

O projeto se apresenta como "Puma-shaped": mesma topologia de workers × threads, DSL de configuração familiar e uma CLI kino. A promessa é que quem sabe rodar Puma sabe rodar Kino.

Os números do benchmark

Os testes foram medidos numa instância AWSAWS20 conteúdosE-mails de verificação com AWS SES + Lambda (Node.js) e Terraform: do zero ao envioDevSecOps · out 2025Codex na AWS: chegada do agente da OpenAI à nuvem da AmazonDevSecOps · abr 2026Salesforce e AWS ampliam colaboração em IA, CRM e marketplaceDevSecOps · nov 2023Ver tudo em DevSecOps c7a.2xlarge (8 núcleos AMD EPYC, 16 GB, Amazon Linux 2023), com Ruby 4.0.5 e YJIT. O Puma rodou com 8 workers × 3 threads; o Kino ficou em um único processo. As requisições foram medidas com wrk.

Em endpoints leves de I/O, o README afirma que todo modo do Kino fica de 1,5x a 2,1x à frente do cluster de forks do Puma. Alguns números da tabela principal (req/s):

  • /plaintext: Kino :ractor 229.534 vs Puma 118.176
  • /10k: Kino :ractor 178.083 vs Puma 106.768
  • /cpu (fib): Kino :ractor 77.999 vs Puma 58.006 (ganho de +34%)

O destaque é a CPU pura: o modo Ractor roda trabalho de CPU mais de 5x mais rápido que o próprio modo threaded do Kino (limitado pela GVL), tudo no mesmo processo pequeno.

Na memória (medida por PSS), o app sintético de benchmark rodou com ~7x menos memória no modo Ractor: 148 MB do Kino contra 1.068 MB do cluster Puma de 8 workers.

A ressalva importante: Rails

Aqui está o ponto que o dev brasileiro precisa entender antes de se animar. Rails não é Ractor.shareable hoje, então o Kino o serve apenas no modo :threaded de fallback, ou seja, um único processo limitado pela GVL. E os números mudam de figura:

  • Kino :threaded (um processo): 2.637 req/s, 92 MB
  • Puma cluster (8 workers): 12.138 req/s, 389 MB

O próprio README chama isso de "trade-off honesto": o cluster de forks do Puma usa os 8 núcleos e serve ~4,6x mais throughput, mas ao custo de ~4x mais memória. O Rails em modo Ractor fecharia essa diferença de throughput com o custo de memória de um único processo, mas os bloqueios estão no upstream (o próprio Ruby/Rails), rastreados em doc/rails-on-ractors.md.

Ou seja: para a maioria das aplicações Rails em produção no Brasil, o ganho imediato não existe hoje. O apelo real é para apps Rack "puros" (Sinatra, Roda ou serviços customizados) que você consiga tornar Ractor-shareable.

A ferramenta kino --check

Um detalhe prático interessante: como descobrir por que seu app não roda em modo Ractor costuma ser um pesadelo (o famoso Ractor::IsolationError sem contexto), o Kino traz o comando kino --check. Ele não modifica nada e lista cada bloqueador: variáveis capturadas com o local onde foram definidas, variáveis de instância por caminho, e a armadilha de ivars em nível de classe. Exemplo da saída:

$ kino --check
check: app is NOT Ractor-shareable
 - app (Proc at app.rb:12)—captures `cache` = {} (Hash) (unshareable)
 hints: freeze config at boot; build endpoints with Ractor.shareable_proc;
 keep per-worker resources in Ractor.store_if_absent; or run mode :threaded.

O status de saída é 0/1, então funciona em pipelines de CI.

Plumbing de produção

O servidor não é só um experimento de performance. Ele inclui drain gracioso, supervisão e respawn de crashes, filas limitadas com backpressure de 503, timeouts de requisição (que devolvem 504 sem matar o handler), proteções contra slowloris e handshakes TLS travados, TLS via rustls, e um hook on_error para integrar com rastreadores de erro. Há também um control plane de leitura (/stats, /metrics no formato Prometheus, /ready e /live para probes de Kubernetes) que continua respondendo mesmo quando todos os workers Ruby estão ocupados.

A instalação dispensa compilador Rust nas versões liberadas, que trazem gems nativas pré-compiladas para Linux (x86_64/aarch64, glibc e musl) e macOS arm64:

bundle add kino
bundle exec kino --init  # gera kino.rb comentado
bundle exec kino         # usa config.ru + kino.rb na porta 9292

O que fica em aberto

O próprio README é explícito: Ractors são oficialmente experimentais no Ruby 4.0, e o Kino também. O modo threaded é descrito como sólido, mas o projeto se posiciona como "a melhor forma de experimentar Ractors hoje", não como substituto de produção do Puma para Rails. Com um roadmap que depende de mudanças no próprio Ruby e no Rails, o Kino é mais um sinal de que o ecossistema Ruby está finalmente construindo ferramentas em cima dos Ractors do que uma troca imediata de servidor. Vale acompanhar, principalmente para quem mantém serviços Rack CPU-bound e quer parar de pagar memória por fork.

Fonte: 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?