Dev & EngNOTÍ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.

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 Ruby↳Ruby3 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 AWS↳AWS20 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. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. 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.

Mais de Redação iMasters
Ver perfil →
Leia também