No sábado, 4 de abril de 2026, o plano de dados do AppView do Bluesky — o backend que atende as leituras do aplicativo social — começou a registrar erros como 'failed to set post cache item: dial tcp: bind: address already in use'. O plano de dados depende fortemente do memcached para aliviar a carga do seu banco principal Scylla, e Jim Calabro, o engenheiro de infraestrutura de plantão, viu os picos de log coincidirem com quedas no tráfego voltado ao usuário. O monitoramento de rede estava limpo, então a causa permaneceu oculta durante o fim de semana enquanto o serviço seguia mancando.
A causa raiz era um novo serviço interno implantado naquela semana: menos de três requisições GetPostRecord por segundo, mas 15.000–20.000 URIs de posts por lote (o normal é de 1 a 50). Todo manipulador de RPC do plano de dados limita a concorrência com errgroup.SetLimit — apenas esse endpoint estava sem essa linha. Uma única chamada gerava até 20.000 goroutines, discando uma tempestade de conexões ao memcached; quando o pool ocioso de 1.000 sockets transbordou, elas se acumularam em TCP TIME_WAIT e esgotaram todas as portas efêmeras. O cliente rodava em um único data center e, sem métricas por cliente, erros de cache de todos os tipos mascaravam o culpado.
Na segunda-feira, 6 de abril, a situação mergulhou numa espiral da morte: com milhões de requisições ao memcached falhando por segundo, a política do Bluesky de registrar todo erro tentava milhões de gravações de log write(2) bloqueantes por segundo. A enxurrada de chamadas de sistema bloqueantes levou o runtime Go de cerca de 150 para 1.500 threads de SO, privando o GC de recursos e provocando longas pausas stop-the-world. O ajuste agressivo de GOGC e GOMEMLIMIT fez o plano de dados sofrer falhas periódicas por OOM — no ar por cerca de 30 minutos, caía, repetia. Cada reinício aprofundava o buraco: sockets em TIME_WAIT deixavam o processo reiniciado incapaz de recriar seu pool de memcached.
O curativo de segunda-feira foi gloriosamente absurdo: um dialer personalizado que escolhia um IP de loopback 127.x.y.z aleatório para cada conexão de saída, ampliando o espaço de ip+porta além da faixa esgotada. Isso deteve a espiral, e só na quarta-feira a equipe encontrou a verdadeira causa raiz e restaurou o SetLimit(50) ausente. O post-mortem público de Calabro também assumiu uma falha de comunicação: a página de status havia culpado um provedor de rede terceirizado, o que 'claramente não era o caso'.
Indisponibilidade intermitente para aproximadamente metade de todos os usuários do Bluesky ao longo de cerca de oito horas em 6 de abril de 2026 — a pior queda da plataforma no tempo de seu líder de infraestrutura ali
A concorrência limitada era imposta por convenção, não por estrutura: todo manipulador tinha SetLimit exceto um, e um único endpoint sem limite bastou para esgotar recursos no nível do host.
O contrato de tráfego não tinha limites de forma: nada rejeitava um lote de 20.000 itens, então um cliente interno discreto — 3 requisições por segundo — superou milhões de clientes normais como fonte de carga.
O tratamento de falhas amplificou a falha: registrar todo erro de memcached a milhões de erros por segundo converteu um problema de cache em explosão de threads, pausas de GC e falhas por OOM.
A observabilidade pressupunha requisições pequenas e não tinha métricas por cliente, então erros de todos os tipos de cache esconderam o único chamador e o único endpoint responsáveis por dias.
O reinício como recuperação estava quebrado: sockets em TIME_WAIT do processo morto impediam o novo processo de reconstruir seus pools de memcached, transformando reinícios por OOM em mais esgotamento de portas.
A lição
Um único laço de goroutines sem limite superou todas as outras salvaguardas. Limites de concorrência devem ser estruturais, não um hábito por endpoint: o único endpoint sem um tornou-se o incidente inteiro.
O serviço foi estabilizado na segunda-feira com o dialer de loopback aleatório, que foi removido assim que a correção real — a restauração do limite de concorrência — entrou no ar na quarta-feira, 8 de abril. A exposição total foi de cerca de oito horas de indisponibilidade intermitente para aproximadamente metade dos usuários. O post-mortem, publicado em 10 de abril de 2026, prometeu observabilidade por cliente, detecção de clientes que enviam pequenos números de requisições superdimensionadas e uma mudança do registro de logs em alto volume para métricas Prometheus e rastreamento OpenTelemetry; ele rendeu uma análise independente detalhada do pesquisador de confiabilidade Lorin Hochstein dois dias depois.
CONFIRA AS EVIDÊNCIAS
As fontes
- April 2026 Outage Post-Mortem Jim Calabro (Bluesky infrastructure engineer), pckt.blog · pckt.blog ·
- Thoughts on the Bluesky public incident write-up Surfing Complexity (Lorin Hochstein) · surfingcomplexity.blog ·
- Bluesky April 2026 Outage Post-Mortem (discussion, 141 points) Hacker News · news.ycombinator.com ·