Arquitetura real · Sênior
Mercado Envios: do MySQL único para a América Latina a células
É o melhor caso BR para senior. Como rotear sem chave de célula na API: broadcast para entidades legadas (404 de todas as células = "não existe") e faixas de ID por célula para entidades novas. p95/p99 caíram cerca de 70%.
Resposta curta
É o melhor caso BR para senior. Como rotear sem chave de célula na API: broadcast para entidades legadas (404 de todas as células = "não existe") e faixas de ID por célula para entidades novas. p95/p99 caíram cerca de 70%.
01 · CONTEXTO
Um banco só para a região inteira
O sistema de estoque do Mercado Envíos, do Mercado Libre, rodava sobre o que a empresa descreve como a segunda maior instância MySQL da casa. Toda entrada, saída, reserva e movimentação logística dependia de um único banco que não conseguia mais escalar.
A arquitetura inicial era simples: vários serviços de estoque ligados a um único cluster MySQL. Esse cluster cuidava da disponibilidade de estoque por centro de fulfillment, das reservas para envios de fulfillment e das movimentações logísticas entre armazéns, vendedores e destinos.
Os clientes da API chamam os serviços de estoque.
Todos os serviços de estoque convergem para um único cluster MySQL.
Com esse desenho, uma única falha podia afetar operações em vários países da região.
Segundo o post, a latência de operações críticas vinha subindo, e a pergunta passou a ser o que fazer quando escalar na vertical deixa de ser opção.
02 · POR QUE CÉLULAS
Sem flavor maior e sem microsserviços por reflexo
Por anos a escala vertical resolveu os problemas; no fim, não havia mais flavors maiores disponíveis e depender de uma única instância MySQL virou risco sistêmico.
Em vez de dividir tudo em microsserviços, a equipe pesou que multiplicar saltos de rede ou pontos de falha tornaria mais difíceis exigências do domínio como latência extremamente baixa mesmo sob pico e forte consistência de estoque. Por isso mantiveram um monólito intencional no núcleo do sistema.
| Antes | Depois | |
|---|---|---|
| Banco | Vários serviços ligados a um único cluster MySQL | Cada célula com banco próprio |
| Alcance de uma falha | Uma única falha podia afetar operações em vários países | Um problema em uma célula fica nessa célula |
| Como cresce | Escalar um banco gigante | Escalar só as células que precisam |
03 · A ARQUITETURA
Células por grupo de países, escrita separada de leitura
A arquitetura em células é conceitualmente parecida com as divisórias estanques de um navio: cada célula opera de forma autônoma, com computação, banco e tráfego próprios. Se uma célula falha, as demais continuam atendendo requisições. Esse isolamento reduz o raio de impacto.
O modelo introduziu duas camadas de segregação. Na primeira, os países foram agrupados em três células. Na segunda, os fluxos foram divididos: escritas estritamente consistentes e críticas para o negócio de um lado, leituras mais flexíveis, apoiadas em réplicas e cache, de outro.
Os clientes chegam a uma camada de tráfego que fica na frente das células.
A camada de tráfego é ligada ao serviço de cada célula.
Cada célula tem serviço e banco próprios.
Se uma célula falhar, as demais continuam atendendo requisições.
Implementar células é também um desafio operacional. A Fury, plataforma interna de desenvolvimento do Mercado Libre, permitiu criar serviços e bancos de cada célula com padrões consistentes e operar pipelines de deploy independentes por célula.
04 · ROTEAMENTO
Quando a API não tem chave de célula
Ao desenhar o roteamento, a equipe viu que várias APIs não tinham uma chave natural que identificasse a qual célula a entidade pertencia. Criar um atributo novo quebraria a compatibilidade com clientes existentes e exigiria coordenar mudanças com dezenas de equipes e serviços.
A saída foi usar duas estratégias. Para entidades legadas, um fallback de roteamento retrocompatível; para dados novos, uma estratégia determinística de IDs.
O cliente faz a mesma requisição de sempre, sem mudanças.
A camada de tráfego encaminha a requisição a todas as células.
A célula que guarda a entidade responde.
Se todas as células devolvem 404, o recurso realmente não existe.
05 · IDS COMO CHAVE
Faixas de ID por célula
O broadcast resolveu o problema dos registros legados, mas as entidades novas pediam roteamento determinístico. Os IDs atrapalhavam: eram públicos e parte de contratos de API antigos, eram sequenciais e gerados por uma única instância MySQL, e não tinham significado embutido. Isso trazia o risco de colisão de IDs entre células se dois primários gerassem números sobrepostos.
A solução foi dar a cada célula uma faixa exclusiva de IDs. Uma entidade nova criada numa célula recebe um ID que nunca colide com o de outra célula, os IDs mantêm o formato original e o próprio ID passa a ser a chave de roteamento.
| Entidades legadas | Entidades novas | |
|---|---|---|
| Como a célula é encontrada | A camada de tráfego encaminha a requisição a todas as células | O próprio ID passa a ser a chave de roteamento |
| Efeito para o cliente | O cliente faz a mesma requisição de sempre | Os IDs mantêm o formato original |
| Ponto de atenção | O broadcast de requisições adiciona overhead | Faixas exclusivas evitam colisão entre células |
06 · MIGRAÇÃO E RESULTADO
Migrar dezenas de terabytes sem parar a logística
A equipe migrou dezenas de terabytes para três células independentes. A leitura continuou sem interrupção e as escritas foram pausadas só numa janela breve e controlada. O roteiro de cada janela era copiar o banco para a célula de destino, pausar as escritas por pouco tempo e manter as leituras no banco original.
Como a maioria dos fluxos é assíncrona, a pausa curta de escrita teve impacto mínimo nos clientes finais. Depois que a célula recebia seus dados, ela entrava no ar aos poucos: primeiro ligaram as leituras e validaram fluxos críticos, depois liberaram as escritas, protegidas contra contaminação entre células. Após a validação, o tráfego de leitura foi deslocado para a nova célula sem indisponibilidade.
As escritas vão ao primário da célula, onde precisam ser estritamente consistentes.
As leituras, mais flexíveis, são apoiadas em réplicas e cache.
O serviço SQL totalmente gerenciado trouxe replicação com garantias de consistência abaixo de 100 ms.
Com as réplicas atendendo leitura, as leituras no primário foram eliminadas.
Um ano após a migração, a latência p95/p99 havia caído cerca de 70%, a degradação recorrente causada pelas janelas de backup foi eliminada e a equipe passou de escalar um banco gigante a escalar só as células que precisam.
Perguntas frequentes
O que é Mercado Envios: do MySQL único para a América Latina a células?
É o melhor caso BR para senior. Como rotear sem chave de célula na API: broadcast para entidades legadas (404 de todas as células = "não existe") e faixas de ID por célula para entidades novas. p95/p99 caíram cerca de 70%.
O que o design de Mercado Envios: do MySQL único para a América Latina a células cobre?
Ele está organizado nestas seções: Um banco só para a região inteira, Sem flavor maior e sem microsserviços por reflexo, Células por grupo de países, escrita separada de leitura, Quando a API não tem chave de célula, Faixas de ID por célula e Migrar dezenas de terabytes sem parar a logística.
Quanto tempo leva Mercado Envios: do MySQL único para a América Latina a células e qual é o nível?
Leva cerca de 17 minutos para ler e tem nível Sê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.