0

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

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

  1. Gerar candidatos personalizados para cada usuário.
  2. Ranquear candidatos por utilidade prevista, respeitando restrições.
  3. Responder em latência baixa e previsível.
  4. Atualizar recomendações conforme novas interações.
  5. Tratar cold-start de usuários e itens.
  6. Ter fallback quando componentes de ML falharem.
  7. Expor metadados mínimos de explicação quando necessário.
  8. Suportar A/B tests, canary e rollback seguro.

Requisitos Não-Funcionais

RequisitoMetaMotivo
Latência API recomendação< 120ms p99UX fluida e retenção
Disponibilidade99,99%Superfícies centrais dependem disso
Freshness de sinaissegundos a poucos minutospersonalização desatualizada perde valor
Escalamilhões de req/s em picosplataformas globais
Consistênciaeventual para features, forte para configuraçãoequilíbrio entre custo e controle
Degradaçãosem tela vazia em falhas de MLresiliência de produto

Métricas de Sucesso

Você não otimiza só CTR. Um sistema maduro monitora cesta de métricas:

  1. CTR
  2. dwell/watch time
  3. conversão
  4. profundidade de sessão
  5. retenção D1/D7/D30
  6. distribuição de exposição por creator/seller
  7. métrica de qualidade e diversidade
  8. latência e erro de serving

Perguntas de Clarificação (Entrevista)

  1. Qual superfície vamos otimizar primeiro (home feed, discover, produto)?
  2. Qual o budget de latência por request?
  3. Quão rápido um clique precisa impactar ranking?
  4. Existe requisito formal de fairness/diversidade?
  5. 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 é:

  1. retrieval barato em lote grande,
  2. ranking pesado em lote menor,
  3. 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:

  1. eficiência retrieval + ranking,
  2. freshness de features,
  3. paridade treino-serving,
  4. 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

  1. Multi-estágio para controlar custo de inferência.
  2. Separação clara entre plano online e plano offline.
  3. Contratos versionados de features e modelos.
  4. Fallback como funcionalidade de produto, não gambiarra.
  5. 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

  1. UserFeatures
  2. ItemFeatures
  3. InteractionEvent
  4. ModelArtifact
  5. DeploymentConfig
  6. 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

  1. Collaborative filtering.
  2. Similaridade por embedding.
  3. Popularidade/trending por contexto.
  4. Afinidade social (follows, grafo).
  5. 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

  1. Alta recall com latência baixa.
  2. Atualizações incrementais.
  3. Particionamento por vertical/locale quando necessário.
  4. Escalabilidade para bilhões de vetores.

Caminho de Retrieval

  1. Buscar embedding do usuário.
  2. Consultar ANN para top-N próximos.
  3. Aplicar filtros grossos (policy, idioma, elegibilidade).
  4. 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égiaVantagemDesvantagemUso
rebuild diáriosimplesstaleness altasuperfícies menos sensíveis
incremental horáriobom equilíbriomais complexidadepadrão
quase realtimefreshness máximacusto altosuperfí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

  1. Pre-ranker leve em ~2.000 candidatos.
  2. Ranker mais pesado em ~300.
  3. 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

  1. Cota máxima por creator.
  2. Diversidade mínima por tópico/fonte.
  3. Bloqueios de policy.
  4. Posições reservadas com limite estrito.
  5. 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

  1. Baixa latência online.
  2. Histórico offline confiável.
  3. Definições únicas e versionadas de features.
  4. 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

  1. Registry central de features.
  2. Tests de consistência online/offline.
  3. Monitoramento de null-rate e drift por feature.
  4. 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

  1. Impression
  2. Click
  3. Like/Favorite
  4. Share
  5. Add-to-cart
  6. Purchase
  7. Hide/Not interested
  8. 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

  1. Schema registry e compatibilidade.
  2. Dedupe de eventos.
  3. Tratamento de clock skew.
  4. Watermarks para atraso.
  5. 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

  1. Epsilon-greedy por segmento.
  2. Thompson sampling.
  3. Contextual bandits.
  4. Buckets de exploração controlada por superfície.

Restrições de Diversidade

  1. Diversidade de fonte.
  2. Diversidade de tópico.
  3. Controle de repetição por creator.
  4. 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íticaProContra
sem exploraçãoestabilidade de curto prazoestagnação e viés de exposição
exploração agressivaaprendizado rápidoqueda de métrica imediata
exploração controladaequilíbrioexige disciplina de experimento

Dica Prática

Comece simples:

  1. ranker determinístico,
  2. exploração pequena e observável,
  3. guardrails fortes,
  4. 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

  1. Rich-get-richer de creators já grandes.
  2. Redução extrema de cobertura de catálogo.
  3. Bolhas de tópicos.
  4. Viés histórico auto-reforçado.

Controles de Governança

  1. Monitorar distribuição de exposição.
  2. Definir limites de concentração.
  3. Medir coortes sensíveis separadamente.
  4. Incluir objetivos de longo prazo.
  5. 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:

  1. melhorou métrica primária,
  2. respeitou guardrails,
  3. 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

  1. Personalizado principal.
  2. Cache curto por usuário.
  3. Lista contextual (popular por locale/superfície).
  4. 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

  1. Timeout em ANN.
  2. Timeout em inferência de ranker.
  3. Limite de dependência por request.
  4. 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.

Pipeline de Treino

Carregando publicação patrocinada...