Executando verificação de segurança...
29

500 pessoas online. Banco offline. A história de como quase perdi a Git City.

A Git City é uma cidade 3D onde cada prédio representa um dev do GitHub. Altura = commits, largura = repos, janelas acesas = atividade recente. Hoje são mais de 60 mil prédios.

Mas teve uma semana em que quase perdi tudo. O banco caiu duas vezes.

Como funcionava

No começo eu carregava a cidade em chunks de 1.000 prédios. Cada usuário que abria o site disparava uma série de requests em paralelo:

GET /api/city?chunk=1   → 1.000 prédios
GET /api/city?chunk=2   → 1.000 prédios
GET /api/city?chunk=3   → 1.000 prédios
...

Com 10 mil devs na cidade, eram 10 requests por usuário. Funcionava perfeitamente.

O dia que explodiu

De um dia pro outro, a Git City viralizou. Saiu de 12 mil pra 30 mil devs. E com a viralização, vieram os acessos simultâneos.

  • 30K prédios na cidade
  • 500 pessoas online ao mesmo tempo
  • 30 requests por usuário

Faz a conta: 500 x 30 = 15.000 queries simultâneas no banco.

O Supabase não aguentou. Banco fora do ar. Cidade offline. Ninguém conseguia acessar.

A tentativa "certa"

Minha primeira reação foi fazer o que qualquer dev faria: criei uma RPC no Postgres que retornava todos os 30 mil devs em uma única query. Menos requests, menos overhead, certo?

Errado. Piorou. A query era pesada demais, o banco travou e caiu de novo.

Duas quedas na mesma semana.

A solução mais simples

Depois de quebrar a cabeça, percebi que o problema real era outro: eu não precisava que cada usuário consultasse o banco. A cidade não muda a cada segundo. Os dados mudam quando alguém faz um commit no GitHub, não quando alguém abre o site.

A solução:

  1. Um cron roda a cada 5 minutos e gera um snapshot da cidade inteira
  2. O snapshot é salvo como arquivo estático no Supabase Storage
  3. A Vercel faz cache na edge e serve pra todo mundo

Resultado: zero queries no banco, não importa se tem 1 ou 10 mil pessoas online. A cidade carrega em 2 segundos.

Mas aí veio outro problema

Com 60 mil prédios, o snapshot JSON ficou grande. Muito grande. 54 MB.

O Supabase Storage tem um limite padrão de 50 MB por arquivo. O upload passou a falhar silenciosamente e a cidade ficou desatualizada sem eu perceber.

A solução? Uma linha de código.

Gzip. Compacta no servidor antes de salvar, descompacta no navegador quando carrega. De 54 MB pra 4 MB. O usuário nem percebe.

O que eu aprendi

Quando o banco caiu pela primeira vez, meu instinto foi criar uma solução mais sofisticada (a RPC). Quando isso piorou tudo, eu parei e pensei no problema real.

A resposta não era uma query mais inteligente. Era não fazer query nenhuma.

A solução mais simples resolveu tudo:

  • Um cron de 5 minutos
  • Um arquivo estático
  • Cache na edge
  • Gzip quando ficou grande demais

Nem sempre a solução mais complexa é a melhor. Na maioria das vezes, a mais simples resolve.


A Git City é open source. Se quiser ver seu prédio na cidade, é só conectar o GitHub.

Carregando publicação patrocinada...
5

As informações que você compartilha sobre o desenvolvimento do seu projeto são bem legais. Esses dias vi no Instagram que você teve contato com um desenvolvedor da Vercel que abriu uma série de PRs para ajudar a reduzir custos, o John Phamous, mas não me aprofundei muito nos PRs para entender as mudanças.

Seria legal ler sobre como foi e quais impactos reais, se já for possível avaliar algo nesses poucos dias que as mudanças estão em produção.

O pouco que vi me deu a impressão que as sugestões foram geradas por IA, até porque a Vercel tem skill de agentes.

Para quem não viu essa interação, além dos PRs no GitHub, tem a thread no X.

2
1

Que legal acompanhar essa experiência.

Na questão do JSON, talvez fosse interessante usar a técnica de JSON streaming, pra carregar em blocos, daí não iria sobrecarregar muito o navegador, e a renderização começaria a partir do primeiro bloco, e não ficaria preso à esses 50 MB, algo parecido com o Chunk loading usado em jogos. Também seria possível quebrar a renderização em mais etapas, 1: tamanho e formato dos prédios, 2: janelas e luzes, 3: texturas e demais detalhes. Nesses jogos de mundo aberto, como Minecraft, a renderização é escalonada e direcionada de acordo com a posição da "câmera".

1

A parte mais valiosa do relato é que a primeira solução "certa" (RPC que retornava tudo numa query) piorou o problema. A tentação de resolver com mais complexidade técnica é forte, mas aqui a resposta era o contrário: parar de fazer queries no banco.

Cron + arquivo estático + cache na edge é elegante justamente por ser simples. Boa escolha.

0

Vale ressaltar que a escolha do cron job para gerar o snapshot é uma boa solução, mas é importante monitorar a latência de atualização conforme a cidade cresce. Um sistema de WebSocket poderia ser considerado futuramente para eventos de mudança em tempo real, especificamente para quando novas construções ou alterações forem feitas, mantendo todos os usuários informados e engajados em tempo real.

0

+3

Sensacional o relato, @shrizzon! A máxima de que "a solução mais simples costuma ser a melhor" se provou real mais uma vez. Muitas vezes o instinto é otimizar a query ou a infraestrutura do banco, quando as vezes o ganho real está em apenas mudar o paradigma para dados estáticos e cache.

Depois cola lá no discord da comunidade, adoraria trocar uma ideía. https://crom.run/comunidade

0

Show de bola! Incrível como um simples arquivo pode resolver um gargalo de banco de dados! Vlw pelas dicas! ;D

Rafael Laube
github.com/laube-developer