Projeto final: desenhando a arquitetura de um sistema real do zero
1. Definição do Problema e Requisitos
Vamos projetar a arquitetura de uma plataforma de streaming de vídeo educacional — a "EduStream". O objetivo de negócio é oferecer cursos em vídeo com baixa latência, alta disponibilidade e recomendações personalizadas para uma base global de 10 milhões de usuários ativos mensais.
Requisitos funcionais:
- Cadastro e autenticação de usuários (alunos e instrutores)
- Catálogo de cursos com busca e filtros por categoria, duração e popularidade
- Upload e transcodificação de vídeos em múltiplas resoluções (360p, 720p, 1080p)
- Reprodução contínua com adaptação de bitrate (HLS/DASH)
- Sistema de recomendação baseado em histórico e avaliações
Requisitos não funcionais:
- Disponibilidade de 99.99% (menos de 53 minutos de downtime por ano)
- Latência de playback inferior a 2 segundos para conteúdo popular
- Escalabilidade para picos sazonais (ex: início de semestre)
- Segurança: DRM para conteúdo premium, proteção contra ataques DDoS
2. Modelagem de Domínio e Restrições Técnicas
As entidades principais do domínio são: Usuário, Curso, Vídeo, Playlist, Avaliação e Log de Visualização. O relacionamento central é entre Usuário e Vídeo, mediado por inscrições em cursos e histórico de visualização.
Restrições técnicas impostas pelo cenário real:
- Throughput: 500 mil requisições simultâneas de playback durante horário de pico
- Armazenamento: 2 PB de vídeos brutos + 5 PB de vídeos transcodificados (estimativa anual)
- Banda de upload: 100 Gbps para ingestão de novos conteúdos
- Banda de download: 1 Tbps para distribuição via CDN
Trade-offs iniciais:
- Consistência eventual para logs de visualização (sacrificamos consistência imediata por disponibilidade)
- Custo vs. performance: optamos por cache em múltiplas camadas (CDN + Redis) para reduzir latência, mesmo que encareça a infraestrutura
- Sincronia vs. assincronia: upload de vídeo é assíncrono (fila), enquanto consultas ao catálogo são síncronas (REST)
3. Arquitetura em Camadas e Estilo Arquitetural
Adotamos microsserviços com API Gateway e comunicação assíncrona via mensageria. Essa escolha permite escalar componentes individualmente e isolar falhas.
Camadas da arquitetura:
[CDN + SPA (React)] → [API Gateway (Kong)] → [Serviços] → [Bancos + Cache]
Separação de responsabilidades em serviços:
- Serviço de Autenticação: OAuth 2.0 + JWT, gerencia sessões e RBAC
- Serviço de Catálogo: CRUD de cursos e vídeos, busca elástica (Elasticsearch)
- Serviço de Upload: Recebe vídeos, valida metadados e publica eventos na fila
- Serviço de Transcodificação: Consome eventos, processa vídeos em lote
- Serviço de Recomendação: Motor baseado em eventos de visualização e cache distribuído
- Serviço de Playback: Entrega URLs assinadas para CDN, gerencia sessões de streaming
4. Componentes Críticos e Comunicação entre Serviços
Serviço de Transcodificação: pipeline com fila
O upload de um vídeo dispara um evento para o RabbitMQ. O serviço de transcodificação consome esse evento, baixa o vídeo bruto do S3, processa em múltiplas resoluções usando FFmpeg e salva os resultados de volta no S3.
# Exemplo de evento publicado no RabbitMQ
{
"event_type": "video.uploaded",
"video_id": "v_12345",
"bucket": "edustream-raw",
"object_key": "courses/matematica/aula01.mp4",
"resolutions": ["360p", "720p", "1080p"],
"timestamp": "2025-03-20T14:30:00Z"
}
Serviço de Recomendação: motor baseado em eventos
Cada visualização gera um evento Kafka. O serviço de recomendação consome esses eventos, atualiza embeddings de usuários no Redis e retorna recomendações via gRPC.
Comunicação síncrona vs. assíncrona:
- Síncrona (REST/gRPC): consultas ao catálogo, busca de cursos, validação de autenticação
- Assíncrona (eventos): upload de vídeo, transcodificação, notificações, atualização de recomendações
A escolha por assincronia no upload é justificada pela necessidade de processamento pesado (transcodificação pode levar minutos), que bloquearia a requisição do usuário se fosse síncrona.
5. Estratégias de Dados e Armazenamento
Banco relacional (PostgreSQL): dados estruturados e transacionais — usuários, cursos, inscrições, avaliações. Usamos replicação primária-secundária para leitura escalável.
-- Esquema simplificado do banco relacional
CREATE TABLE users (
id UUID PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255) UNIQUE,
role ENUM('student', 'instructor', 'admin'),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE courses (
id UUID PRIMARY KEY,
title VARCHAR(200),
instructor_id UUID REFERENCES users(id),
category VARCHAR(50),
created_at TIMESTAMP DEFAULT NOW()
);
Banco NoSQL (Cassandra): logs de visualização e histórico — dados de alta cardinalidade e escrita intensa. Particionamos por user_id e ordenamos por timestamp.
Armazenamento de objetos (S3): vídeos brutos (bucket edustream-raw) e transcodificados (bucket edustream-transcoded). Usamos lifecycle policies para mover vídeos antigos para Glacier.
Cache: CDN (CloudFront) para conteúdo popular com TTL de 24 horas. Cache de aplicação (Redis) para sessões de usuário, recomendações temporárias e resultados de busca frequentes.
6. Resiliência, Escalabilidade e Observabilidade
Estratégias de resiliência:
- Circuit breaker no serviço de recomendação: se o Redis falhar, retorna lista padrão de cursos populares
- Retry com backoff exponencial para chamadas ao serviço de transcodificação (máx. 3 tentativas)
- Fallback: se o CDN não tiver o vídeo, o serviço de playback redireciona para o S3 diretamente
Escalabilidade horizontal:
- API Gateway com auto-scaling baseado em CPU (mín. 3 instâncias, máx. 20)
- Serviço de transcodificação escala com base no tamanho da fila (Kubernetes HPA)
- Banco PostgreSQL usa read replicas para consultas; escritas vão para o primário
Observabilidade:
- Logging centralizado: ELK Stack (Elasticsearch, Logstash, Kibana)
- Métricas: Prometheus coleta métricas de cada serviço (latência, taxa de erro, throughput)
- Tracing distribuído: Jaeger para rastrear requisições completas (ex: do upload ao playback)
7. Segurança e Governança da Arquitetura
Autenticação e autorização: OAuth 2.0 com fluxo Authorization Code + PKCE. Tokens JWT com claims de role (student, instructor, admin). RBAC por serviço: apenas instrutores podem fazer upload; apenas admins podem deletar cursos.
Proteção de conteúdo:
- DRM (Widevine/PlayReady) para vídeos premium
- URLs assinadas no CDN com expiração de 1 hora
- Rate limiting no API Gateway: 100 req/min por usuário para endpoints de busca
Governança:
- ADRs (Architecture Decision Records) documentados no repositório de arquitetura
- Revisões trimestrais de arquitetura com testes de caos (Netflix Chaos Monkey) para validar resiliência
- Política de versionamento de APIs (semver) e depreciação com 6 meses de aviso
8. Exemplo Prático: Fluxo Completo de uma Requisição
Cenário 1: Upload de vídeo por um instrutor
- Instrutor envia vídeo via SPA → API Gateway valida JWT e roteia para serviço de upload
- Serviço de upload salva metadados no PostgreSQL (status: "processing") e faz upload do arquivo para S3 (bucket raw)
- Publica evento
video.uploadedno RabbitMQ e retorna 202 Accepted para o cliente - Serviço de transcodificação consome o evento, baixa o vídeo do S3, processa em 3 resoluções e salva no bucket transcoded
- Atualiza status no PostgreSQL para "ready" e publica evento
video.ready - Serviço de notificação (via WebSocket) avisa o instrutor que o vídeo está disponível
Cenário 2: Usuário assiste a um vídeo
- Usuário clica em "Assistir" → SPA requisita URL assinada ao serviço de playback via API Gateway
- Serviço de playback verifica se o usuário tem acesso ao curso (consulta PostgreSQL) e se o vídeo está em cache no CDN
- Se cache hit: retorna URL do CDN diretamente (latência < 100ms)
- Se cache miss: gera URL assinada para o S3 e retorna; CDN fará cache para próximas requisições
- Paralelamente, o serviço de playback publica evento
video.watchedno Kafka - Serviço de recomendação consome o evento e atualiza o perfil do usuário no Redis
Decisões de design justificadas:
- Fila (RabbitMQ) em vez de chamada síncrona no upload: transcodificação leva de 30 segundos a 5 minutos. Se fosse síncrona, o usuário ficaria esperando. Com fila, o upload termina em segundos e o processamento ocorre em background.
- Cache em duas camadas (CDN + Redis): CDN reduz latência de entrega de vídeo para usuários globais; Redis acelera recomendações e sessões sem sobrecarregar o banco relacional.
- Cassandra para logs: logs de visualização geram milhões de escritas por minuto. PostgreSQL não suportaria essa carga sem custo proibitivo. Cassandra oferece escrita rápida e escalabilidade linear.
Referências
- AWS Well-Architected Framework - Streaming Media — Guia oficial da AWS para arquitetura de plataformas de streaming, cobrindo CDN, transcodificação e escalabilidade.
- Netflix Tech Blog - Microservices Architecture — Artigo técnico da Netflix sobre como eles estruturam microsserviços para streaming em escala global.
- RabbitMQ Documentation - Event-Driven Architecture — Documentação oficial do RabbitMQ com exemplos práticos de filas e mensageria assíncrona.
- Cassandra Architecture - DataStax — Visão detalhada da arquitetura do Cassandra para alta disponibilidade e escrita intensa.
- OAuth 2.0 Authorization Framework - RFC 6749 — Especificação técnica do OAuth 2.0, base para autenticação e autorização em sistemas distribuídos.
- Prometheus Monitoring - Best Practices — Guia de boas práticas para monitoramento de microsserviços com Prometheus e Grafana.