Caso 7 · Tu mero mole

Sistemas de recomendación

Generar candidatos relevantes para cada usuario, rankearlos rápido y aprender continuamente del feedback.

Recursos

Recommendation, Candidate, FeatureVector, Event, Experiment.

Operaciones

Generar, rankear, registrar feedback, A/B test.

Escala

Millones de items, millones de users, decisiones por segundo.

Riesgo

Cold start, sesgo de exposición, drift, feedback loop tóxico.

Requisitos

Aclara el contrato: qué responde el sistema y con qué garantías.

Funcionales

  • Devolver lista rankeada según contexto.
  • Logear feedback (impressions, clicks, conversiones).
  • Explicabilidad opcional ("porque viste X").
  • Asignar variantes A/B sticky por user.
  • Filtros: locale, language, content policy.

No funcionales

  • p99 < 100 ms en respuesta online.
  • Train/serve consistency en features.
  • Frescura modelo: re-train diario, hot features < min.
  • Escala 100M+ items, 100M+ users.
  • Exploración ≥ 5% del tráfico para evitar feedback loop.

Cómo aclarar requisitos en la entrevista

Casos de uso típicos. Home feed personalizado, "you might also like" en página de producto, email weekly picks, search re-ranking, push notifications de items nuevos relevantes, "out-of-stock alternatives" en e-commerce, sidebar de "trending in your network", continue-watching en streaming.

Preguntas que debes hacer:

• ¿Cuántos slots a recomendar? 5 vs 100 cambia el budget de cómputo.
• ¿Personalizado por user o cohort-based / popularidad?
• ¿Online (real-time) o async (precomputed batch)?
• ¿Cold start matters: usuarios nuevos cómo arrancan?
• ¿Métrica de éxito: CTR, conversión, watch time, retención D7/D30?
• ¿Diversidad importa? Si solo optimizas relevancia, eco chamber.
• ¿Explicabilidad obligatoria? Cambia los modelos válidos (interpretables vs deep).
• ¿Latencia: budget online (sub-100ms) o se puede precomputar?
• ¿Cuántos items y users? 1K vs 1B cambia ANN, sharding, etc.

Frase clave: "Asumo home feed online, ~10 slots, sub-100ms p99, 100M items y 100M users, métrica primaria CTR con guardrail de diversidad. Si me dices long-form watch time o conversion, ajusto el ranker."

Estimaciones de capacidad

Resoluciones año/día/seg. Define el budget online del ranker y el tamaño del feature store.

100M
DAU
~3B MAU · plataforma de consumo masivo.
~30B sesiones/año.
~10
Reco requests / user / día
~1B requests/día · ~365B/año.
~12K/s avg · ~120K/s pico.
~500
Candidates → 10–50 ranked
~500B candidates rankeados/día.
~6M ranks/s en peak.
~1 KB
Feature vector / item
~100 GB / 100M items.
+ ~100 GB user features (1 KB × 100M).
10–50 ms
Budget feature lookup
Bulk MGET de ~500 items.
Redis / Bigtable / DynamoDB.
100 ms p99
Latency total
Recall ~30 + lookup ~30 + rank ~30 + filter ~10.
Hard budget no negociable.
~10K events/s
Pipeline feedback
~860M eventos/día · ~314B/año.
Impr + click + conv ratio típico 100:5:1.
99.95%
SLO reco
~4.4 h/año · ~21 min/mes.
~43 s/día permitidos.

Endpoints

MétodoPathDescripciónNotas
GET/api/recommendations?userId=&context=homeLista rankeada para un slot.Latencia objetivo <100ms.
POST/api/events/impressionVista del item en pantalla.Imprescindible para CTR.
POST/api/events/clickClick en una recomendación.
POST/api/events/conversionCompra/like/save.Señal positiva fuerte.
GET/api/recommendations/explain?recId=...Razón de la recomendación.Útil para confianza.
POST/api/experiments/assignDevuelve variante A/B.Ideal stickiness por user.

Cómo defiendo estas APIs en la entrevista

Una API simple esconde un sistema complejo. GET /recommendations parece trivial — pero detrás hay candidate generation, feature lookup, ranker, diversity filter, A/B assignment. Mantengo la API estable; los detalles cambian con cada release del modelo.

Eventos separados por tipo. impression, click, conversion en endpoints distintos para que el cliente no envíe payloads enormes. Cada uno con event_id para dedup en el stream.

Explainability como first-class. GET /recommendations/explain?recId=... devuelve la razón ("similar a tu listening history" o "popular en tu cohort"). Esto sube confianza del usuario y ayuda a debuggear el sistema.

Frase clave: "La API es contract estable; el sistema atrás itera con A/B continuo. experiment_id en cada response permite atribuir métricas a la variante correcta."

Ejemplo

GET /api/recommendations?userId=u_44&context=home&limit=10

200 OK
{
  "experiment": "ranker_v3.2",
  "items": [
    { "id": "i_99", "score": 0.91, "reason": "similar_to_recent" },
    { "id": "i_42", "score": 0.88, "reason": "popular_in_cohort" }
  ]
}

Arquitectura

flowchart LR Client(["Cliente"]) --> Reco Reco{{"🌐 RECO API GATEWAY
experiment routing"}} --> Recall["Candidate Generation
ANN + popular + cohort"] Recall --> Embed Reco --> Rank["Ranker Online
p99 ≈ 100 ms"] Rank --> FS Reco --> Filter["Policy / Diversity Filter"] Reco --> Exp["A/B Assignment
sticky hash"] Client -. impressions / clicks / conv .-> Stream Stream --> FS Stream --> Train["Training Pipeline
offline batch + incremental"] Train --> Rank Train --> Embed subgraph Embed["🧠 Embeddings ANN · HNSW / FAISS"] direction TB v1["item_vectors"] v2["user_vectors"] end subgraph FS["💾 Feature Store · Bigtable / Redis"] direction TB f1["user:id"] f2["item:id"] f3["cohort:id"] end subgraph Stream["📨 Kafka · events"] direction TB k1["impressions"] k2["clicks"] k3["conversions"] end classDef gateway fill:#fbbf24,stroke:#f59e0b,stroke-width:3px,color:#0f172a,font-weight:bold classDef service fill:#4c1d95,stroke:#a78bfa,stroke-width:2px,color:#ede9fe classDef client fill:#1f2937,stroke:#94a3b8,stroke-width:2px,color:#e5e7eb class Reco gateway class Recall,Rank,Filter,Exp,Train service class Client client

Cómo lo explico en la entrevista

Request entra. Cliente abre la home y hace GET /api/recommendations?context=home. El Reco API lee primero la asignación de experimento del user (sticky por hash(userId)), luego dispara dos cosas en paralelo: candidate generation y feature lookup.

Candidate generation (~30 ms). Tres queries: (1) ANN sobre el embedding del user devuelve ~200 items cercanos, (2) popularidad por cohort/región da ~100 items que están funcionando ahora, (3) collaborative filtering agrega ~200 más. Dedup → ~500 candidatos únicos.

Feature lookup paralelo. Bulk MGET al feature store: features del user (last 30 d activity, demographics, hour, device) más features de los 500 items. Esto lleva 20–30 ms con Redis o Bigtable.

Online ranker. El modelo (TF Serving u ONNX) toma los 500 × user_features × item_features y devuelve scores. Aplicamos policy filters (locale, content policy) y diversity filter. Top-K final con razón ("similar a lo que viste"). Total p99 ~100 ms.

Feedback loop. Cliente muestra. Cada item visible emite impression. Click → click. Compra → conversion. El stream alimenta features online en segundos y el training pipeline en batch (cada hora o día) para refrescar el modelo.

Frase clave: two-stage retrieval con feature store unificado. El ranker se entrena offline y se sirve online — esto evita train/serve skew y permite A/B sin caos.

Por qué cada componente

Two-stage retrievalRankear millones es imposible. Recall barato + rank fino es el patrón estándar.
ANN (HNSW / FAISS / ScaNN)Top-K en embeddings sub-10 ms. Captura semántica más allá de keywords.
Feature StoreTrain/serve consistency. Las mismas features en entrenamiento y serving evita skew silencioso.
Online rankerModelo entrenado offline, servido online. Estabilidad de latencia, no se entrena en path crítico.
Sticky AB assignmentHash de userId garantiza que el usuario no oscile entre variantes en la misma sesión.
Stream eventsLatencia de segundos para incorporar feedback al feature store. Reprocesable.
Diversity filterEvita feedback loop tóxico. Forza exploración mínima del 5%.
EmbeddingsEntendimiento semántico. Permite "user/item similarity" sin reglas explícitas.

Cuellos de botella

  • Feature store hot keys (mismos items leídos por miles de users).
  • Ranker GPU/CPU saturado en peak — latencia se dispara.
  • ANN index rebuild lento en uploads masivos de items nuevos.
  • Cold start users e items sin historial.
  • Train/serve skew si las features se computan distinto en cada lado.

Mejoras / cómo escala

  • Cache de features por item con TTL corto (decay rápido pero ahorra hot reads).
  • Multi-tenant ranker con cuotas por experimento.
  • HNSW incremental updates para que items nuevos aparezcan en minutos.
  • Bandit con epsilon-decay para cold start (más exploración al inicio).
  • Feature Definition compartida (mismo código de transformación en train y serve).
  • Modelo ligero en path crítico, modelo pesado para refresh batch.

Por qué estos servicios cloud (vs alternativas)

FAISS / HNSW / ScaNN / Vertex AI Matching Engineembeddings ANN

Por qué: top-K vecinos en embeddings de 100M+ items en sub-10 ms. HNSW soporta inserts incrementales para items nuevos. Recall > 95% con tuning correcto.

vs pgvector: insuficiente a esta escala. vs Elasticsearch dense_vector: aceptable, menos óptimo. vs Pinecone / Weaviate: managed equivalentes pero costosos.

Feature Store (Bigtable / DynamoDB / Redis / Feast)user + item features

Por qué: bulk MGET de features en <30 ms. Bigtable/Dynamo para volumen + Redis para hot keys. Feast como capa de abstracción para train/serve consistency.

vs Postgres: no escala a 6M req/s. vs DynamoDB sin Redis: aceptable pero hot keys saturan. vs custom in-memory: sin durabilidad ni replicación.

Apache Kafka / Pub/Subevents impr/click/conv

Por qué: stream con dedup por event_id, particionado por user_id, alimenta feature store online y warehouse para training. Múltiples consumers (training, attribution, fraud, BI).

vs Kinesis: AWS-only. vs SQS: point-to-point, no escala a múltiples consumers. vs llamadas síncronas: path crítico se rompe si downstream falla.

Model Serving (TF Serving / Triton / Vertex AI Predictions)online ranker

Por qué: inference con batching, model versioning, A/B sticky por user, GPU/CPU optimization, warm-up al deploy. Crítico para mantener p99 sub-100 ms.

vs SageMaker (managed): aceptable, más caro y menos custom batching. vs FastAPI con torch.load: sin batching ni warm-up serio, latencia inaceptable.

Training Pipeline (Airflow / Kubeflow / Vertex AI / SageMaker)batch training

Por qué: orquestación de pipelines con dependencias (data ingestion → feature gen → train → eval → deploy), schedules, retries, observability del DAG.

vs cron + scripts: sin observability, retries inexistentes, debugging penoso. vs MLflow solo: tracking pero no orquesta el DAG.

Diseño de base de datos

Feature store online, embeddings en ANN store, eventos al stream para entrenamiento.

items
item_idUUID PK
typeENUM
titleTEXT
localeVARCHAR(8)
policy_flagsINT
created_atTIMESTAMPTZ
idx (type, created_at), idx (locale)
embeddings
item_idUUID PK
vectorVECTOR(128)
model_versionVARCHAR
updated_atTIMESTAMPTZ
Backed por FAISS / ScaNN / pgvector
idx HNSW para top-K ANN
feature_store (online)
user:{id}HASH
item:{id}HASH
cohort:{id}HASH
Bigtable / Redis / DynamoDB
Same code path en train y serve
events (stream)
user_id, item_idUUID
actionimpr/click/conv
experimentVARCHAR
tsTIMESTAMPTZ
Tópico Kafka con dedup por event_id
Sink: feature store + warehouse

Cómo defiendo este diseño de base de datos

Cuatro storages, un solo dato lógico. Items en relacional para joins; embeddings en ANN para retrieval; features en KV low-latency para serving; events en stream para feedback. Cada uno representa una "vista" del mismo data lifecycle.

Train/serve consistency es no-negociable. El feature store online (serving) y el feature store offline (training) deben tener idéntico código de transformación. Si el modelo se entrena con user.click_rate_7d calculado de una manera y serving lo calcula distinto, el modelo miente sobre datos que nunca vió.

Embeddings actualizables. HNSW soporta inserts incrementales; cuando hay un item nuevo, generamos su embedding y lo agregamos sin rebuild completo. Re-train completo es nocturno; updates incrementales son sub-minuto.

Frase clave: "El sistema tiene un feature store que vive en el centro: training lee de él, serving lee de él, eventos lo updatean. Sin esa unificación, hay train/serve skew que destruye la accuracy."

Tipos de sistemas de recomendación

Lo que se pregunta en entrevistas: qué algoritmos existen, cuándo usar cada uno, y cuál proponer hoy.

01

Content-based filtering

Item features → recomienda items similares al historial del user.

Cómo: TF-IDF / embeddings sobre descripción, tags, atributos. User profile = vector promedio de items que le gustaron. Score = cosine similarity.

Cuándo: catálogo con metadata rica (artículos, productos), users nuevos sin historial colaborativo, cold-start friendly.

Pros: explicable ("porque te gustó X con tag Y"), no necesita historial de otros, items nuevos entran rápido.

Contras: filter bubble — solo te recomienda más de lo mismo. Depende de calidad de features.

Ejemplo: news apps por keyword, "más como este" en producto.

02

Collaborative filtering · user-based

User-User similarity → te gusta lo que les gustó a usuarios similares.

Cómo: matriz user × item con interacciones; cosine sim entre filas. Recomienda items que vieron tus k vecinos.

Cuándo: catálogos pequeños/medianos, prototipos rápidos. No para producción a escala.

Pros: descubre items lejos del historial, no necesita features de items.

Contras: no escala (k-NN sobre 100M users es brutal), cold start fuerte, sparsity.

Ejemplo: Amazon temprano, GroupLens, MovieLens académico.

03

Collaborative filtering · item-based

Item-Item similarity → items similares a los que ya usaste.

Cómo: cosine sim entre columnas (items co-vistos por mismos users). Score user×item = sum de similarities con items del historial.

Cuándo: muchos users, items relativamente estables. Workhorse clásico.

Pros: precomputable offline, escala mejor que user-based, explicable.

Contras: cold start de items nuevos, no captura tendencias temporales.

Ejemplo: Amazon "Customers who bought X also bought Y" (Linden et al. 2003).

04

Matrix Factorization (SVD / ALS)

Latent factors → comprime user-item en embeddings densos.

Cómo: descompone matriz user-item rala en U × Vᵀ con dimensiones latentes (~50–200). Score = U_user · V_item.

Cuándo: ratings explícitos o implícitos, base de muchos sistemas modernos.

Pros: descubre patrones latentes, ALS distribuido escala (Spark MLlib), pre-cálculo de embeddings.

Contras: cold start de users e items, factores poco interpretables.

Ejemplo: ganador del Netflix Prize, Spotify CF temprano.

05

Two-Tower / Dual Encoder

User tower + Item tower → embeddings que se matchean por dot product.

Cómo: dos NNs separados producen embeddings de user e item. Entrenar para que producto interno alto = relevancia. Indexar items con ANN (HNSW/FAISS/ScaNN).

Cuándo: retrieval de catálogos masivos con sub-10 ms latency. Estándar de oro hoy en producción.

Pros: escala a billones de items, captura semántica, train/serve consistency.

Contras: complejidad de infra, hay que regenerar embeddings de items nuevos.

Ejemplo: YouTube candidate generation, Pinterest, Etsy, Amazon.

06

Deep Ranking (DLRM / Wide & Deep / DCN)

Modelos densos para rankear pocos candidatos con muchas features.

Cómo: arquitecturas como DLRM (Meta), Wide & Deep (Google), DCN. Combinan features categóricas (embeddings) y dense (cross networks). Output: P(click), P(watch > 30 s), etc.

Cuándo: ranking stage en two-stage system, presupuesto computacional moderado.

Pros: SOTA accuracy, captura cross-features no obvias, multi-objetivo.

Contras: feature engineering caro, training pesado, latencia significativa por candidato.

Ejemplo: Facebook Newsfeed, Google Ads, YouTube ranker.

07

Sequence-based (BERT4Rec / SASRec / GRU4Rec)

Modela la secuencia de items vistos como un lenguaje.

Cómo: trata historia del user como secuencia. Predice next-item con self-attention (BERT4Rec / SASRec) o RNN (GRU4Rec). Mask de items para entrenar.

Cuándo: orden importa (música, video, e-commerce con sesiones), historiales largos.

Pros: captura patrones temporales y sesiones, SOTA en next-item.

Contras: caro de entrenar (transformers), latencia mayor, necesita historia suficiente.

Ejemplo: Spotify Discover Weekly mix, Netflix continue-watching, Amazon session-based.

08

Graph Neural Networks (PinSage / GraphSAGE)

Modela usuarios + items + interacciones como un grafo.

Cómo: aprende embeddings propagando info por aristas (followers, likes, co-views). Score por proximidad en el grafo.

Cuándo: dominio inherentemente de grafo (social, e-commerce con co-purchases, content sharing).

Pros: rico en estructura, items nuevos entran rápido vía vecinos, captura relaciones indirectas.

Contras: infra compleja, training pesado, debugging difícil.

Ejemplo: Pinterest PinSage, Uber Eats, LinkedIn People You May Know.

09

Contextual Bandits / RL

Decide explorar nuevos items vs explotar lo que sabes.

Cómo: cada slot es una decisión con reward. LinUCB, Thompson sampling. Slate optimization para múltiples slots correlacionados. RL con reward delayed (watch time, retention).

Cuándo: cold start estructural, exploración necesaria, métricas largo plazo.

Pros: maneja exploración formalmente, adapta rápido a items nuevos, marcos teóricos sólidos.

Contras: convergencia lenta sin priors, evaluación compleja, off-policy difícil.

Ejemplo: Yahoo News (LinUCB), Microsoft Decision Service, Uber promociones.

10

Hybrid (combinación)

Mezcla content + CF + signals contextuales.

Cómo: ensemble lineal sobre scores de modelos distintos, o cascada (content para cold start, CF cuando hay historia, deep ranker al final).

Cuándo: producción real. Casi nadie usa un solo modelo.

Pros: maneja cold start, combina fortalezas, robusto a fallas parciales.

Contras: complejidad operativa, debugging del ensemble, tuning de pesos.

Ejemplo: Netflix, Spotify, Amazon, YouTube — todos en producción son híbridos.

Qué proponer en una entrevista hoy

Para sistemas modernos a escala (YouTube, TikTok, Spotify, e-commerce), propongo un pipeline híbrido de dos etapas con bandits:

1. Retrieval (recall, ~500 candidatos). Combino tres fuentes en paralelo:
Two-tower neural con ANN (HNSW/FAISS) para ~200 items semánticamente similares al user.
Item-based CF precomputado para ~150 vecinos colaborativos.
Popularidad por cohort/región para ~100 items que tienden ahora (cold start safety net).
Después dedup → ~500 candidatos en < 30 ms.

2. Ranking (precision, ~10–50). DLRM o Wide & Deep que toma features del user e item del feature store, predice probabilidad de la métrica primaria (CTR, watch time, conversión). Multi-objetivo si hay varios KPIs.

3. Re-ranking final. Diversity filter (no stack del mismo creator/topic), business rules (boost campañas, filter policy/locale), recent_seen dedup.

4. Cold start & exploration. Contextual bandit con epsilon-greedy ~5–10% del tráfico para items nuevos. Fallback a popularity para users sin historial.

5. Sequence model opcional. Si la entrevista es Spotify / Netflix continue-watching, agrego SASRec / BERT4Rec en candidate generation para capturar patrones temporales del user.

Por qué esta combinación: two-tower escala a billones de items con sub-10 ms; DLRM da SOTA en ranking; bandits resuelven cold start formalmente; popularidad y re-ranking son guardrails baratos. Es exactamente lo que YouTube, TikTok y Pinterest tienen en producción hoy.

Decisiones técnicas

TemaDecisiónPor qué
Two-stageRecall (mucha cantidad) + ranking (pocos, finos).Costo y latencia, patrón estándar.
EmbeddingsANN (HNSW, FAISS, ScaNN) para recall.Subsegundo aún con millones de items.
FeaturesOnline + offline en feature store unificado.Train/serve consistency.
ModeloEntrenado offline, servido online.Estabilidad de latencia, A/B sano.
EventosStream con dedup y latencia < segundos.Aprende rápido del usuario.
ExperimentosAsignación stickyness por hash del userId.Resultados consistentes en sesión.

Cómo defiendo estas decisiones técnicas

Constraint principal: p99 < 100 ms con 6M req/s en peak. Esto fuerza two-stage retrieval (no puedes rankear millones), modelo offline (no entrenas en path crítico), feature store low-latency (no queries SQL), y model serving optimizado (no flask + torch.load).

Métricas que validan. Online: CTR, conversion, watch time. Offline: nDCG, recall@K. Operacional: p99, feature staleness, model staleness, A/B sample size. Guardrail: diversity, exploration rate, feature lookup error rate.

Cuándo cambio de opinión. Latencia presupuesto sube a 500 ms → modelo más complejo (sequence transformers, graph attention). Items super dinámicos → embeddings actualizables vs reindex completo. Cold start crítico → bandit prominent en el blend.

Frase clave: "Cada decisión es trade entre latencia, accuracy, freshness, complejidad operacional. El sistema mejor no es el con mejor modelo — es el que da el mejor número en producción con el budget que tienes."

Pitfalls

Train/serve skew

Si las features online no matchean con las del entrenamiento, el modelo miente.

Cold start

Usuarios nuevos sin historial. Usa popularidad, geografía, onboarding.

Feedback loop

El modelo se reinforza a sí mismo. Reserva tráfico para exploración.

Script de respuesta: “Diseño un pipeline de dos etapas: recall (con ANN sobre embeddings) y ranking (modelo offline servido online). Las features viven en un feature store compartido entre training y serving para evitar skew. Los eventos van por stream y alimentan el ciclo de re-entrenamiento. Manejo experimentos con asignación sticky por user, mido CTR, conversion, diversidad y exploro un porcentaje del tráfico.”

Tiers de almacenamiento

Feature store online es caro per-byte; events viejos pueden vivir muy frío sin perder valor.

Hot · in-memory + ANN
Feature store online (user/item features), ANN index en RAM/SSD-NVMe, hot embeddings.
Bigtable + Redis + FAISS/HNSW node memory
~$0.25/GB/h Bigtable · ~$36/GB Redis
Warm · object storage Standard
Eventos recientes (last 7–30 días), modelos servidos actuales, training partitions hot.
S3 Standard + BigQuery active partitions
~$0.023/GB/mes
Cold · object storage IA
Eventos > 30 días para training (offline), modelos viejos para rollback, embeddings de versiones N-2.
S3 Standard-IA / BigQuery long-term storage
~$0.0125/GB/mes (BQ long-term auto a 90 días)
Frozen · archive
Raw event archive > 1 año (compliance, reentrenamiento histórico, análisis longitudinal).
S3 Glacier / Glacier Deep Archive
~$0.001–0.004/GB/mes · retrieval horas

Cómo defenderlo en la entrevista

BigQuery long-term automático. Particiones de tabla en BigQuery sin acceso por 90 días bajan automáticamente a long-term storage (50% off). No requires lifecycle manual — el warehouse lo hace solo. Hot queries siguen funcionando sin cambio.

Modelos viejos como artifacts. Cada modelo entrenado se versiona en S3 con tag model_version. Mantengo los últimos 2 en Standard (rollback rápido); > 6 meses van a IA. Si un modelo de hace 2 años falla auditoría, puedo retrievear (12 h) para investigar.

Frase clave: "Online serving está en RAM/Bigtable porque sub-30ms es no-negociable. Training data en S3 / BigQuery con tiering automático: hot recents, cold > 30 d, frozen para audit. Esto reduce el costo de storage del pipeline ML ~5×."

Versión alternativa: con Load Balancer (no API Gateway)

Para reco serving la latencia es product feature. LB es lo natural; Gateway no aporta valor.

flowchart LR Client(["Cliente"]) --> LB LB{{"⚖️ L7 LOAD BALANCER
region routing"}} --> Pod["Reco API Pods
+ JWT verifier (local)
+ Rate limit (token bucket)"] Pod --> Recall["Candidate Generation"] Recall --> Embed Pod --> Rank["Ranker Online"] Rank --> FS Pod --> Filter["Policy / Diversity Filter"] Pod --> Exp["A/B Assignment"] Client -. impressions/clicks/conv .-> Stream Stream --> FS Stream --> Train["Training Pipeline"] Train --> Rank Train --> Embed subgraph Embed["🧠 Embeddings ANN"] direction TB v1["item_vectors"] v2["user_vectors"] end subgraph FS["💾 Feature Store"] direction TB f1["user:id"] f2["item:id"] end subgraph Stream["📨 Kafka events"] direction TB k1["impressions"] k2["clicks"] k3["conversions"] end classDef lb fill:#34d399,stroke:#10b981,stroke-width:3px,color:#0f172a,font-weight:bold classDef service fill:#4c1d95,stroke:#a78bfa,stroke-width:2px,color:#ede9fe classDef client fill:#1f2937,stroke:#94a3b8,stroke-width:2px,color:#e5e7eb class LB lb class Pod,Recall,Rank,Filter,Exp,Train service class Client client

API Gateway vs Load Balancer: cómo defender cada uno

Reco serving es interno. El cliente típicamente es tu propio app o frontend, no un third-party. Auth con JWT verificado local en pod, rate limit con Redis. Gateway agrega latencia que el SLO p99 < 100 ms no aguanta.

Frase clave: "Reco serving usa LB porque es interno, latency-sensitive y high-QPS. Si expongo recos como producto (e.g., Reco-as-a-Service para terceros), agrego Gateway en el path externo manteniendo el LB para internal."

Cuándo elegir API Gateway

  • Reco-as-a-Service ofrecido a clientes externos.
  • Multi-tenant con quotas distintas por cliente.
  • API monetization con plans por requests/mes.
  • Auth via OAuth con scopes granulares.

Cuándo elegir Load Balancer

  • Reco interno para tu propio frontend (caso típico).
  • SLO p99 < 100 ms — gateway agrega latencia inaceptable.
  • High QPS (12K+/s) — costo gateway prohibitivo.
  • Eventos ingest: 10K/s, fire-and-forget, no necesita gateway features.
  • Service mesh con sidecar para mTLS y observability.