“Projete o YouTube” é uma pergunta querida de system design porque as partes interessantes não estão onde as pessoas esperam. Os servidores web são comuns. O trabalho pesado é levar gigabytes de um celular para o armazenamento com segurança, transformar um upload em uma dúzia de versões que tocam em qualquer dispositivo e conexão, e servir esses bytes de um CDN para que seus próprios servidores quase não os vejam.
Este artigo percorre esse pipeline em ordem: upload, transcodificação, empacotamento e entrega. Ele termina com um diagrama de arquitetura que você pode adaptar e com as decisões que vale escrever nele.
Dois sistemas, não um
Uma plataforma de vídeo são dois sistemas que dividem um banco de dados:
- Ingestão: os criadores fazem upload; a plataforma transcodifica e empacota. A latência é medida em minutos e ninguém se importa.
- Reprodução: os espectadores apertam play; o primeiro quadro precisa aparecer em poucos segundos e não pode travar.
Desenhe os dois como raias separadas. Eles escalam por sinais diferentes (uploads por hora contra espectadores simultâneos) e falham de jeitos diferentes.
Upload: nunca pelos seus servidores de API
Arquivos de vídeo são grandes e conexões móveis caem. Daí saem duas regras:
- Faça upload direto para o armazenamento de objetos. A API de upload autentica o criador, cria um registro do vídeo e devolve URLs pré-assinadas. O cliente envia os bytes direto para o bucket. Sua API nunca faz proxy de gigabytes.
- Torne-o retomável. Use uploads multipart para que uma conexão que caiu repita só a parte que falhou. O upload multipart do Amazon S3, por exemplo, envia as partes de forma independente e as junta quando o cliente conclui o upload.
Quando o upload termina, o evento do armazenamento (ou a chamada de conclusão do cliente) coloca um job de transcodificação em uma fila.
Transcodificação: um upload, uma escada de bitrate adaptativo
Os players trocam a qualidade conforme a banda, então você codifica cada vídeo várias vezes: uma escada de bitrate adaptativo (ABR). Uma escada típica vai de uns 240p ou 360p até 1080p ou 4K, cada degrau com seu próprio bitrate.
A transcodificação pesa na CPU e se paraleliza com muita facilidade:
- Divida a fonte em pedaços de poucos segundos, nos keyframes.
- Codifique cada pedaço e cada versão como um job independente em uma frota de workers, geralmente com FFmpeg.
- Junte os resultados ou mantenha-os como segmentos.
Assim, um filme de duas horas é transcodificado em minutos em vez de horas, e um job que falha repete só um pedaço. Torne os jobs idempotentes identificando-os por vídeo, versão e pedaço, para que uma nova tentativa sobrescreva em vez de duplicar.
Uma escada única para todo conteúdo desperdiça bits: uma apresentação de slides parada precisa de muito menos bitrate que uma partida de futebol. A Netflix popularizou a codificação por título, que escolhe a escada de cada vídeo conforme a complexidade dele. Você pode começar com uma escada fixa e passar para a codificação por título depois.
Empacotamento: HLS, DASH e CMAF
Os players não baixam um arquivo gigante. Eles leem um manifesto que lista versões e segmentos e depois buscam segmentos de poucos segundos por HTTP comum.
| Formato | Definido por | Players típicos |
|---|---|---|
| HLS | RFC 8216 | Dispositivos Apple, a maioria dos navegadores com players como hls.js |
| MPEG-DASH | ISO/IEC 23009-1 | Android, smart TVs, navegadores com dash.js e Shaka Player |
| CMAF | ISO/IEC 23000-19 | Um único conjunto de segmentos MP4 fragmentados para manifestos HLS e DASH |
O CMAF é o motivo de o empacotador importar: com ele, você guarda um único conjunto de segmentos e escreve dois manifestos, em vez de duas cópias de cada vídeo. Segmentos curtos começam mais rápido e trocam de qualidade antes; segmentos mais longos custam menos requisições. A especificação de autoria de HLS da Apple traz recomendações concretas de duração de segmento, keyframes e escadas.
Conteúdo pago acrescenta DRM. O empacotador criptografa os segmentos uma vez com criptografia comum (CENC), e o sistema de DRM de cada plataforma (Widevine, FairPlay, PlayReady) emite licenças para os players por meio de um servidor de licenças.
Entrega: o CDN faz o trabalho
Segmentos são arquivos estáticos, e esse é o ponto: um CDN os guarda em cache perto dos espectadores, e um vídeo popular é servido quase todo dos caches de borda. A origem é o bucket de versões, muitas vezes atrás de um origin shield, para que um cache miss em 50 pontos de borda vire uma única requisição ao armazenamento.
A API de reprodução continua pequena: verifica se o espectador pode assistir ao vídeo, devolve uma URL de manifesto (assinada, se o conteúdo for privado) e registra os eventos de reprodução para o analytics.
Transmissão ao vivo é outro pipeline
O vídeo ao vivo reaproveita o empacotamento e o CDN, mas troca a ingestão. Um encoder envia um fluxo por um protocolo como RTMP ou SRT para um servidor de ingestão, que transcodifica a escada em tempo real e grava segmentos novos a cada poucos segundos. A latência vem da duração do segmento mais o buffer do player; os modos de baixa latência do HLS e do DASH entregam partes de um segmento antes de ele terminar, para chegar mais perto de poucos segundos. Mantenha o ao vivo e o sob demanda como pipelines separados que dividem o CDN, o player e os metadados.
O diagrama de arquitetura
Conteúdo do diagrama
- Creator
- Upload API
- Raw uploads
- Transcode jobs
- Transcode workers
- Packager
- Renditions
- Video metadata
- Viewer
- Playback API
- CDN
- DRM license server
- 1. upload URL
- 2. multipart
- 3. done
- ladder
- segments
- ready
- manifest URL
- cache miss
- license
Como ler:
- Raia de cima, ingestão: o criador pega uma URL de upload na API de upload (1), envia as partes direto para o bucket de uploads brutos (2), e o upload concluído enfileira jobs de transcodificação (3). Os workers codificam a escada, e o empacotador grava os segmentos no bucket de versões e marca o vídeo como pronto no armazenamento de metadados.
- Raia de baixo, reprodução: o espectador pede uma URL de manifesto à API de reprodução e depois recebe os segmentos do CDN. Um cache miss lê do bucket de versões.
- O DRM é pontilhado porque só o conteúdo protegido precisa dele: o player busca uma licença no servidor de licenças.
- O bloco Markdown mostra uma escada de exemplo. Seus números devem vir do seu conteúdo e da banda dos seus espectadores.
O que colocar no diagrama
- Por onde passam os bytes. Desenhe uploads e segmentos indo para o armazenamento e o CDN, não através da sua API.
- A unidade de job. “Um job por versão e pedaço” mostra a quem revisa como funcionam as novas tentativas e o paralelismo.
- Formatos e proteção. Nomeie HLS, DASH ou CMAF, e o DRM se você usa.
- O sinal de pronto. Um vídeo só pode ser reproduzido quando o empacotamento termina; mostre onde esse estado vive.
O mesmo formato de fila e workers aparece no artigo sobre arquitetura orientada a eventos. Do lado da nuvem, o diagrama de arquitetura multirregião na AWS trata de servir a partir de mais de uma região, e o diagrama de arquitetura serverless mostra como eventos de armazenamento podem disparar funções em vez de uma frota de workers.
Monte no Archboard
- Entre com Google ou GitHub e crie um diagrama.
- Adicione dois nós Pessoa do pack Modelo C4 para o criador e o espectador.
- Adicione nós Contêiner para a API de upload, os workers de transcodificação, o empacotador e a API de reprodução, e um Banco de dados para os metadados dos vídeos.
- Adicione dois nós Armazenamento de objetos e um CDN do pack Nuvem, uma Fila do pack Dados para os jobs de transcodificação e um Sistema externo para o servidor de licenças DRM.
- Desenhe a ingestão na raia de cima e a reprodução na de baixo, numere os passos do upload nas arestas e adicione um bloco Markdown do pack Básico com a sua escada.
O exemplo usa 13 nós de diagrama e fica dentro do plano Free.
Perguntas frequentes
O que é uma escada de bitrate adaptativo? O conjunto de versões em que um vídeo é codificado, cada uma com sua resolução e seu bitrate. O player escolhe a melhor que a conexão do espectador aguenta e troca conforme a banda muda.
Devo usar HLS ou DASH? Muitas vezes os dois. Empacote uma vez como segmentos CMAF e escreva um manifesto HLS e um DASH; assim você cobre os dispositivos Apple e os outros players sem guardar duas cópias.
Por que fazer upload direto para o armazenamento de objetos? Arquivos grandes passando pelos seus servidores de API prendem conexões e memória, e uma conexão que cai reinicia o upload. Uploads multipart pré-assinados vão direto para o armazenamento e retomam parte por parte.
Como a transcodificação é paralelizada? Divida a fonte em pedaços nos keyframes e codifique cada pedaço e cada versão como um job separado; depois junte ou empacote os resultados.
Preciso de um CDN para vídeo? Para qualquer público além de um pequeno, sim. Segmentos são arquivos estáticos, e um CDN atende requisições repetidas a partir de caches perto dos espectadores, e não do seu armazenamento.