Arquitetura real · Pleno
Pinterest: sharding da frota MySQL
Arquitetura real em produção. Pontos centrais: geração de IDs únicos.
Resposta curta
Arquitetura real em produção. Pontos centrais: geração de IDs únicos. Este caso vem de um post de engenharia do Pinterest, de agosto de 2015, sobre como a empresa dividiu seus dados entre muitos servidores MySQL. Os números aqui são os da época do post. A abordagem terminou de ser lançada no início de 2012.
01 · CONTEXTO
Um banco único que não acompanhava o produto
Este caso vem de um post de engenharia do Pinterest, de agosto de 2015, sobre como a empresa dividiu seus dados entre muitos servidores MySQL. Os números aqui são os da época do post. A abordagem terminou de ser lançada no início de 2012.
Em 2011 o crescimento foi rápido demais: por volta de setembro, toda a infraestrutura estava acima da capacidade. As tecnologias NoSQL em uso acabaram quebrando de forma catastrófica, e as muitas réplicas MySQL usadas para leitura geravam bugs irritantes, sobretudo com cache. A equipe decidiu redesenhar o armazenamento inteiro.
Na data do post, o grafo de interesses já tinha mais de 50 bilhões de Pins em um bilhão de boards. Esse é o volume que o desenho precisava sustentar.
02 · REQUISITOS
O que o desenho precisava garantir
Os requisitos eram poucos e claros: todo conteúdo dos usuários acessível o tempo todo e atualizações, em geral, de melhor esforço. Com isso a equipe aceitava abrir mão de consistência forte em troca de simplicidade e disponibilidade.
Espalhar os dados por vários bancos tem um custo: não dá para usar joins, chaves estrangeiras ou índices que atravessem bancos. Outra decisão foi evitar mover dados item a item; se for preciso balancear, move-se um nó virtual inteiro. Em produção, só se lê e escreve no master, porque réplicas atrasam e isso causa bugs estranhos.
A escolha de armazenamento foi conservadora: MySQL, por ser maduro, em vez de tecnologias novas de autoescala. Ele já entregava ordenação, seleção de faixas e transações de linha, que era o que o produto usava. É um exemplo prático de seleção de banco de dados guiada por maturidade e pelas consultas necessárias.
03 · A FROTA
Muitos bancos pequenos em poucos servidores
O ponto central é separar shard lógico de servidor físico. O sistema começou com oito servidores EC2, cada um com uma instância MySQL e vários bancos dentro dela. Cada banco é um shard dos dados, e um dado que cai num shard nunca sai dele. Capacidade extra vem de mover shards inteiros para outras máquinas.
Cada servidor tem replicação master-master para um host de backup, e a produção só conversa com o master. Uma tabela de configuração diz quais máquinas atendem quais shards; ela só muda ao mover shards ou trocar um host, e ficava no ZooKeeper.
O serviço consulta a configuração para saber qual servidor atende o shard que ele procura.
Com o servidor descoberto, a leitura ou a escrita vai direto ao master da faixa, e só a ele.
O master replica para o backup, que existe para recuperação e alta disponibilidade, não para leitura em produção.
Se o master morre, um script promove o backup e uma máquina nova é preparada para ocupar o lugar dele.
04 · O ID
Um identificador que já diz onde o dado mora
Para distribuir e depois achar os dados, o Pinterest criou um ID de 64 bits que carrega o shard, o tipo do dado e a posição dele na tabela. É um jeito de embutir a regra de particionamento no próprio identificador, sem consultar um índice central.
| Campo | Bits | Papel no ID |
|---|---|---|
| Shard ID | 16 | Indica em qual shard o objeto está |
| Type ID | 10 | Indica o tipo do objeto, como Pin |
| ID local | 36 | Posição da linha na tabela do shard |
| Reservado | 2 | Mantidos em zero para uso futuro |
O ID é montado com deslocamentos de bits sobre esses campos. No Pin de exemplo do post, a decomposição mostra que ele mora no shard 3429, e a configuração dos shards indica o servidor onde esse banco está.
A aplicação recebe o ID de um Pin e extrai dele o shard, sem consultar nenhum banco.
Com o shard em mãos, consulta a configuração para saber qual servidor atende esse banco.
Conecta ao master certo e lê a linha do banco do shard pelo ID local.
Na escrita o caminho é o inverso. A aplicação escolhe um shard (de preferência o do board onde o Pin entra), insere o JSON na tabela de objetos, o MySQL devolve o ID local autoincrementado e, com shard, tipo e ID local, o sistema compõe o ID completo.
Um efeito colateral: não é preciso um gerador de IDs à parte. O ID local junto de shard e tipo já é um identificador único.
05 · MODELO DE DADOS
Objetos, mapeamentos e junção na aplicação
Há dois tipos de dado. Os objetos, como Pins, usuários, boards e comentários, têm um ID local autoincrementado e um blob de JSON com todos os dados. Para editar, o sistema lê, modifica e grava o JSON dentro de uma transação MySQL. Como campos novos são só campos do JSON, não é preciso nenhum ALTER na tabela.
Os mapeamentos ligam um objeto a outro, como um board aos Pins nele. São unidirecionais, têm uma coluna de sequência que dá a ordenação e seus índices vivem no shard do ID de origem.
Listar os Pins de um board é então uma junção na camada de aplicação: primeiro os IDs no mapeamento, depois os objetos. Isso permite fazer cache do mapeamento separado do objeto; o cache de objetos ficava em um cluster memcache e o de mapeamentos em um cluster redis.
06 · CRESCER E TROCAS
Como a frota cresce e o que se perde
O post descreve três formas de ganhar capacidade. A mais fácil é melhorar as máquinas. A segunda é abrir novas faixas: o ID comporta bem mais shards do que os criados no começo, então bastou subir servidores novos com a faixa seguinte e deixá-los receber os objetos novos. A terceira é mover shards para máquinas novas. Esse é o escalonamento horizontal aplicado a bancos.
Para mover shards, cria-se um novo par master-master que replica a partir do servidor original. Terminada a replicação, altera-se a configuração, e cada servidor passa a atender metade das faixas.
O servidor original está no limite e atende uma faixa grande de shards.
Um servidor novo é criado e começa a replicar a partir do original.
Quando a replicação termina, a configuração é atualizada com a nova divisão.
Cada servidor passa a atender só metade da faixa, com metade da carga.
Há objetos que precisam ser achados por algo que não é ID, como o ID do Facebook, o e-mail ou um endereço IP. Para eles existe o mod shard: a chave passa por hash e módulo do total de shards. Em troca, perdem-se propriedades como a localidade, e é preciso criar todos os shards no início e montar a chave por conta própria.
| Aspecto | Shard por ID | Mod shard |
|---|---|---|
| Como acha o shard | O próprio ID carrega o shard | Hash da chave e módulo do total de shards |
| Chaves aceitas | IDs gerados pelo sistema | Chaves arbitrárias, como e-mail ou IP |
| Localidade | Mantida | Perdida |
| Criação dos shards | Novas faixas podem ser abertas depois | Todos precisam existir desde o início |
Um login chega com um identificador externo que não tem shard embutido.
O serviço aplica hash à chave, acha o servidor do mod shard e lê o ID interno da conta.
Com o ID interno, o caminho volta ao desenho normal: o shard está embutido no ID.
O sistema é de melhor esforço e não dá atomicidade, isolamento ou consistência em todos os casos. Quando um master morre, scripts promovem o backup e preparam uma máquina substituta, e na data do post ainda não havia failover automático. Na migração do banco antigo, a dica era repetir a transferência até o que chega ao sistema novo ser mínimo ou zero. Esse arranjo estava em produção havia 3,5 anos.
Perguntas frequentes
O que é Pinterest: sharding da frota MySQL?
Arquitetura real em produção. Pontos centrais: geração de IDs únicos.
O que o design de Pinterest: sharding da frota MySQL cobre?
Ele está organizado nestas seções: Um banco único que não acompanhava o produto, O que o desenho precisava garantir, Muitos bancos pequenos em poucos servidores, Um identificador que já diz onde o dado mora, Objetos, mapeamentos e junção na aplicação e Como a frota cresce e o que se perde.
Quanto tempo leva Pinterest: sharding da frota MySQL e qual é o nível?
Leva cerca de 15 minutos para ler e tem nível Pleno.
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.