Arquitetura real · Júnior
Instagram: 14 milhões de usuários com 3 engenheiros (Postgres e IDs por shard)
Arquitetura real em produção. Pontos centrais: geração de IDs únicos e shards lógicos vs físicos.
Resposta curta
Arquitetura real em produção. Pontos centrais: geração de IDs únicos e shards lógicos vs físicos. Em dezembro de 2011, o time do Instagram descreveu a própria pilha como um retrato de como uma startup com equipe pequena pode escalar até mais de 14 milhões de usuários em pouco mais de um ano. Naquele momento eram apenas 3 engenheiros.
01 · CONTEXTO
Uma startup, poucos engenheiros, muito tráfego
Em dezembro de 2011, o time do Instagram descreveu a própria pilha como um retrato de como uma startup com equipe pequena pode escalar até mais de 14 milhões de usuários em pouco mais de um ano. Naquele momento eram apenas 3 engenheiros.
Os princípios para escolher cada peça eram manter tudo muito simples, não reinventar a roda e preferir tecnologias comprovadas e sólidas quando possível. Tema de escalar na horizontal.
02 · A PORTA DE ENTRADA
Do DNS round-robin ao balanceador gerenciado
Toda requisição passava por máquinas de balanceamento de carga. A primeira versão usava 2 máquinas nginx com DNS round-robin entre elas, e o ponto fraco era o tempo que o DNS leva para atualizar quando uma das máquinas precisava ser desativada.
O app consulta o DNS, que reveza as respostas entre as duas máquinas nginx.
Para tirar uma máquina de circulação é preciso esperar o DNS atualizar; esse é o ponto fraco apontado pelo time.
Depois o time passou a usar o Elastic Load Balancer da Amazon, com 3 instâncias NGINX atrás dele, que podem ser trocadas e saem de rotação automaticamente se falharem num health check. O SSL também passou a ser terminado no ELB, o que alivia a CPU do nginx.
| Aspecto | DNS round-robin | ELB com NGINX atrás |
|---|---|---|
| Máquinas nginx | 2 máquinas | 3 instâncias |
| Retirar uma máquina | Depende do DNS atualizar | A instância pode ser trocada e sai de rotação se falhar no health check |
03 · APLICAÇÃO, DADOS E CACHE
A pilha completa em 2011
A camada de aplicação cresceu de poucas máquinas para mais de 25, e é a parte fácil de escalar na horizontal porque as máquinas são stateless. O time observou que a carga era limitada por CPU, não por memória.
A requisição entra pelo ELB, que também termina o SSL, e é distribuída a uma das instâncias NGINX.
O NGINX repassa a requisição a um servidor de aplicação, camada que o time ampliou ao crescer.
A aplicação lê e grava no PostgreSQL, que roda em master-replica com Streaming Replication.
A aplicação usa Memcached como cache e Redis para feeds e sessões.
As fotos vão direto para o S3, e o CloudFront serve de CDN para melhorar o tempo de carga das imagens no mundo todo.
Tarefas como compartilhar em outras redes vão para uma fila e são tratadas por workers em segundo plano.
A maior parte dos dados (usuários, metadados de fotos, tags) ficava em PostgreSQL. O cluster principal tinha 12 instâncias de memória grande e doze réplicas em outra zona. O time viu que o disco de rede do EBS não oferecia seeks suficientes, então manter o working set em memória era extremamente importante.
| Armazenamento | O que guarda |
|---|---|
| PostgreSQL | Usuários, metadados de fotos e tags |
| Redis | Feed principal, feed de atividade e sessões |
| Memcached | Cache, com 6 instâncias |
| Amazon S3 | Os arquivos das fotos |
04 · QUANDO UM BANCO NÃO BASTA
Shardar sem trocar de banco
No fim de 2012 o Instagram recebia mais de 25 fotos e 90 curtidas por segundo. Para manter os dados importantes na memória e disponíveis rapidamente, o time começou a shardar os dados, isto é, a dividi-los em muitos baldes menores, cada um com uma parte.
O time avaliou algumas soluções NoSQL, mas concluiu que o que melhor atendia era distribuir os dados por um conjunto de servidores PostgreSQL.
Era preciso resolver como atribuir identificadores únicos a cada dado do banco. A solução típica de um único banco, a chave primária autoincremental, deixa de funcionar quando os dados entram em vários bancos ao mesmo tempo.
Os requisitos do time eram: IDs ordenáveis por tempo, para ordenar uma lista de IDs de fotos sem buscar mais informação; IDs idealmente de 64 bits, para índices menores e melhor armazenamento em sistemas como o Redis; e o mínimo possível de novas partes móveis.
| Abordagem | Vantagem apontada | Limite apontado |
|---|---|---|
| Gerar na aplicação | Cada thread gera IDs de forma independente, reduzindo pontos de falha e contenção | Em geral pede mais espaço, 96 bits ou mais, para garantir unicidade |
| Serviço dedicado (Snowflake) | IDs de 64 bits, metade do tamanho de um UUID | Mais complexidade e mais partes móveis, como ZooKeeper e servidores Snowflake |
| Ticket servers no banco | Bancos são bem entendidos e têm fatores de escala previsíveis | Pode virar gargalo de escrita |
Dos caminhos avaliados, o Snowflake do Twitter foi o que chegou mais perto, mas a complexidade de operar um serviço de IDs pesou contra. A escolha foi uma abordagem conceitualmente parecida, trazida para dentro do PostgreSQL.
05 · SHARDS LÓGICOS E O ID
Milhares de shards lógicos sobre poucos servidores físicos
O sistema tem vários milhares de shards lógicos, mapeados em código para um número bem menor de shards físicos. Cada shard lógico é um schema do Postgres, e cada tabela shardada existe dentro de cada schema.
A aplicação guarda em código o mapa de qual shard lógico mora em qual servidor físico.
Cada servidor físico hospeda um conjunto de shards lógicos, e cada shard lógico é um schema do Postgres.
Para crescer, move-se um conjunto de shards lógicos de um banco para outro, sem reagrupar os dados.
Cada ID combina três campos: tempo, shard lógico e uma sequência autoincremental.
| Campo do ID | Tamanho | Para que serve |
|---|---|---|
| Tempo | 41 bits | Milissegundos desde uma época própria, o que dá 41 anos de IDs |
| Shard lógico | 13 bits | Identifica o shard lógico do dado |
| Sequência | 10 bits | Sequência autoincremental, módulo 1024 |
Com essa sequência, o sistema consegue gerar 1024 IDs por shard por milissegundo.
A geração do ID fica dentro de cada tabela de cada shard, usando PL/pgSQL e a função de autoincremento que o Postgres já oferece. O ID volta ao servidor de aplicação pelo RETURNING do INSERT.
06 · FILAS E OBSERVABILIDADE
Trabalho pesado fora da requisição, e olho no sistema
Compartilhar uma foto no Twitter ou no Facebook, ou avisar assinantes em tempo real de uma nova foto, vira uma tarefa enviada ao Gearman, um sistema de fila de tarefas. Fazer isso de forma assíncrona deixa o upload de mídia terminar rápido, enquanto o trabalho pesado roda em segundo plano.
O usuário publica a foto e a aplicação conclui o upload.
A aplicação enfileira as tarefas pesadas, como o compartilhamento em outras redes e o fan-out do feed.
Cerca de 200 workers em Python consomem a fila, divididos entre os serviços para os quais compartilham.
O fan-out do feed também passa pelo Gearman, e por isso publicar é tão responsivo para um usuário novo quanto para um com muitos seguidores.
Com mais de 100 instâncias, acompanhar o sistema inteiro era importante. O time usava Munin para gráficos e alertas, com plugins próprios para métricas de negócio como cadastros por minuto e fotos postadas por segundo, além de Pingdom para monitoramento externo e PagerDuty para notificações e incidentes. Tema: monitoramento e observabilidade.
Perguntas frequentes
O que é Instagram: 14 milhões de usuários com 3 engenheiros (Postgres e IDs por shard)?
Arquitetura real em produção. Pontos centrais: geração de IDs únicos e shards lógicos vs físicos.
O que o design de Instagram: 14 milhões de usuários com 3 engenheiros (Postgres e IDs por shard) cobre?
Ele está organizado nestas seções: Uma startup, poucos engenheiros, muito tráfego, Do DNS round-robin ao balanceador gerenciado, A pilha completa em 2011, Shardar sem trocar de banco, Milhares de shards lógicos sobre poucos servidores físicos e Trabalho pesado fora da requisição, e olho no sistema.
Quanto tempo leva Instagram: 14 milhões de usuários com 3 engenheiros (Postgres e IDs por shard) e qual é o nível?
Leva cerca de 12 minutos para ler e tem nível Júnior.
Agora projete você mesmo
Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.