Pular para o conteúdo
fernando.moretes.com
BlogEstudosCursosE-booksOpen SourcePodcasts
Loading…
Fernando Azevedo

Arquiteto de TI Especialista

Arquitetura, AWS, IA em produção, sistemas financeiros e FinOps, escritos a partir do que foi operado, com os números.

  • LinkedIn
  • GitHub
  • E-mail

Conteúdo

  • Blog
  • Estudos de arquitetura
  • Cursos
  • E-books
  • Open Source
  • Podcasts
  • Assuntos
  • Trilhas

Ferramentas

  • Well-Architected self-check
  • Arquitetura deste site
  • Números públicos
  • Histórico de estudo

Sobre

  • Comunidade
  • IA Builder
  • Perfil
  • Currículo (CV)
  • Trabalhe comigo
  • Media kit
  • RSS do blog
  • RSS dos estudos
  • Artigos narrados (podcast)
  • llms.txt
  • Termos, privacidade e uso de IA

(c) 2026 Fernando Francisco Azevedo

Estudos/Teardown
RSSMarkdownLLMs
TeardownFigmaDados

Figma: Sharding Horizontal de Postgres Sem Parar de Crescer

14 de mar. de 2024 7 min Com apoio de IA000 visualizações00 reproduções
Ouvir estudo

cerca de 7 min · áudio gerado ao tocar

Sharding de banco de dados é uma das operações mais arriscadas que uma engenharia pode executar em produção. O Figma fez isso com Postgres, em escala de produto SaaS global, sem downtime e sem interromper o crescimento, e depois contou como. Este teardown desmonta a arquitetura, avalia as decisões e diz o que eu mudaria.

Ficha Técnica

Empresa
Figma
Domínio
Plataforma de design colaborativo SaaS
Período da migração
2021–2022 (publicado em 2022)
Banco de dados original
PostgreSQL monolítico (instância única de escrita)
Banco de dados alvo
PostgreSQL com sharding horizontal por chave de tenant/objeto
Stack principal
PostgreSQL, PgBouncer, Ruby on Rails, infraestrutura AWS
Estratégia de roteamento
Camada de roteamento customizada na aplicação (shard map)
Downtime
Zero downtime para usuários finais
Impacto do problema
CPU, WAL lag e capacidade de conexões próximos do limite físico da instância primária

O Problema: Um Postgres Monolítico Engolindo Uma Empresa em Crescimento

O Figma cresceu rápido demais para a sua própria infraestrutura de dados. Durante anos, a arquitetura de banco de dados seguiu o padrão clássico de startups bem-sucedidas: um Postgres primário com réplicas de leitura, escalando verticalmente sempre que os sinais de alerta apareciam. Essa abordagem funcionou, até o momento em que deixou de funcionar.

O problema não foi um único evento catastrófico. Foi uma convergência de pressões: a instância primária acumulando CPU elevada de forma crônica, o WAL (Write-Ahead Log) apresentando lag crescente nas réplicas, e o pool de conexões operando perto do limite físico do PgBouncer. Em sistemas transacionais de alta frequência como o Figma, onde múltiplos usuários editam o mesmo documento em tempo real, qualquer degradação no banco de dados primário se propaga diretamente para a experiência do usuário.

A escala vertical havia chegado ao seu teto prático. Mover para uma instância maior resolveria o problema por meses, não por anos. O time precisava de uma solução estrutural, e a única saída era o sharding horizontal, distribuir os dados entre múltiplos nós Postgres independentes, cada um responsável por um subconjunto das entidades do sistema.

O que torna esse problema especialmente difícil é que o Figma não tinha o luxo de pausar o produto para fazer a migração. O crescimento do negócio continuava, novos usuários chegavam, novos arquivos eram criados. A migração precisava acontecer debaixo de um sistema em plena operação, sem que os usuários percebessem.

A Arquitetura Reconstruída: Como o Sistema Funciona

A solução do Figma pode ser decomposta em três camadas interdependentes: particionamento lógico, roteamento dinâmico e migração incremental com dupla escrita.

Particionamento lógico por chave de entidade

O esquema de sharding escolhido foi baseado em chave, especificamente, no identificador da entidade raiz (tipicamente o file_id ou equivalente de tenant). Isso significa que todos os dados relacionados a um determinado arquivo ou usuário são colocalizados no mesmo shard físico. A colocação é crítica: queries que atravessam shards (cross-shard joins) são extremamente custosas e, se mal planejadas, eliminam qualquer ganho de escala. O Figma optou por uma abordagem de colocação agressiva para evitar esse antipadrão.

O número de shards lógicos foi definido como um múltiplo intencional dos shards físicos. Isso é uma decisão de engenharia sofisticada: ao separar shards lógicos de shards físicos, o sistema pode rebalancear dados movendo shards lógicos entre nós físicos sem precisar rehashear todas as chaves. É o mesmo princípio do consistent hashing, mas implementado de forma mais explícita com um mapa de shards controlado pela aplicação.

Roteamento dinâmico na camada de aplicação

Em vez de adotar um proxy de banco de dados externo (como Vitess ou Citus), o Figma implementou o roteamento dentro da própria aplicação Rails. Existe um componente central, o shard map, que mantém o mapeamento de shard_id lógico → instância Postgres física. Antes de qualquer query, a aplicação consulta esse mapa para determinar para qual conexão de banco de dados rotear a operação.

Essa escolha tem implicações profundas. Por um lado, elimina um hop de rede e uma camada de infraestrutura adicional para operar. Por outro, acopla a lógica de roteamento ao código da aplicação, o que significa que toda mudança no mapa de shards precisa ser coordenada com o deploy da aplicação, ou gerenciada via feature flags e configuração dinâmica.

Migração incremental com dupla escrita e verificação

A parte mais delicada de toda a operação foi a migração dos dados existentes sem downtime. O processo seguiu um padrão clássico de migração online: primeiro, ativar a dupla escrita (dual-write) para as entidades sendo migradas, onde cada escrita vai tanto para o shard de origem quanto para o shard de destino; segundo, executar o backfill dos dados históricos em background, com controle de taxa para não sobrecarregar o primário; terceiro, verificar a consistência entre origem e destino antes de cortar o tráfego de leitura; quarto, promover o shard de destino como autoritativo e remover a escrita duplicada.

Cada fase dessa migração foi executada de forma incremental, tabela por tabela, entidade por entidade. Não foi uma big-bang migration, foi uma série de migrações cirúrgicas, cada uma com rollback definido.

Arquitetura de Sharding Horizontal do Figma

Fluxo de leitura/escrita com roteamento por shard map, dupla escrita durante migração e réplicas por shard físico.

🌐 Client Layer
  • Figma Client · (Browser / Desktop)
⚙️ Application Layer
  • Rails App · (API Servers)
  • Shard Map · (logical→physical)
  • PgBouncer · (connection pool)
🗄️ Shard 0 (Physical)
  • Postgres Primary · Shard 0
  • Postgres Replica · Shard 0
🗄️ Shard 1 (Physical)
  • Postgres Primary · Shard 1
  • Postgres Replica · Shard 1
🗄️ Shard N (Physical)
  • Postgres Primary · Shard N
  • Postgres Replica · Shard N
🔄 Migration Layer
  • Backfill Worker · (rate-limited)
  • Consistency Verifier · (diff checker)

A Complexidade Oculta: O Que Não Aparece no Diagrama

Qualquer diagrama de sharding parece razoável no papel. A brutalidade está nos detalhes operacionais que o diagrama não captura.

O problema das transações distribuídas

O Postgres não tem suporte nativo a transações distribuídas entre instâncias independentes. Isso significa que qualquer operação que precise de atomicidade entre dois shards diferentes precisa ser redesenhada. O Figma resolveu isso de duas formas: primeiro, através da colocação agressiva de entidades relacionadas no mesmo shard (evitando o problema na origem); segundo, aceitando consistência eventual em casos onde a atomicidade cross-shard era inviável e redesenhando o modelo de dados para eliminar dependências entre shards sempre que possível.

Essa é uma decisão de design que tem impacto direto no produto. Alguns padrões de query que eram triviais no monolito, um JOIN entre tabelas de entidades diferentes, se tornam operações proibidas ou muito custosas no mundo shardado. O time de engenharia precisou auditar todas as queries existentes e classificá-las por padrão de acesso antes de definir a estratégia de particionamento.

O custo humano da dupla escrita

A fase de dual-write é conceitualmente simples, mas operacionalmente cara. Durante o período de migração, cada escrita relevante precisa ir para dois destinos. Isso aumenta a latência de escrita, dobra a pressão sobre o pool de conexões, e introduz um novo vetor de falha: o que acontece se a escrita no shard de destino falhar? O Figma precisou definir políticas explícitas de tratamento de falha para cada fase da migração, e essas políticas precisavam ser conservadoras o suficiente para não corromper dados, mas agressivas o suficiente para não travar o produto.

Gerenciamento do shard map como infraestrutura crítica

O shard map não é um arquivo de configuração estático. É um componente de infraestrutura que precisa ser lido em alta frequência (toda query passa por ele), ter baixíssima latência, e ser atualizado de forma atômica durante rebalanceamentos. O Figma precisou tratar o shard map como um serviço de primeira classe, com cache na aplicação, invalidação controlada e monitoramento dedicado. Uma falha no shard map é uma falha global: se a aplicação não consegue resolver para qual shard rotear uma query, ela não consegue servir nenhuma requisição.

Schema migrations em um mundo shardado

No monolito, uma migration de schema é um evento único e controlado. Com N shards físicos, cada migration precisa ser executada N vezes, de forma coordenada, sem causar inconsistência entre shards durante o período de transição. O Figma adotou a prática de migrations compatíveis com versões anteriores (backward-compatible schema changes), adicionando colunas como nullable antes de torná-las obrigatórias, mantendo colunas antigas durante períodos de transição, para garantir que diferentes shards pudessem estar em estados de schema ligeiramente diferentes durante o rollout.

Matriz de Decisões: Opções de Sharding Consideradas

Roteamento na aplicação (escolha do Figma)

Prós
  • Sem hop adicional de rede
  • Controle total sobre lógica de roteamento e failover
  • Sem dependência de produto externo para o caminho crítico
  • Integração nativa com feature flags e rollout incremental
Contras
  • Lógica de sharding acoplada ao código da aplicação
  • Cada linguagem/serviço precisa implementar o roteamento
  • Shard map vira infraestrutura crítica gerenciada internamente

Correto para o contexto: stack Rails homogênea, equipe com controle total do código

Vitess (proxy MySQL-compatible)

Prós
  • Sharding transparente para a aplicação
  • Gerenciamento de conexões centralizado
  • Amplamente testado em produção (YouTube, PlanetScale)
Contras
  • Incompatível com Postgres, requereria migração de banco de dados também
  • Adiciona camada de infraestrutura complexa para operar
  • Latência adicional de proxy no caminho crítico

Descartado: incompatível com Postgres e introduz risco duplo

Citus (extensão Postgres para sharding)

Prós
  • Sharding nativo dentro do ecossistema Postgres
  • SQL distribuído com suporte a joins cross-shard
  • Compatível com ferramentas existentes do ecossistema
Contras
  • Adiciona complexidade operacional de extensão crítica
  • Migração de schema e dados para modelo Citus seria big-bang
  • Vendor lock-in para uma extensão específica

Viável, mas o custo de migração e o lock-in foram desfavoráveis no contexto

Escala vertical contínua

Prós
  • Zero mudança no código da aplicação
  • Operacionalmente simples
Contras
  • Teto físico de hardware já próximo
  • Custo exponencial por ganho linear de capacidade
  • Não resolve o problema de conexões (PgBouncer tem limite)

Solução paliativa, compra tempo mas não resolve o problema estrutural

Leitura pelo AWS Well-Architected Framework

Segurança

Adequado para o contexto, mas não destacado. O post não detalha a postura de segurança, mas a arquitetura implica múltiplos endpoints de banco de dados, cada um precisando de controle de acesso independente. Em ambientes regulados (o Figma não é financeiro, mas serve empresas enterprise), a proliferação de endpoints de banco de dados aumenta a superfície de ataque e a complexidade de auditoria. Credenciais rotacionadas por shard, network policies por instância, e auditoria de acesso por shard são requisitos que escalam linearmente com o número de shards.

Confiabilidade

Forte. A migração incremental com dual-write e verificação de consistência é um padrão de alta confiabilidade. Cada fase tem rollback definido. A separação entre shards lógicos e físicos permite rebalanceamento sem rehashing completo. O risco principal é o shard map como single point of failure lógico, se não for tratado com redundância e cache adequados, uma falha nele é uma falha global. O Figma demonstra consciência disso ao tratar o shard map como infraestrutura crítica.

Eficiência de performance

Forte. O objetivo central do projeto era performance, e a arquitetura endereça isso diretamente: distribuição de carga de escrita entre múltiplos primários, redução de contenção de locks, e pool de conexões por shard em vez de um pool global. A colocação de entidades relacionadas no mesmo shard minimiza o custo de queries. O risco de degradação de performance está nas queries cross-shard não antecipadas, que, sem auditoria rigorosa, podem aparecer em produção.

Sustentabilidade

Neutro. Mais instâncias significa mais consumo de energia. Não há informação pública sobre estratégias de eficiência energética específicas para essa arquitetura. A consolidação de shards lógicos em menos shards físicos quando o crescimento estabilizar seria a alavanca de sustentabilidade mais direta.

FA
O Que Eu Faria Diferente
Arquiteto de TI Especialista

A execução do Figma é tecnicamente sólida e o post é um dos mais honestos sobre sharding que já li. Mas há três pontos onde eu tomaria decisões diferentes, ou pelo menos questionaria mais cedo. 1. Shard map como serviço explícito, não como biblioteca embutida. Implementar o roteamento dentro da aplicação Rails é pragmático para uma stack homogênea, mas cria um problema de longo prazo: quando o Figma adicionar serviços em outras linguagens (Go, Python, o que for), cada um precisará reimplementar o cliente do shard map. Eu teria extraído o shard map como um serviço leve (um endpoint HTTP/gRPC com cache agressivo no cliente), garantindo que a lógica de roteamento fosse centralizada e versionada de forma independente do código da aplicação. O custo de latência de um cache local com TTL curto é negligenciável; o custo de manter N implementações do mesmo roteamento em N linguagens é alto. 2. Auditoria de queries cross-shard como gate obrigatório antes do sharding. O maior risco em uma migração de sharding é descobrir, em produção, que uma query crítica faz join entre entidades que foram parar em shards diferentes. Eu teria investido mais tempo, antes de qualquer linha de código de migração, em instrumentar o banco de dados monolítico para identificar todos os padrões de join, classificar entidades por afinidade de acesso, e só então definir a estratégia de particionamento. Isso é trabalho chato e lento, mas é o que separa uma migração de sharding bem-sucedida de um incidente de produção seis meses depois. **3.

Veredicto

O Figma executou uma das migrações de banco de dados mais complexas do ecossistema SaaS moderno e fez isso de forma incremental, reversível e sem downtime para o usuário final. A escolha de roteamento na aplicação em vez de um proxy externo é defensável e provavelmente correta para o contexto, stack homogênea, equipe com controle total do código, e necessidade de integração nativa com o ciclo de deploy. O que mais me impressiona nesse caso não é a tecnologia, sharding por chave é um padrão conhecido. O que impressiona é a disciplina de execução: a separação entre shards lógicos e físicos para facilitar rebalanceamento futuro, o processo de verificação de consistência antes de cada cutover, e a abordagem incremental que permitiu rollback em qualquer ponto. O post original do Figma é uma leitura obrigatória para qualquer engenheiro que trabalha com dados em escala. Ele não vende uma solução mágica, documenta o trabalho duro, os trade-offs reais, e os problemas que apareceram no caminho. Isso é raro e valioso.

Referências

Figma: How Figma's databases team lived to tell the scale
#postgres#sharding#data-platform#database#scalability#partitioning#migration#figma
Fontes do caso
Figma: How Figma's databases team lived to tell the scale
Compartilhar:LinkedInWhatsAppXBaixar em Markdown
Escrito com apoio de IA a partir do caso público e da minha leitura como arquiteto.
Próximo passo
Trilha Arquiteto de IA, gratuitaFundamentos, LLMs, RAG, tools, MCP e arquitetura na AWS, em aulas curtas e interativas.Começar a trilhaAgentes de IA em produção na AWSComo eu desenho, oriento e audito agentes que vão ao ar, com os números e as fontes.Ver o IA Builder

Continue lendo

TeardownNotion: O Modelo de Blocos e o Sharding do PostgresO Notion cresceu de um banco Postgres monolítico para uma arquitetura shardada horizontalmente, particionando dados por tenant para sustentar crescimento explosivo durante a pandemia. Este teardown reconstrói as decisões de modelagem, o processo de migração e os trade-offs reais de operar Postgres em escala.Ler TeardownShopify: Arquitetura de Pods para Escalar na Black FridayA Shopify redesenhou sua infraestrutura monolítica em torno de pods isolados e sharding de banco de dados para sobreviver aos picos extremos da BFCM sem degradação global. Este teardown reconstrói a arquitetura, examina as decisões de trade-off e avalia o que eu faria diferente com base em 16 anos operando sistemas de missão crítica.Ler TeardownDiscord: Como Armazenar Trilhões de Mensagens: Teardown da Migração Cassandra → ScyllaDBO Discord migrou seu armazenamento de mensagens de Apache Cassandra para ScyllaDB, eliminando latências de cauda imprevisíveis e pausas de GC que afetavam milhões de usuários. Este teardown reconstrói a arquitetura, examina as decisões de engenharia e os trade-offs envolvidos, e apresenta minha leitura crítica do que foi feito bem, e o que eu faria diferente.Ler
AnteriorDatadog (2023): como um patch de segurança do systemd derrubou 5 regiões simultaneamentePróximoGoogle Cloud × UniSuper (2024): Quando uma Configuração Apagou uma Subscrição Inteira
Gostou deste estudo? Receba o próximo.

Post-mortems, ADRs e deep dives de arquitetura no seu email, do jeito que um arquiteto lê.

Sem spam · cancele quando quiser

Pergunte ao Fernando sobre isto

Uma resposta focada sobre este estudo, do meu assistente de IA, baseada no meu trabalho.

Participe da conversa

Entre para comentar

Confirme seu e-mail para participar, você também recebe a newsletter. Sem senha.

Neste estudo
O Problema: Um Postgres Monolítico Engolindo Uma Empresa em CrescimentoA Arquitetura Reconstruída: Como o Sistema FuncionaArquiteturaA Complexidade Oculta: O Que Não Aparece no DiagramaMatriz de Decisões: Opções de Sharding ConsideradasWell-ArchitectedVeredictoReferências