Arquitetura real · Pleno
Canva: 50 milhões de uploads por dia
Arquitetura real em produção. Pontos centrais: entrega de blobs e vídeo.
Resposta curta
Arquitetura real em produção. Pontos centrais: entrega de blobs e vídeo. Segundo o time de engenharia, usuários enviam 50 milhões de novas mídias por dia, e o Canva é construído com microsserviços: cada serviço expõe uma API, tem persistência isolada e é de uma pequena equipe.
01 · CONTEXTO
O serviço de mídia do Canva
Segundo o time de engenharia, usuários enviam 50 milhões de novas mídias por dia, e o Canva é construído com microsserviços: cada serviço expõe uma API, tem persistência isolada e é de uma pequena equipe.
Sobre o padrão de acesso, o serviço de mídia atende muito mais leituras do que escritas, a maior parte da mídia raramente é modificada depois de criada e as leituras se concentram na mídia criada recentemente, com exceção da biblioteca de fotos e gráficos de acervo.
02 · O LIMITE DO MYSQL
Quando o banco relacional deixou de acompanhar
Por boa parte da história do Canva, a maioria dos microsserviços eram camadas finas sobre MySQL hospedado no AWS RDS. O banco foi escalado primeiro na vertical, com instâncias maiores, e depois na horizontal, com leituras eventualmente consistentes em réplicas de leitura em alguns serviços.
O desenho típico dos microsserviços do Canva é uma camada fina sobre o MySQL hospedado no RDS; o diagrama mostra esse desenho para o serviço de mídia.
Na escala horizontal, alguns serviços passaram a ler de réplicas do MySQL, com leituras eventualmente consistentes.
Limites rígidos da taxa de replicação do MySQL impunham um teto à taxa de escritas nas réplicas de leitura.
A tabela a seguir reúne os limites do MySQL que o time relata.
| Limite | O que o time relata |
|---|---|
| Mudança de esquema | Operações de alteração de esquema nas maiores tabelas de mídia passaram a levar dias; mesmo com o gh-ost chegaram a levar até seis semanas, bloqueando lançamentos. |
| Replicação | Limites rígidos da taxa de replicação do MySQL 5.6 impunham um teto à taxa de escritas nas réplicas de leitura. |
| Volume EBS | O time se aproximava do limite de tamanho de volume EBS do RDS MySQL, de 16 TB na época. |
| Latência de cauda | Cada aumento do volume EBS trazia um pequeno aumento de latência de I/O, o que afetava as latências de cauda das requisições dos usuários. |
| Reinícios | Reinícios de instância e upgrades de versão não eram possíveis sem aceitar algum downtime. |
| Tamanho de arquivo | Com o sistema de arquivos ext3, os arquivos de tabela do MySQL eram limitados a 2 TB. |
03 · GANHAR TEMPO
Estender o MySQL e escolher o destino
Em meados de 2017, com o número de mídias se aproximando de 1 bilhão e crescendo exponencialmente, o time começou a investigar caminhos de migração, com forte preferência por abordagens incrementais.
Para estender a vida do MySQL, o time moveu os metadados de conteúdo, a parte mais modificada do esquema, para uma coluna JSON, desnormalizou algumas tabelas para reduzir contenção de locks e joins e removeu as restrições de chave estrangeira.
Perto do fim da vida da solução MySQL, o time implementou um sharding simples, para evitar o limite de tamanho de arquivo de tabela do ext3 e o teto de vazão de replicação.
A solução foi otimizada para a requisição mais comum, a busca por ID usada ao carregar designs.
Requisições menos comuns, como listar toda a mídia de um usuário, exigiam consultas scatter-gather ineficientes.
Em paralelo, o time investigou e prototipou soluções de longo prazo. Com pouco prazo, preferência por solução gerenciada, experiência prévia com serviços DynamoDB mais simples e um protótipo, escolheu o DynamoDB como alvo provisório. Era preciso também uma estratégia de migração sem impacto para os usuários e com cutover sem downtime.
04 · MIGRAÇÃO AO VIVO
Copiar o histórico sem parar o produto
O time considerou escrever nos dois bancos a cada criação ou atualização, construir e reproduzir um log ordenado de todas as mudanças entre outras opções. A abordagem escolhida daria controle total sobre o mapeamento dos dados, permitiria migrar progressivamente, ao vivo, e tiraria carga do cluster MySQL o quanto antes.
O desenho usa filas de mensagens que apenas identificam a mídia, em vez de carregar o conteúdo da atualização. O diagrama mostra o fluxo em seis passos.
O estado atual de cada mídia é lido do primário do MySQL por um worker na hora de copiá-la.
Mensagens enfileiradas apenas identificam qual mídia foi criada, atualizada ou lida, sem o conteúdo da atualização.
Um worker processa cada mensagem, lê o estado atual no primário do MySQL e atualiza o DynamoDB se necessário, o que permitiu que as mensagens fossem reordenadas ou repetidas arbitrariamente.
Criações e atualizações vão para a fila de alta prioridade e leituras para a de baixa; os workers só leem da de baixa depois de esgotar a de alta.
Um processo de varredura percorre toda a mídia, começando pela criada mais recentemente, e com backpressure só avança enquanto a fila de baixa prioridade está aproximadamente vazia.
Leituras eventualmente consistentes de mídias individuais passam a ser servidas do DynamoDB, com fallback para o MySQL nas poucas mídias ainda não replicadas.
O time implementou um processo de leitura dupla com comparação para testar a replicação. Requisições que não identificam a mídia por ID, como achar toda a mídia de um usuário, só podiam ser atendidas depois que toda a mídia fosse replicada.
05 · CUTOVER
A parte mais arriscada: trocar as escritas
Trocar todas as escritas para o DynamoDB foi a parte mais arriscada do processo. O novo código usava escritas transacionais e condicionais para garantir os mesmos contratos da implementação anterior.
Para reduzir o risco, o time escreveu um runbook do cutover, usando o sistema de flags para poder voltar as leituras ao MySQL em segundos, e o ensaiou conforme a mudança passava pelos ambientes de desenvolvimento e staging. O cutover em produção foi sem problemas, sem downtime nem erros.
06 · RESULTADO E TROCAS
O que se ganhou e o que se perdeu
Os usuários ativos mensais do Canva mais que triplicaram desde a migração. Segundo o time, o DynamoDB tem sido muito estável, com autoscaling conforme o Canva cresce, e custa menos do que os clusters AWS RDS que substituiu.
| Perda ou custo | Situação relatada |
|---|---|
| Mudanças de esquema e backfills | Passaram a exigir escrever e testar com rigor código de migração com parallel scan. |
| Consultas SQL ad hoc | O time perdeu a capacidade de rodar SQL ad hoc numa réplica MySQL e hoje atende essa necessidade com CDC para o data warehouse. |
| Índices secundários globais compostos | São necessários para os padrões de acesso existentes e ainda são criados manualmente, concatenando atributos. |
Olhando para trás, o time diz que, diante do mesmo problema hoje, voltaria a considerar fortemente produtos NewSQL hospedados maduros. O serviço de mídia guarda hoje mais de 25 bilhões de mídias enviadas por usuários, com outras 50 milhões por dia.
Perguntas frequentes
O que é Canva: 50 milhões de uploads por dia?
Arquitetura real em produção. Pontos centrais: entrega de blobs e vídeo.
O que o design de Canva: 50 milhões de uploads por dia cobre?
Ele está organizado nestas seções: O serviço de mídia do Canva, Quando o banco relacional deixou de acompanhar, Estender o MySQL e escolher o destino, Copiar o histórico sem parar o produto, A parte mais arriscada: trocar as escritas e O que se ganhou e o que se perdeu.
Quanto tempo leva Canva: 50 milhões de uploads por dia 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.