Design clássico · Sênior
Comentários ao vivo (Facebook Live)
Projeto de entrevista clássico. Pontos centrais: WebSocket e presença.
Resposta curta
Projeto de entrevista clássico. Pontos centrais: WebSocket e presença. Comentários ao vivo permitem que quem assiste a uma transmissão escreva e leia mensagens enquanto o vídeo acontece. Os requisitos funcionais da fonte são três: postar comentários num vídeo ao vivo, ver os comentários novos enquanto assiste e ver os comentários feitos antes de entrar na transmissão.
01 · CONTEXTO E REQUISITOS
O que os comentários ao vivo precisam fazer
Comentários ao vivo permitem que quem assiste a uma transmissão escreva e leia mensagens enquanto o vídeo acontece. Os requisitos funcionais da fonte são três: postar comentários num vídeo ao vivo, ver os comentários novos enquanto assiste e ver os comentários feitos antes de entrar na transmissão.
Os requisitos não funcionais mandam no desenho: escalar para milhões de vídeos simultâneos e milhares de comentários por segundo em cada vídeo, priorizar disponibilidade sobre consistência (consistência eventual basta) e entregar em quase tempo real, abaixo de 200 ms de ponta a ponta em condições típicas de rede. A fonte explica o alvo: interações abaixo de 200 ms costumam ser percebidas como tempo real.
02 · API E ARMAZENAMENTO
Gravar e paginar o histórico
A criação é um endpoint POST simples. O identificador de quem comenta não vai no corpo da requisição: ele vem do cabeçalho, por token de sessão ou JWT. O serviço de gestão de comentários recebe a mensagem e a grava no banco, que na fonte é o DynamoDB.
Quem comenta envia a mensagem ao serviço de gestão de comentários.
O serviço grava o comentário no banco.
Quem assiste consulta o serviço para ler comentários.
Para o histórico, quem entra num vídeo vê os comentários recentes e rola para cima para ver os mais antigos. Isso pede paginação. A paginação por offset é instável numa fila que anda: se um comentário é inserido ou removido durante a rolagem, o offset fica errado e aparecem duplicados ou lacunas. A paginação por cursor usa um cursor como ponto de partida, e a fonte a considera mais adequada a este caso. Mesmo assim, ela ainda exige uma consulta ao banco a cada nova página.
| Critério | Offset | Cursor |
|---|---|---|
| Custo no banco | O banco precisa contar todas as linhas antes do offset a cada consulta | O banco não precisa contar as linhas anteriores ao cursor, supondo índice no campo do cursor |
| Rolagem com comentários entrando | Instável: inserção ou remoção gera duplicados ou lacunas | Estável: inserção ou remoção não desloca o ponto de partida |
03 · DO POLLING AO PUSH
Como entregar comentários novos
A abordagem mais ingênua é os clientes perguntarem por comentários novos a cada poucos segundos. Ela pressiona o banco e gera muitas requisições desnecessárias. A alternativa são os protocolos de comunicação de modelo push, em que o servidor envia o comentário ao cliente assim que ele é criado, com WebSockets ou Server-Sent Events (SSE).
| Critério | WebSockets | SSE |
|---|---|---|
| Natureza do canal | Canal bidirecional entre cliente e servidor | Conexão persistente sobre HTTP padrão, mais simples de implementar |
| Encaixe neste caso | A razão entre leitura e escrita é desbalanceada, e manter uma conexão bidirecional por viewer tem custo alto | A criação de comentário, infrequente, pode usar requisições HTTP POST comuns |
| Pontos de atenção | Custo de manter a conexão por viewer | Proxies e balanceadores sem suporte a streaming, limite de conexões por domínio no navegador e monitoramento mais difícil |
04 · ESCALANDO PARA MILHÕES
Coordenar vários servidores de mensagens
Com SSE, cada viewer mantém uma conexão aberta. Um servidor aguenta muitas conexões, na casa de 100 mil segundo a fonte, mas CPU, memória e descritores de arquivo viram gargalo antes do limite teórico. Para muitos milhões de viewers é preciso escalar horizontalmente, adicionando servidores.
Isso cria o problema de coordenação: viewers do mesmo vídeo podem estar ligados a servidores diferentes, e o servidor que recebe um comentário não consegue enviá-lo a quem está conectado em outro. A fonte separa o tráfego de escrita do de leitura, criando servidores de mensagens em tempo real que enviam os comentários aos viewers. Como o tráfego de escrita é bem menor, eles escalam de forma independente.
Quem comenta envia o comentário ao serviço, que o grava no banco.
O serviço publica o comentário no canal de pub/sub.
Os servidores de mensagens assinam o canal e recebem o comentário.
Cada servidor envia o comentário por SSE aos viewers ligados a ele, mesmo que sejam de servidores diferentes.
No pub/sub ingênuo, o serviço publica num canal que todos os servidores de mensagens assinam, e cada servidor processa todos os comentários de todos os vídeos, mesmo sem viewers daquele vídeo. A versão particionada usa uma função de hash para distribuir os vídeos num número limitado de canais, e cada servidor assina só os canais de que precisa. Com round robin, um servidor poderia acabar assinando muitos canais; por isso a fonte propõe um balanceador de camada 7 que usa hash consistente pelo identificador do vídeo para levar viewers do mesmo vídeo ao mesmo servidor.
A alternativa é o Dispatcher: um serviço que roteia cada comentário direto aos servidores de mensagens corretos, em vez de os servidores assinarem canais. Ele mantém um mapa dinâmico de quais servidores cuidam de quais vídeos, atualizado por heartbeats e por registro.
| Critério | Pub/sub ingênuo | Pub/sub particionado com co-locação | Dispatcher |
|---|---|---|---|
| Como o comentário chega ao servidor certo | Todos os servidores assinam o mesmo canal | Cada servidor assina só os canais de que precisa | O Dispatcher roteia direto aos servidores corretos |
| Principal limitação | Cada servidor processa todos os comentários de todos os vídeos | Coordenar o balanceamento com as assinaturas do pub/sub | Manter o mapa correto durante mudanças rápidas, como um stream viral |
05 · MEGA-STREAMS
Quando um vídeo explode de audiência
Quando os comentários chegam muito rápido, as metas tradicionais de tempo real, baixa latência e entrega confiável de cada mensagem, importam menos, porque os viewers só precisam ver comentários suficientes para sentir a energia da multidão.
A primeira resposta da fonte é a amostragem: entregar a cada viewer só um subconjunto do fluxo. Como exemplo, ela sugere amostrar 50% dos comentários a 100 por segundo e só 1-2% a 5.000 por segundo. Mesmo assim, ainda restam conexões SSE persistentes com milhões de viewers.
A segunda é trocar o push por um modelo pull que usa a CDN já existente. Um buffer circular guarda os comentários recentes de cada mega-stream, e a cada segundo ou menos um snapshot é gravado no Redis ou na origem da CDN. A CDN distribui o snapshot globalmente, em cache nas bordas, e os clientes o consultam a cada segundo.
O serviço recebe os comentários e mantém um buffer circular com os mais recentes do vídeo.
Periodicamente, um snapshot do buffer vai ao Redis ou à origem da CDN, e a CDN o distribui em cache nas bordas.
Os viewers consultam a CDN pelo snapshot mais recente, em vez de manter uma conexão SSE.
O cliente anima os comentários novos, espaçando-os no intervalo, em vez de despejar todos de uma vez.
O custo é latência: até 1-2 segundos de atraso, em vez de menos de 200 ms. Há duas sutilezas. A leitura do próprio comentário é tratada localmente pelo cliente, com inserção otimista. E a troca de modo é automática acima de 100 mil viewers simultâneos ou 500 comentários por segundo, o que exige histerese no limiar para evitar oscilação entre os modos.
06 · DESCONEXÕES
Não perder comentários na rede móvel
Ignorar as desconexões é a opção mais simples, mas o viewer perde todos os comentários postados durante a queda. O SSE tem um mecanismo próprio de reconexão, o cabeçalho Last-Event-ID: cada comentário enviado leva um ID de evento único, e ao ver o cabeçalho na reconexão o servidor reenvia os comentários perdidos antes de voltar ao fluxo normal.
A fonte acrescenta cuidados: o cliente pode guardar localmente o último ID e pedir a recuperação por HTTP; é preciso definir limites práticos de quanto tempo para trás se reenvia; um cache Redis compartilhado permite que qualquer servidor reenvie comentários recentes caso o viewer reconecte a outro; e o cliente precisa deduplicar por ID quando chegam comentários por SSE durante a recuperação por HTTP.
Perguntas frequentes
O que é Comentários ao vivo (Facebook Live)?
Projeto de entrevista clássico. Pontos centrais: WebSocket e presença.
O que o design de Comentários ao vivo (Facebook Live) cobre?
Ele está organizado nestas seções: O que os comentários ao vivo precisam fazer, Gravar e paginar o histórico, Como entregar comentários novos, Coordenar vários servidores de mensagens, Quando um vídeo explode de audiência e Não perder comentários na rede móvel.
Quanto tempo leva Comentários ao vivo (Facebook Live) e qual é o nível?
Leva cerca de 16 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.