Projetando Sistemas de Recomendação em Escala: Guia Completo de System Design
Resumo em português: Um guia de nível produção para construir plataformas de recomendação em escala de internet, cobrindo geração de candidatos, retrieval, ranking, feature store, inferência online, loops de feedback em tempo real, experimentação, confiabilidade e trade-offs de entrevista.
Publicado: Fevereiro 2026
Tempo de leitura: 100 minutos
Palavras-chave: #SystemDesign #RecommendationSystem #Ranking #Retrieval #FeatureStore #MLSistemas #SistemasDistribuídos #Escalabilidade #EntrevistaTécnica
Um usuário abre o app por 15 segundos enquanto espera um café. Nesse intervalo, o sistema precisa decidir:
- quais itens aparecem no topo,
- quais criadores entram no feed,
- quais produtos vão para a vitrine,
- quanto de exploração vale a pena antes de prejudicar a experiência.
Um erro isolado quase não muda nada.
Um milhão de erros por minuto muda retenção, receita, distribuição de exposição e confiança no produto.
Esse é o ponto central: recomendação não é só "treinar um modelo". É um problema de arquitetura distribuída com componentes de ML, contratos de latência e operação em produção.
Em entrevistas, respostas medianas param em "vamos usar collaborative filtering". Respostas senior mostram pipeline completo, limites de latência por etapa, consistência de features, degradação controlada e governança de modelo.
Este guia segue esse nível.
Sumário
- Análise de Requisitos
- Cálculos de Envelope
- Arquitetura de Alto Nível
- Design de API
- Modelagem de Dados
- Pipeline de Geração de Candidatos (Core 1)
- Retrieval e Infra de ANN (Core 2)
- Ranking e Re-Ranking (Core 3)
- Arquitetura de Feature Store (Core 4)
- Ingestão de Sinais em Tempo Real (Core 5)
- Exploração, Diversidade e Restrições (Core 6)
- Feedback Loops e Governança de Modelos (Core 7)
- Confiabilidade de Serving e Fallbacks (Core 8)
- Treinamento, Validação e Deploy
- Experimentação e Medição Causal
- Caching e Sharding
- Multi-Região e Disaster Recovery
- Segurança, Privacidade e IA Responsável
- Observabilidade e SLOs
- Dicas para Entrevista
- Anti-Patterns para Evitar
- Conclusão
- Referências
- Referência Rápida
Análise de Requisitos
A primeira decisão é delimitar o problema. "Sistema de recomendação" pode significar feed social, ecommerce, vídeo curto, trilhas de aprendizado, ranking de vagas, anúncios ou busca personalizada.
Sem escopo, tudo vira abstrato e a arquitetura perde precisão.
Requisitos Funcionais
- Gerar candidatos personalizados para cada usuário.
- Ranquear candidatos por utilidade prevista, respeitando restrições.
- Responder em latência baixa e previsível.
- Atualizar recomendações conforme novas interações.
- Tratar cold-start de usuários e itens.
- Ter fallback quando componentes de ML falharem.
- Expor metadados mínimos de explicação quando necessário.
- Suportar A/B tests, canary e rollback seguro.
Requisitos Não-Funcionais
| Requisito | Meta | Motivo |
|---|---|---|
| Latência API recomendação | < 120ms p99 | UX fluida e retenção |
| Disponibilidade | 99,99% | Superfícies centrais dependem disso |
| Freshness de sinais | segundos a poucos minutos | personalização desatualizada perde valor |
| Escala | milhões de req/s em picos | plataformas globais |
| Consistência | eventual para features, forte para configuração | equilíbrio entre custo e controle |
| Degradação | sem tela vazia em falhas de ML | resiliência de produto |
Métricas de Sucesso
Você não otimiza só CTR. Um sistema maduro monitora cesta de métricas:
- CTR
- dwell/watch time
- conversão
- profundidade de sessão
- retenção D1/D7/D30
- distribuição de exposição por creator/seller
- métrica de qualidade e diversidade
- latência e erro de serving
Perguntas de Clarificação (Entrevista)
- Qual superfície vamos otimizar primeiro (home feed, discover, produto)?
- Qual o budget de latência por request?
- Quão rápido um clique precisa impactar ranking?
- Existe requisito formal de fairness/diversidade?
- Qual é o tamanho do catálogo ativo?
Premissas para Este Guia
- Superfícies tipo feed e discover.
- p99 fim-a-fim <= 120ms.
- Personalização quase em tempo real.
- Experimentação obrigatória.
- Fallback obrigatório.
Cálculos de Envelope
Aqui o objetivo não é acertar número exato. É mostrar maturidade para guiar escolhas de arquitetura.
Hipóteses de Escala
DAU: 400 milhões
Requests de recomendação/dia: 120 bilhões
Itens retornados por request: 20
Pool inicial de candidatos por request: 2.000
Catálogo ativo: 1,5 bilhão de itens
Eventos de interação/dia: 2,8 trilhões
Pico: 5x média
QPS de Serving
QPS medio = 120.000.000.000 / 86.400 ~= 1.388.889
QPS de pico (5x) ~= 6.944.445
Custo de Scoring Sem Multi-Estágio
Se você tentar pontuar 2.000 candidatos com modelo pesado em todo request:
6,94M req/s * 2.000 candidatos ~= 13,9 bilhões de scores/s
Isso é caro demais e tende a explodir latência/custo.
Por isso o padrão industrial é:
- retrieval barato em lote grande,
- ranking pesado em lote menor,
- reranking final no top curto.
Ingestão de Eventos
2,8 trilhões/dia ~= 32,4M eventos/s (média)
Pico (3x) ~= 97M eventos/s
Exige streaming particionado, schema governance e controles de qualidade.
Armazenamento (direcional)
Assumindo 200 bytes por evento comprimido:
2,8T * 200B ~= 560TB/dia lógico
Conclusão: retenção precisa de políticas por camada (hot, warm, cold) e sampling inteligente.
Insight Principal
Os gargalos reais são:
- eficiência retrieval + ranking,
- freshness de features,
- paridade treino-serving,
- proteção contra regressão de qualidade.
Arquitetura de Alto Nível
flowchart TB
subgraph Clientes
APP["Mobile/Web"]
end
subgraph Serving
API["Recommendation API"]
ORQ["Orchestrator"]
RET["Retrieval Service"]
RANK["Ranking Service"]
RER["Re-ranker + Constraints"]
FALL["Fallback Service"]
end
subgraph Online Data
OFS["Online Feature Store"]
UEMB["User Embedding Store"]
IANN["ANN Item Index"]
PROF["Profile Store"]
CACHE[("Redis")]
end
subgraph Data & Training
EVT["Event Collector"]
BUS[("Kafka/PubSub")]
FPIPE["Feature Pipelines"]
OFFS["Offline Feature Store"]
TRAIN["Training Pipeline"]
REG["Model Registry"]
DEP["Model Deploy"]
DWH[("Warehouse")]
end
APP --> API --> ORQ
ORQ --> RET --> IANN
ORQ --> OFS
ORQ --> RANK
RANK --> RER
RER --> ORQ
ORQ --> FALL
ORQ --> CACHE
EVT --> BUS
BUS --> FPIPE --> OFS
FPIPE --> OFFS
OFFS --> TRAIN --> REG --> DEP --> RANK
BUS --> DWH
TRAIN --> UEMB
TRAIN --> IANN
Princípios Arquiteturais
- Multi-estágio para controlar custo de inferência.
- Separação clara entre plano online e plano offline.
- Contratos versionados de features e modelos.
- Fallback como funcionalidade de produto, não gambiarra.
- Observabilidade de sistema e de modelo lado a lado.
Design de API
API boa para recomendação precisa carregar contexto e restrições, sem estourar payload.
Endpoint Principal
POST /v1/recommendations
Request:
{
"request_id": "req_2381",
"user_id": "u_991",
"surface": "HOME_FEED",
"context": {
"device": "ios",
"locale": "pt-BR",
"timezone": "America/Sao_Paulo",
"network_type": "wifi"
},
"session": {
"session_id": "s_882",
"entry_point": "app_open"
},
"constraints": {
"max_items": 20,
"allow_sensitive": false,
"diversity_level": "medium"
},
"debug": false
}
Response:
{
"request_id": "req_2381",
"model_version": "ranker_v278",
"items": [
{
"item_id": "i_101",
"score": 0.9281,
"reason_codes": ["similar_interest", "fresh_content"],
"rank": 1
}
],
"served_at": "2026-02-22T23:40:10Z",
"fallback_used": false,
"trace_id": "tr_5502"
}
Endpoint de Eventos
POST /v1/recommendations/events
{
"event_id": "evt_901",
"request_id": "req_2381",
"user_id": "u_991",
"item_id": "i_101",
"event_type": "CLICK",
"position": 1,
"surface": "HOME_FEED",
"event_ts": "2026-02-22T23:40:21Z"
}
Dedupe de Evento
dedupe_key = event_id
ou
dedupe_key = (request_id, user_id, item_id, event_type, bucket_ts)
Sem dedupe, você duplica feedback positivo/negativo e distorce treino.
Modelagem de Dados
Recomendação mistura formatos diferentes:
- eventos append-only,
- features online mutáveis,
- snapshots históricos para treino,
- configurações de experimento e rollout.
Objetos Principais
- UserFeatures
- ItemFeatures
- InteractionEvent
- ModelArtifact
- DeploymentConfig
- ExperimentAssignment
Exemplo de Feature de Usuário
{
"user_id": "u_991",
"embedding": [0.12, -0.44, 0.89],
"recent_topics": ["ml", "system-design", "cloud"],
"activity_1d": {
"views": 52,
"clicks": 13,
"likes": 2
},
"quality_signals": {
"session_depth_avg_7d": 8.2,
"negative_feedback_ratio": 0.07
},
"updated_at": "2026-02-22T23:31:01Z"
}
Exemplo de Feature de Item
{
"item_id": "i_101",
"creator_id": "c_55",
"embedding": [0.02, 0.88, -0.31],
"tags": ["distributed-systems", "architecture"],
"freshness_hours": 3,
"quality_score": 0.82,
"policy": {
"eligible_surfaces": ["HOME_FEED", "DISCOVER"],
"sensitivity_level": "LOW"
},
"updated_at": "2026-02-22T23:29:44Z"
}
Tabela de Assignment de Experimento
CREATE TABLE experiment_assignments (
experiment_id VARCHAR(64) NOT NULL,
user_id BIGINT NOT NULL,
variant VARCHAR(32) NOT NULL,
assigned_at TIMESTAMP NOT NULL,
PRIMARY KEY (experiment_id, user_id)
);
Diagrama ER Simplificado
erDiagram
USER ||--o{ INTERACTION_EVENT : emits
ITEM ||--o{ INTERACTION_EVENT : receives
USER ||--|| USER_FEATURES : has
ITEM ||--|| ITEM_FEATURES : has
MODEL ||--o{ MODEL_DEPLOYMENT : deployed_as
EXPERIMENT ||--o{ EXPERIMENT_ASSIGNMENT : assigns
USER ||--o{ EXPERIMENT_ASSIGNMENT : belongs_to
Pipeline de Geração de Candidatos (Core 1)
Você nunca rankeia catálogo inteiro. Primeiro você reduz espaço de busca.
Fontes de Candidatos
- Collaborative filtering.
- Similaridade por embedding.
- Popularidade/trending por contexto.
- Afinidade social (follows, grafo).
- Candidatos estratégicos de negócio (com limites).
Blend de Candidatos
final_candidates = unique(
topK(collab, 500)
U topK(embedding, 600)
U topK(trending, 200)
U topK(business, 100)
)
Sequência de Candidatos
sequenceDiagram
participant O as Orchestrator
participant CF as CF Generator
participant ANN as Embedding Retriever
participant POP as Trending Generator
participant BIZ as Business Generator
participant M as Candidate Merger
O->>CF: get candidates(user)
O->>ANN: get nearest neighbors
O->>POP: get contextual popular
O->>BIZ: get business candidates
CF-->>M: set A
ANN-->>M: set B
POP-->>M: set C
BIZ-->>M: set D
M-->>O: merged dedup candidates
Cold-Start
Usuário novo
- popularidade por contexto (cidade/idioma/horário),
- sinal de onboarding,
- exploração maior no início.
Item novo
- embeddings por conteúdo/metadado,
- exploração controlada,
- limites por confiança de qualidade.
Retrieval e Infra de ANN (Core 2)
ANN costuma ser a etapa mais sensível em latência e infra.
Requisitos do Index
- Alta recall com latência baixa.
- Atualizações incrementais.
- Particionamento por vertical/locale quando necessário.
- Escalabilidade para bilhões de vetores.
Caminho de Retrieval
- Buscar embedding do usuário.
- Consultar ANN para top-N próximos.
- Aplicar filtros grossos (policy, idioma, elegibilidade).
- Retornar ids para o ranker.
Diagrama de Retrieval
flowchart LR
U["User Embedding"] --> A["ANN Cluster"]
A --> N["Nearest Candidates"]
N --> F["Coarse Filters"]
F --> O["Output Candidates"]
Estratégias de Refresh do Index
| Estratégia | Vantagem | Desvantagem | Uso |
|---|---|---|---|
| rebuild diário | simples | staleness alta | superfícies menos sensíveis |
| incremental horário | bom equilíbrio | mais complexidade | padrão |
| quase realtime | freshness máxima | custo alto | superfícies premium |
Budget de Latência (exemplo)
Budget total: 120ms
- API + orchestration: 15ms
- retrieval: 30ms
- fetch de features: 25ms
- ranking + reranking: 35ms
- serialização/rede: 15ms
Ranking e Re-Ranking (Core 3)
Essa é a etapa de maior impacto na qualidade percebida.
Padrão Multi-Estágio
- Pre-ranker leve em ~2.000 candidatos.
- Ranker mais pesado em ~300.
- Re-ranker em ~50 para restrições finais.
Features Comuns
- Usuário: afinidade, recência, profundidade de sessão.
- Item: qualidade, freshness, risco de policy.
- Contexto: dispositivo, rede, horário.
- Cruzadas: histórico usuário-item, similaridade semântica.
Input do Ranking Service
{
"user_id": "u_991",
"surface": "HOME_FEED",
"candidate_ids": ["i_101", "i_102"],
"feature_refs": {
"online_snapshot_id": "ofs_788"
},
"model_version": "ranker_v278"
}
Re-Ranking com Restrições
flowchart TB
I["Ranked List"] --> D["Diversity Layer"]
D --> P["Policy Filter"]
P --> B["Business Constraints"]
B --> F["Final List"]
Restrições Típicas
- Cota máxima por creator.
- Diversidade mínima por tópico/fonte.
- Bloqueios de policy.
- Posições reservadas com limite estrito.
- Quota de freshness.
Erro Comum
Otimizar CTR imediato sem guardrails de longo prazo piora ecossistema e retenção.
Arquitetura de Feature Store (Core 4)
A maior causa de regressão silenciosa em ML de recomendação é mismatch treino-serving.
Objetivos
- Baixa latência online.
- Histórico offline confiável.
- Definições únicas e versionadas de features.
- Point-in-time correctness no treino.
Fluxo de Features
flowchart LR
E["Raw Events"] --> T["Transforms"]
T --> OFF["Offline FS"]
T --> ON["Online FS"]
OFF --> TR["Training"]
ON --> INF["Online Inference"]
Exemplo de Definição Versionada
feature_name: user_click_rate_7d
entity: user_id
logic: clicks_7d / impressions_7d
source: interaction_events
update_mode: streaming
online_ttl: 10m
offline_backfill: daily
version: v91
Point-in-Time (regra)
No treino, joins só podem usar dados disponíveis até o timestamp do label.
Qualquer "vazamento de futuro" infla métrica offline e quebra em produção.
Boas Práticas
- Registry central de features.
- Tests de consistência online/offline.
- Monitoramento de null-rate e drift por feature.
- Rollback rápido de feature version.
Ingestão de Sinais em Tempo Real (Core 5)
Sem eventos frescos, personalização degrada rápido.
Eventos Mais Importantes
- Impression
- Click
- Like/Favorite
- Share
- Add-to-cart
- Purchase
- Hide/Not interested
- Session end
Pipeline de Eventos
flowchart TB
SDK["Client SDK"] --> COL["Event Collector"]
COL --> BUS["Kafka/PubSub"]
BUS --> VAL["Schema Validators"]
VAL --> RT["Realtime Feature Jobs"]
RT --> OFS["Online FS"]
BUS --> DWH["Warehouse"]
Controles de Qualidade de Dados
- Schema registry e compatibilidade.
- Dedupe de eventos.
- Tratamento de clock skew.
- Watermarks para atraso.
- Filtragem de bots e fraude.
Freshness SLA
Sinais de alta relevância devem impactar serving em segundos, não horas.
Exploração, Diversidade e Restrições (Core 6)
Sem exploração, o sistema converge para repetição e perde descoberta.
Estratégias de Exploração
- Epsilon-greedy por segmento.
- Thompson sampling.
- Contextual bandits.
- Buckets de exploração controlada por superfície.
Restrições de Diversidade
- Diversidade de fonte.
- Diversidade de tópico.
- Controle de repetição por creator.
- Quota mínima de itens novos.
Objetivo com Restrições
max expected_utility(items)
subject to:
- policy_eligible(item)
- creator_repeat_cap <= threshold
- min_diversity_score >= threshold
- sponsored_slots <= limit
Trade-off
| Política | Pro | Contra |
|---|---|---|
| sem exploração | estabilidade de curto prazo | estagnação e viés de exposição |
| exploração agressiva | aprendizado rápido | queda de métrica imediata |
| exploração controlada | equilíbrio | exige disciplina de experimento |
Dica Prática
Comece simples:
- ranker determinístico,
- exploração pequena e observável,
- guardrails fortes,
- evolução gradual.
Feedback Loops e Governança de Modelos (Core 7)
Seu modelo altera o próprio dado que vai treinar o próximo modelo.
Riscos Clássicos
- Rich-get-richer de creators já grandes.
- Redução extrema de cobertura de catálogo.
- Bolhas de tópicos.
- Viés histórico auto-reforçado.
Controles de Governança
- Monitorar distribuição de exposição.
- Definir limites de concentração.
- Medir coortes sensíveis separadamente.
- Incluir objetivos de longo prazo.
- Manter rollback rápido por degradação.
Metadados de Registro de Modelo
{
"model_name": "ranker_v278",
"training_data_window": "2026-01-20..2026-02-18",
"feature_set_version": "fs_v91",
"offline_metrics": {
"auc": 0.812,
"ndcg_20": 0.442,
"coverage_1k": 0.71
},
"guardrails": {
"creator_gini_max": 0.82,
"latency_p99_ms_max": 40
}
}
Regra de Promoção
Modelo novo só sobe se:
- melhorou métrica primária,
- respeitou guardrails,
- passou canary sem regressão operacional.
Confiabilidade de Serving e Fallbacks (Core 8)
Falha de recomendação não pode virar tela vazia.
Hierarquia de Fallback
- Personalizado principal.
- Cache curto por usuário.
- Lista contextual (popular por locale/superfície).
- Lista global segura.
Fluxo com Degradação
sequenceDiagram
participant App as Cliente
participant API as Rec API
participant RET as Retrieval
participant RANK as Ranking
participant F as Fallback
App->>API: get recommendations
API->>RET: retrieve candidates
alt stack principal saudável
RET-->>API: candidates
API->>RANK: score
RANK-->>API: ranked
API-->>App: personalized list
else degradado
API->>F: fallback(context)
F-->>API: fallback list
API-->>App: fallback list
end
Circuit Breakers Importantes
- Timeout em ANN.
- Timeout em inferência de ranker.
- Limite de dependência por request.
- Queda para degradado em caso de erro repetido.
Regra de Produto
Retornar lista não-vazia sempre que policy permitir.
Treinamento, Validação e Deploy
Sem disciplina aqui, modelo bom no notebook vira incidente em produção.