PRODPlataforma BaaS europeia soberanaAbra o painel →

Desempenho · 10 minutos de leitura

Por que nenhum coletor de lixo altera a latência p99

Affane Daylami · Fondateur · 2 de julho de 2026

Voltar ao blog

p99 mede a solicitação mais lenta entre cem – aquela que quebra seu SLA enquanto a média permanece perfeita. Em um back-end de alto tráfego, esse punhado de solicitações lentas geralmente tem uma única causa: o coletor de lixo, que interrompe o programa inteiro para liberar memória. Rust não tem coletor de lixo. Aqui está o mecanismo, com fontes de terceiros datadas, em vez de números de marketing.

Este texto em inglês foi gerado automaticamente a partir do original em francês e ainda não foi revisado.
Esta página foi traduzida automaticamente. A versão em inglês é oficial.

Este artigo baseia-se exclusivamente em fontes datadas de terceiros – nunca em uma cifra Aurabase inventada. Nenhuma latência p99 específica para nosso back-end está incluída. Escrevemos o núcleo da nossa aplicação em Rust, sem coletor de lixo: fato que pode ser verificado diretamente no código, no workspace Cargo e nos serviços axum. No entanto, ainda não publicamos uma metodologia de benchmark p99 reproduzível para demonstrar isso em números. Este texto explica um mecanismo, não um resultado medido.

O essencial

  • p99 mede a consulta mais lenta entre cem – o local onde a pausa do coletor de lixo (GC) prejudica mais, não em média (Dean & Barroso, “The Tail at Scale”, Google, 2013).
  • Um GC interrompe todo o programa (“stop-the-world”) para liberar memória não utilizada. Rust não possui GC: a memória é liberada no exato momento em que um valor sai do escopo, verificado pelo compilador.
  • O Discord documentou um serviço de cache em 2020, onde Go acionava um ciclo de coleta de lixo pelo menos a cada dois minutos, com cada ciclo causando um aumento na latência (Discord Engineering Blog).
  • Reduzir uma pausa no GC leva anos de engenharia, mesmo no Google: o coletor GB passou de 300-400 ms para 500 µs entre 2015 e 2018, sem nunca chegar a zero (go.dev).
  • O núcleo backend do Aurabase é escrito em Rust, sem coletor de lixo – verificado no código. Nenhum número de latência do p99 Aurabase foi publicado até o momento: isso continua sendo um mecanismo, não uma medida.
#
Latência de cauda

Por que p99 não é mediano

Uma média esconde o essencial. Se 99 solicitações em 100 responderem em 5 ms e apenas uma levar 500 ms, a média permanecerá baixa. Mas um em cada cem usuários enfrenta uma espera cem vezes maior. O p99 mede exatamente esta solicitação: o centésimo mais lento, aquele que viola seu SLA enquanto seu painel de latência média permanece verde.

No Google, Jeffrey Dean e Luiz André Barroso formalizaram esse problema em “The Tail at Scale” (Communications of the ACM, vol. 56, 2013). A sua observação, frequentemente citada desde então: “Episódios temporários de alta latência que não são importantes em sistemas de tamanho moderado podem vir a dominar o desempenho geral do serviço em grande escala”. Resumindo: episódios ocasionais de latência, insignificantes em pequena escala, acabam dominando o desempenho percebido de um sistema distribuído.

Um back-end que processa milhares de solicitações por segundo certamente enviará, em um ponto ou outro, uma solicitação que cai durante uma pausa do GC. Em grande escala, este não é um caso incomum. Esta é uma certeza estatística.

#
Mecânica de GC

O que um coletor de lixo faz e por que pausa tudo

Um coletor de lixo (GC) rastreia continuamente os objetos vivos de um programa — aqueles ainda referenciados em algum lugar — e libera a memória de objetos que se tornaram inacessíveis. Esse rastreamento é chamado de tracing: o GC percorre o gráfico de referência, marca o que ainda é usado e depois varre o restante.

O problema: percorrer este gráfico enquanto o programa continua a criar novas referências produz resultados inconsistentes. A resposta histórica, ainda usada como último recurso por muitos GCs modernos, é stop-the-world — todo o programa faz uma pausa durante a marcação e a digitalização. Quanto maior o heap, mais longa tende a ser a pausa: sua duração depende do tamanho dos dados ativos, não da carga de trabalho atual.

A maioria dos GCs modernos utiliza uma estratégia geracional: eles assumem que a maioria dos objetos morre jovem. As alocações recentes são, portanto, verificadas frequentemente, mas rapidamente, em uma pequena área de memória. Objetos que sobrevivem a vários ciclos migram para uma área maior, escaneados com pouca frequência — mas quando essa área precisa ser limpa, a pausa associada aumenta com seu tamanho. É esta quebra “grande”, e não as pequenas quebras “menores”, que domina o p99 de um serviço de alto tráfego e alta alocação.

Informações

Os GCs simultâneos e geracionais modernos reduzem a frequência e a duração dessas pausas, trabalhando em paralelo com o programa. Mas quase todos eles mantêm um mecanismo alternativo de parar o mundo para casos limítrofes – e reduzi-lo requer anos de engenharia. A seção 04 fornece um exemplo quantificado e fundamentado.

#
Caso real

Discord, 2020: uma quebra de GC se torna um incidente de produção

Em fevereiro de 2020, o engenheiro Jesse Howarth publicou um post que se tornou referência no setor: “Por que o Discord está mudando do Go to Rust” (Discord Engineering Blog). O serviço relevante, Read States, gerencia o status de leitura de mensagens para milhões de usuários – dezenas de milhões de entradas por cache – com centenas de milhares de atualizações por segundo.

O diagnóstico é direto, citado como está no artigo: “Go forçará uma coleta de lixo a cada 2 minutos no mínimo”. Em outras palavras, Go aciona um ciclo de coleta de lixo pelo menos a cada dois minutos neste serviço — e cada ciclo produz um aumento na latência visível nos gráficos da equipe.

A equipe primeiro reduziu o tamanho do cache para suavizar os picos. O compromisso permaneceu desfavorável: menos pausas de GC, mas mais solicitações de perda de cache caindo no banco de dados – portanto, um p99 geral degradado em outros lugares. A solução básica foi reescrever o serviço em Rust, sem coletor de lixo para monitorar.

A postagem gerou um acalorado debate técnico: mais de 1.580 pontos e 642 comentários no Hacker News no mesmo dia de sua publicação (4 de fevereiro de 2020) — sinal de que o problema vai muito além do caso Discord.

#
Ir para a história

Três anos de engenharia no Google para reduzir a pausa de 400 ms para 500 µs

O coletor de lixo Go ilustra a escala do esforço necessário para controlar uma pausa do GC – mesmo com os recursos de uma equipe dedicada do Google. Rick Hudson, líder técnico do Go GC, documentou essa história em duas postagens oficiais do blog Go.

Antes de agosto de 2015300-400msColecionador histórico de Go, antes do redesenho
Agosto de 2015 · Vá para 1.530-40msPrimeiro coletor concorrente, meta < 10 ms definida
2016 · Ir 1.6< 10 ms (SLO mantido)Objetivo inicial alcançado na produção
Março de 2017 · Vá para 1.8abaixo do milissegundoRemovendo a verificação de pilha stop-the-world
Agosto de 2017 · Vá para 1.9100-200 µs (marca)Novo benchmark informal mencionado pela equipe
2018 · SLO anunciado500 µs por cicloObjetivo de serviço formalizado por Rick Hudson

Fonte: “Getting to Go: The Journey of Go’s Garbage Collector”, go.dev, 12 de julho de 2018; e “Go GC: Priorizando baixa latência e simplicidade”, go.dev, 31 de agosto de 2015.

Três anos de trabalho dedicado reduziram a quebra típica por um fator de mil. Mas a pausa nunca desapareceu: é um objetivo de serviço (SLO), e não uma garantia absoluta de zero. Um traçado de GC deve, por construção, percorrer um gráfico de objetos vivos de tempos em tempos. A única variável ajustável é a frequência e a duração desta viagem – não a sua existência.

Esta escolha de prioridade não é neutra. Go visa principalmente serviços de rede e back-ends da web, onde uma pausa de várias centenas de milissegundos interrompe diretamente a experiência do usuário – daí o enorme esforço investido em latência, em vez de taxa de transferência bruta de GC. Outros tempos de execução gerenciados herdaram diferentes compensações, moldadas por seus casos de uso históricos, antes de ganhar terreno com seus próprios coletores de baixa pausa. O ponto comum permanece o mesmo: todos partem do traçado do GC, portanto de um mecanismo de pausa a ser minimizado – nunca eliminado pela construção.

#
Mecânica da Ferrugem

Por que Rust não tem esse problema por construção

A ferrugem não reduz as pausas do GC: elimina o mecanismo que as causa. O compilador rastreia, na compilação, quem possui cada valor de memória - este éownership. Quando o dono de um valor sai do escopo, o Rust insere automaticamente a chamada que libera aquela memória, no mesmo local do código binário. Esse mecanismo é chamado de RAII (Resource Acquisition Is Initialization): a liberação é determinística, não agendada por um coletor de lixo em execução em segundo plano.

Alexandru Nedelcu, autor de um blog técnico reconhecido no ecossistema Scala/Rust, resume a compensação em um artigo recente: “A compensação que Rust faz é a facilidade de uso, em preferência ao desempenho com latência previsível e segurança” (alexn.org, 21 de julho de 2026). Rust troca um pouco da simplicidade da escrita por uma latência previsível.

O mesmo artigo resume porque os GCs modernos nem sempre são suficientes: "Os GCs modernos tentam fazer o seu trabalho de forma incremental e simultânea, sem afetar o programa. Mas a sua capacidade é limitada, recorrendo a um ciclo de GC de parar o mundo que congela todo o programa, afetando assim a latência".

Aqui está o mecanismo em cerca de dez linhas — um exemplo genérico, não um extrato do código Aurabase:

example.rsrust
struct Connection {
    id: u32,
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("connexion {} fermée", self.id);
    }
}

fn handle_request() {
    let conn = Connection { id: 42 };
    // ...processa a solicitação...
} // conn sai do escopo aqui: drop() é executado
   // no momento preciso, verificado pelo compilador -
   // não através de um ciclo de coleta de lixo.

Nuance importante: nem tudo é de graça. Os tipos de contagem de referências (Rc, Arc) adicionam um pequeno custo a cada clone e lançamento. Este custo permanece local e determinístico. Nunca há uma pausa que congele o programa inteiro enquanto ele passa por uma pilha de memória.

Esclarecimento útil para um back-end assíncrono: o tempo de execução assíncrono Rust (tokio, usado por todos os serviços Aurabase) não tem nada a ver com um coletor de lixo. Ele agenda tarefas cooperativas em um conjunto de threads, mas nunca itera através de um gráfico de objeto ativo para liberar memória. A confusão é comum em ecossistemas onde o tempo de execução assíncrono e o GC são gerenciados pela mesma máquina virtual.

#
Implicação arquitetônica

O que isso muda para um back-end de alto tráfego

Em um backend que atende milhares de solicitações simultâneas, a ausência de GC remove uma variável da equação p99. Não há mais necessidade de dimensionar um heap de memória, ajustar as gerações de um coletor ou monitorar um ciclo que pode cair no pior momento. A latência de uma solicitação individual depende do seu próprio trabalho, e não de algum evento global imprevisível em outra parte do programa.

O núcleo backend do Aurabase aplica este princípio: todos os serviços (aura-gateway, aura-auth, aura-db, aura-realtime, aura-storage, aura-functions, aura-ai…) são escritos em Rust, organizados em um único Cargo workspace. Isso pode ser verificado diretamente no repositório:

Cargo.tomltoml
[workspace]
resolver = "2"

members = [
    "services/aura-gateway",
    "services/aura-auth",
    "services/aura-db",
    # ...9 outros serviços + bibliotecas compartilhadas
]

[workspace.dependencies]
axum = { version = "0.8", features = ["ws", "multipart", "macros"] }

Extrato real de Cargo.toml, edição do espaço de trabalho 2021, resolvedor v2 - verificado no repositório Aurabase.

O que este facto não prova, nesta fase: um valor de latência p99 medido para Aurabase. Ainda não publicamos uma metodologia de benchmark reproduzível para nosso próprio back-end — este é um trabalho em andamento, não um resultado disponível hoje. A ausência de coletor de lixo é um mecanismo verificado no código. Isso por si só não é evidência da latência medida do p99. Tenha essa distinção em mente diante de qualquer argumento de marketing sobre o assunto, incluindo o nosso - consulte nossa comparação técnica Aurabase vs Supabase para obter detalhes da arquitetura.

Medir corretamente um p99 requer disciplina própria: condições de carga representativas, percentis calculados em uma janela deslizante suficientemente ampla e um ambiente de teste próximo à produção. Publicar uma figura sem esta metodologia é como publicar uma figura de marketing. Isto é exatamente o que nos recusamos a fazer neste artigo.

#
Nuance

O que a ausência de GC não resolve

No-GC não é uma varinha mágica

A remoção do coletor de lixo elimina apenas uma fonte de latência final – não todas. Um back-end Rust ainda pode mostrar um p99 degradado devido à espera da rede, um pool de conexões Postgres saturado, um bloqueio de banco de dados contestado, uma consulta SQL mal indexada ou uma chamada lenta de API de terceiros. O mecanismo descrito neste artigo elimina uma causa estrutural. Não fornece imunidade contra outras pessoas.

No Aurabase, por exemplo, cada serviço se comunica com o Postgres através de um pool de conexões (sqlx) e com outros serviços via NATS JetStream. Um pool subdimensionado, uma assinatura NATS de consumo lento ou uma consulta SQL sem um índice adequado produzem seu próprio pico de latência, independentemente da ausência de um coletor de lixo.

A conclusão prática: a ausência de GC é uma boa razão arquitetônica para escolher um back-end Rust para um sistema compatível com p99. Isto não é, por si só, uma garantia de latência – nem na Aurabase, nem em qualquer outro lugar. O método que importa permanece o mesmo: medir, publicar a metodologia e depois corrigir o que as medições revelam. Se você estiver migrando de um back-end com GC, nosso guia de migração Supabase para Aurabase detalha o que está mudando e o que permanece igual.

#
Perguntas frequentes

FAQ: coletor de lixo e latência p99

A ausência do coletor de lixo garante p99 baixo?+
Não. Ele remove uma fonte estrutural de pausas imprevisíveis, mas outros fatores (rede, pool de conexões, bloqueios de banco de dados) também influenciam a latência final. Consulte a seção “O que nenhum GC não corrige” acima.
Por que o Discord não ajustou seu GC Go de maneira diferente?+
A equipe tentou vários ajustes, incluindo uma redução no tamanho do cache, documentada em sua postagem de 2020. A compensação permaneceu desfavorável: menos pausas de GC versus mais perdas de cache. Reescrever em Rust removeu o comprometimento em vez de movê-lo.
Os GCs modernos como Go resolveram o problema?+
Eles o reduziram enormemente – o GC do Go passou de 300-400 ms para 500 microssegundos entre 2015 e 2018 (go.dev) – mas não o eliminou. Um rastreamento de GC mantém, por construção, um mecanismo de pausa para casos extremos.
A Aurabase lançou um benchmark de latência p99?+
Ainda não. O fato verificado no código é a ausência de coletor de lixo (Rust, workspace Cargo, axum services). O valor medido da latência p99 e sua metodologia reproduzível ainda não foram publicados – preferimos nenhum valor a um valor sem fontes.

PRONTO PARA IMPLEMENTAR?

Seu back-end em cinco minutos.

Não é necessário cartão de crédito · 500 MB grátis · 50.000 MAU