Danh sách bài viết

Bài 36: AI System Design — kiến trúc 1 ML inference pipeline

Walk-through 6-bước thiết kế ML inference pipeline serving traditional classifier: fraud detection real-time, recommendation, image moderation. Tập trung feature store, latency budget, online vs offline inference, scaling high-throughput, và failure handling — phân biệt rõ với RAG (bài 35).

28/05/2026
0 lượt xem
1

Mục Tiêu Bài Học

Sau bài này bạn sẽ:

  • ✅ Phân biệt được điểm khác biệt giữa ML inference pipeline và RAG pipeline trong interview
  • ✅ Walk-through 6-bước framework với example fraud detection cụ thể (số liệu, latency budget, cost)
  • ✅ Giải thích được feature store — hot path vs cold path, online vs offline feature
  • ✅ Biết cách handle high-throughput (100–1000 TPS) và justify trade-off
  • ✅ Chuẩn bị được follow-up questions về drift, cold start, model reload, SHAP
2

ML Inference vs RAG — Điểm Khác Biệt Chính

Bài 35 cover RAG production (LLM-centric). Bài này cover traditional ML serving. Hai loại có những đặc điểm khác nhau đáng kể:

Tiêu chí RAG Pipeline ML Inference Pipeline
Model core LLM (GPT, Claude, Llama) Classifier, regressor, recommender (XGBoost, LightGBM, CNN, Two-Tower)
QPS thực tế 1–50 QPS (LLM latency cao) 100–10,000 QPS (inference ms)
Latency target 1–5 giây (acceptable) P99 < 50–200ms (strict)
Input chính Natural language query Tabular feature, image, time-series
Output Generated text + citations Probability score, class label, top-N list
Feature engineering Prompt construction, chunking Feature store (offline + online), aggregation
Training pipeline Optional (zero-shot hoặc fine-tune) Integral — weekly/daily retrain với labeled data
Stochasticity Cao (LLM sampling) Thấp (deterministic predict)

Nhận ra loại hệ thống ngay từ đầu interview giúp bạn đi đúng hướng từ bước requirements.

3

Pattern Câu Hỏi Phổ Biến

Interviewer thường mở bằng một trong các dạng sau:

"Design an ML inference system for fraud detection
serving 100 TPS with P99 latency under 100ms."

"Design a real-time recommendation system for e-commerce."

"Design an image content moderation pipeline handling
5,000 images/second."

"How would you serve an XGBoost model at scale?"

Bài này walk-through fraud detection end-to-end. Các biến thể (recommendation, image moderation) được cover ở phần 11.

4

Bước 1 — Requirements

Câu Hỏi Functional Cần Clarify

  • Model type: Classifier? Regressor? Recommender? (ảnh hưởng output format và evaluation)
  • Input type: Tabular feature? Image? Text? Time-series?
  • Output: Probability score? Binary decision (pass/block)? Top-N list? Regression value?
  • Online vs Batch: Realtime inference (sync) hay batch job (async)?
  • Multi-model: Cần A/B test không? Cần fallback model không?

Câu Hỏi Non-Functional Cần Clarify

  • QPS: 100? 10,000? Peak multiplier là bao nhiêu?
  • Latency: P99 < 50ms? < 500ms? Có hard deadline không (vd transaction settlement)?
  • Availability: 99.9% hay 99.99%? Mission-critical?
  • Cost: Budget tháng? On-prem hay cloud?
  • Retraining cadence: Daily? Weekly? Triggered by drift?
  • Compliance: Cần explainability (SHAP/LIME) cho regulatory không?

Example — Case Study: Fraud Detection

Sau khi clarify:
- Ngân hàng với 1M transaction/ngày, peak 100 TPS
- Latency target: P99 < 100ms (phải block fraud trước khi
  transaction settle)
- Model: XGBoost classifier, 50 tabular feature
- Output: probability score + binary decision (threshold = 0.7)
- Retrain weekly với label mới từ fraud investigation team
- Uptime SLA: 99.9% (downtime < 44 phút/tháng)
- Cần explainability: SHAP score cho compliance

Với requirements rõ, bắt đầu design. Fraud detection là use case có latency constraint khắt khe nhất vì transaction window thường < 3 giây.

5

Bước 2 — Capacity Estimate

Throughput

Average:  1M / 86,400s ≈ 12 TPS
Peak:     100 TPS (giờ cao điểm)
Spike:    500 TPS (Black Friday, holiday season)

Design cho: 500 TPS peak, headroom ×2 → 1,000 TPS capacity

Latency Budget (target P99 = 100ms)

Giai đoạn Budget Ghi chú
Network in 5ms Same-region request
Feature lookup (Redis) 20ms Hot path, in-memory
Online feature compute 10ms Tính từ request data
Model inference (XGBoost) 30ms 50 feature, in-memory model
Logging (async) 5ms Không block response
Network out 5ms
Buffer 25ms Cho jitter và P99 tail
Tổng 100ms

Storage

Feature store (online):
  100M user × 50 feature × 8 bytes (float64) ≈ 40GB → Redis cluster

Model artifact:
  XGBoost 500 trees → ~100MB → in-memory per replica

Inference log:
  1M request/ngày × 1KB/request = 1GB/ngày
  Retention 90 ngày → 90GB → S3 (rẻ, $2/tháng)

Cost Estimate — Per Month

Component Spec Ước lượng
Inference Service (EC2) 3×m5.large (2vCPU, 8GB RAM) ~$150/tháng
Redis (ElastiCache) r6g.large, 40GB data ~$100/tháng
Postgres (RDS) db.t3.medium, offline feature ~$50/tháng
S3 (log, model) ~100GB ~$3/tháng
Monitoring (CloudWatch) Metrics + alarms ~$20/tháng
Tổng ~$323/tháng
6

Bước 3 — High-Level Architecture

Diagram Tổng Quan

─── Online path (query) ─────────────────────────────────────

┌──────────────┐
│  Banking App │
└──────┬───────┘
       │ Transaction request (HTTPS)
       ↓
┌──────────────┐
│ API Gateway  │  (Auth, Rate limit, TLS termination)
└──────┬───────┘
       ↓
┌──────────────┐     ┌────────────────────────────┐
│  Inference   │────▶│  Feature Store             │
│  Service     │     │  Hot path:  Redis (40GB)   │
│  (FastAPI)   │     │  Cold path: Postgres (RDS) │
└──────┬───────┘     └────────────────────────────┘
       │
       ├──▶ [Model: XGBoost in-memory]
       │      ↓ predict(features)
       │    score, decision
       │
       ├──▶ [SHAP: async, on-demand]
       │
       └──▶ (async) Kafka topic: inference-logs
                       ↓
                      S3 (partitioned by date)

─── Offline path (training) ────────────────────────────────

┌──────────────────┐
│  Training        │  Airflow weekly DAG
│  Pipeline        │
└────────┬─────────┘
         ├──▶ Pull data: S3 (logs) + label (fraud DB)
         ├──▶ Feature engineer
         ├──▶ Train + eval (cross-validation)
         ├──▶ MLflow Model Registry (versioned artifact)
         ├──▶ Feature Store update (Postgres → Redis sync)
         └──▶ Drift Monitor (Evidently)

Hai Luồng Chính

Query path (online):

  1. Banking app gửi transaction request (user_id, amount, merchant, location, timestamp).
  2. API Gateway xác thực, rate limit.
  3. Inference Service lookup offline feature từ Redis (user history, avg spend 30d).
  4. Compute online feature từ request data (amount deviation, hour of day, country mismatch).
  5. Merge offline + online feature → 50-dim vector.
  6. Model.predict() → probability score.
  7. Apply threshold (0.7) → decision (allow/block).
  8. Return decision trong < 100ms.
  9. Log async sang Kafka (không block response).

Training path (offline):

  1. Airflow DAG chạy hàng tuần (hoặc trigger khi drift detected).
  2. Join inference logs với fraud label từ investigation team.
  3. Feature engineer, train XGBoost với hyperparameter search.
  4. Evaluate AUC, precision/recall trên holdout set.
  5. Nếu AUC > baseline → promote lên Model Registry, trigger deploy.
  6. Precompute offline feature batch → sync vào Redis.
7

Bước 4 — Deep Dive Component

a) Feature Store — Hot Path vs Cold Path

Feature store là component phân biệt rõ nhất ML inference pipeline so với web API thông thường:

Path Storage Latency Feature type Update cadence
Hot path Redis (in-memory) < 5ms Offline precomputed (avg spend 30d, merchant count, device count) Nightly batch sync
Cold path Postgres (RDS) 20–50ms Historical aggregates, slowly changing Weekly batch, fallback khi Redis miss
Online compute In-memory (request) < 1ms Real-time signal (amount ÷ avg, hour, country, velocity last 1 min) Per request

Phần lớn production system dùng hybrid: offline feature từ Redis + online feature compute từ request payload.

b) Inference Service — FastAPI Pattern

from fastapi import FastAPI
from contextlib import asynccontextmanager
import xgboost as xgb
import mlflow

model: xgb.Booster = None  # global, loaded once

@asynccontextmanager
async def lifespan(app: FastAPI):
    global model
    # Load model once at startup (không reload mỗi request)
    client = mlflow.tracking.MlflowClient()
    model_uri = client.get_latest_versions("fraud-detector", stages=["Production"])[0].source
    model = mlflow.xgboost.load_model(model_uri)
    yield
    # Cleanup nếu cần

app = FastAPI(lifespan=lifespan)

@app.post("/v1/predict")
async def predict(request: TransactionRequest):
    # 1. Lookup offline feature từ Redis
    offline = await redis_client.hgetall(f"user:{request.user_id}:features")

    # 2. Compute online feature
    online = compute_online_features(request, offline)

    # 3. Merge và predict
    features = merge_features(offline, online)   # 50-dim
    score = model.predict(xgb.DMatrix([features]))[0]
    decision = "block" if score > THRESHOLD else "allow"

    # 4. Log async (không await)
    asyncio.create_task(log_to_kafka(request, features, score, decision))

    return {"score": float(score), "decision": decision}

Model được load 1 lần khi startup (lifespan pattern). Predict là CPU-bound, synchronous — với XGBoost 50 feature thường < 5ms.

c) Model Reload Khi Deploy Model Mới

Ba pattern phổ biến:

  • Blue-green deploy: Spin up instance mới với model mới, chuyển load balancer sau khi health check pass. Zero downtime, rollback bằng cách trỏ traffic trở lại blue.
  • SIGHUP reload: Instance nhận SIGHUP signal → reload model trong memory → continue serving. Đơn giản hơn, có thể có brief latency spike trong quá trình reload.
  • A/B weight routing: Load balancer route 10% traffic đến instance có model mới. So sánh metric (fraud catch rate, false positive rate) trước khi promote 100%.

d) Latency Optimization

  • XGBoost native predict: Dùng xgb.DMatrix thay vì scikit-learn wrapper — bỏ qua Python overhead, tận dụng Cython backend. Với 50 feature, 500 trees: ~1–5ms.
  • Pre-allocate feature array: Tránh allocate numpy array mới mỗi request — dùng thread-local buffer hoặc object pool.
  • Async Redis lookup: Dùng aioredis để không block event loop khi chờ network I/O.
  • Feature pipeline vectorize: Tránh loop Python — dùng numpy operations cho online feature compute.

e) SHAP Explainability

Compliance yêu cầu giải thích tại sao giao dịch bị block:

import shap

explainer = shap.TreeExplainer(model)  # Khởi tạo 1 lần

def get_explanation(features: list) -> dict:
    """Trả về top-5 feature quan trọng nhất cho prediction."""
    shap_values = explainer.shap_values(np.array([features]))
    feature_importance = dict(zip(FEATURE_NAMES, shap_values[0]))
    # Sort by absolute value
    top_5 = sorted(feature_importance.items(),
                   key=lambda x: abs(x[1]), reverse=True)[:5]
    return dict(top_5)

SHAP TreeExplainer với XGBoost là exact (không phải approximate) — latency ~10–20ms. Gọi on-demand khi có compliance request, không gọi mỗi transaction để tiết kiệm latency.

8

Bước 5 — Scaling

10x QPS (1,000 TPS peak)

Component Hiện tại (100 TPS) Sau 10x (1,000 TPS)
Inference Service 3 instances m5.large 20–30 instances, autoscaling (CPU threshold 70%)
Redis Single r6g.large Redis Cluster (3 shard, read replica per shard)
Load Balancer ALB round-robin ALB với least-connection hoặc IP hash
Kafka 1 partition 10 partition (1 per 100 TPS), 3 consumer
Cost ~$323/tháng ~$2,000–2,500/tháng

Heavier Model (Deep Learning thay vì XGBoost)

Nếu business yêu cầu AUC cao hơn và sẵn sàng trade latency:

  • GPU instance: g4dn.xlarge (T4) cho inference deep tabular model (TabNet, DeepFM).
  • ONNX export: Convert model từ PyTorch/TensorFlow sang ONNX — runtime inference nhanh hơn ~2–3x so với Python backend.
  • TensorRT optimization: Quantization INT8 giảm latency ~4x, memory ~4x. Cần benchmark accuracy drop trước khi deploy.
  • Triton Inference Server: Dynamic batching — gom nhiều request nhỏ thành 1 batch GPU call → throughput tăng 10–20x, latency tăng nhẹ (thêm batch wait time ~2–5ms).

Multi-Region

  • Replicate model artifact từ S3 + MLflow sang mỗi region — model load từ local storage.
  • Redis: Mỗi region có Redis cluster riêng. Feature sync eventually consistent (nightly batch push).
  • Transaction data ở mỗi region route về inference service cùng region → latency < 10ms network.
  • Global user feature (cross-region purchase history) cần CDN cache layer hoặc accept eventual consistency.
9

Bước 6 — Failure Handling

Failure Scenarios Và Xử Lý

Failure Impact Xử lý
Redis down Không có offline feature → không predict Fallback sang Postgres slow path (~50ms thay vì 5ms); alert on-call
Inference service crash Request fail cho 1 instance Load balancer health check → remove instance; Kubernetes restart pod < 30s
Network partition Timeout liên tục Circuit breaker (Hystrix pattern): sau 5 fail → open circuit → fallback rule-based
Bad model deploy (AUC drop) Fraud rate tăng hoặc false positive tăng A/B canary (10% traffic) → monitor business metric 24h → auto rollback nếu metric ngoài band
Feature drift (input distribution shift) Model score kém dần theo thời gian Evidently monitor feature distribution daily; alert khi PSI > 0.2 → trigger retrain
Kafka lag tăng Inference log bị delay → retrain data stale Add consumer, alert khi lag > 100k message

Fallback Decision Logic

Khi toàn bộ inference service down (extreme case), cần fallback để không block mọi giao dịch:

def fallback_decision(amount: float, country: str,
                      user_country: str) -> dict:
    """Rule-based fallback khi ML service unavailable.
    Conservative: chỉ block các case rõ ràng nhất."""
    if amount > 10_000:
        return {"decision": "flag_for_review", "reason": "high_amount_fallback"}
    if country != user_country and amount > 1_000:
        return {"decision": "flag_for_review", "reason": "cross_country_fallback"}
    # Default: allow (false negative rủi ro thấp hơn block toàn bộ)
    return {"decision": "allow", "reason": "service_unavailable_fallback"}

Nguyên tắc: trong fraud detection, false negative (miss fraud) thường được chấp nhận hơn false positive (block legitimate transaction) khi service degraded — vì block toàn bộ giao dịch gây thiệt hại business lớn hơn.

Monitoring Metrics

  • Service metric: P50/P95/P99 latency per endpoint; error rate (5xx); RPS; CPU/memory usage per instance.
  • Model metric: Score distribution (histogram), mean score per hour, score variance — drift khi distribution thay đổi.
  • Business metric: Fraud catch rate (true positive rate), false positive rate, $/transaction blocked — reviewed bởi fraud analyst daily.
  • Cost: $/inference, Redis memory usage, Kafka consumer lag.

Alerting

  • P99 latency > 200ms liên tục 5 phút → page on-call.
  • Error rate > 1% → page.
  • Score distribution shift > 20% (PSI > 0.1) → drift alert → trigger manual review retrain.
  • False positive rate tăng > 50% so với 7-day baseline → business alert → xem xét threshold adjustment.
  • Redis memory > 80% → scale up alert.
10

Trade-off Discussion

Model Complexity vs Latency

Model Inference latency AUC (typical) Trade-off
Logistic Regression < 1ms 0.78 Fastest, lowest accuracy — dùng làm fallback
XGBoost (50 feature) 1–5ms 0.85 Sweet spot cho tabular fraud detection
TabNet (deep tabular) 30–80ms (CPU) 0.87 +2% AUC, +10x latency — không fit P99 < 100ms trên CPU
TabNet + GPU (T4) 5–15ms 0.87 Fit latency, nhưng GPU cost cao hơn 3–5x

Với P99 < 100ms và budget ~$323/tháng, XGBoost là lựa chọn hợp lý. TabNet GPU chỉ justify khi AUC improvement dẫn đến tiết kiệm > $X fraud mỗi tháng.

Feature Store — Build vs Managed

Option Ưu điểm Nhược điểm
Build in-house (Redis + Postgres) Full control, chi phí thấp (~$150/tháng), không vendor lock-in Cần engineer maintain, schema migration phức tạp
Feast (open-source) Standard API, training/serving consistency, community support Operational overhead deploy Feast server
Tecton (managed) Faster setup, real-time feature streaming, SLA $1,000–5,000+/tháng — chỉ hợp lý ở scale lớn

Online vs Batch Inference

Pattern Latency Throughput Use case
Online (sync) P99 < 200ms 100–1,000 TPS Fraud detection, ad ranking, content moderation real-time
Near-real-time (async) 1–30 giây Cao hơn Notification, email trigger, soft-block với review
Batch (offline) Hours Không giới hạn (scale out) Daily recommendation refresh, weekly churn prediction, report

Fraud detection bắt buộc online vì window settlement < 3 giây. Recommendation hàng ngày có thể batch — precompute top-N cho mỗi user, cache vào Redis, serve từ cache (latency < 1ms).

11

Các Biến Thể Use Case

Recommendation System (E-commerce)

Thường dùng 2-stage pipeline:

  1. Candidate generation: Two-tower model (user embedding + item embedding). Lookup từ vector DB (FAISS/Qdrant) — ANN retrieval top-1,000 candidate. Chạy offline hoặc near-real-time.
  2. Ranking: XGBoost/LightGBM re-rank 1,000 candidate xuống top-20. Online, per-request. Feature: user context, item context, cross feature (user × item interaction).

Điểm khác với fraud detection: latency relaxed hơn (P99 < 300ms acceptable). Throughput thường thấp hơn (homepage load) nhưng batch cold-start cần xử lý.

Image Content Moderation

  • CNN classifier (ResNet/EfficientNet) hoặc Vision Transformer.
  • GPU serving bắt buộc — Triton với dynamic batching gom request.
  • Multiple model chạy song song: NSFW detector, violence detector, spam detector — kết quả aggregate.
  • Confidence threshold tunable per category: violence threshold thấp hơn (0.5) so với NSFW (0.7) vì cost of miss khác nhau.
  • Async acceptable: upload ảnh → return job_id → poll result sau 1–2 giây.

Time-Series Forecasting

  • Model: Prophet, DeepAR (Amazon), N-BEATS.
  • Thường batch inference (hourly/daily run) — không realtime.
  • Pattern: precompute forecast → store vào Redis theo key (store_id, metric) → serve từ cache.
  • Cache TTL = forecast horizon (vd 24h TTL cho daily forecast).
12

Follow-up Questions Thường Gặp

Câu hỏi Hướng trả lời
"How do you handle model drift?" Monitor PSI (Population Stability Index) cho feature distribution daily. Monitor score distribution shift. Trigger retrain khi PSI > 0.2 hoặc business metric (fraud rate) ngoài band 2σ. Chi tiết ở Series 5 module MLOps.
"How do you handle cold start for new user?" Fallback sang default feature value (median của population). Hoặc popularity-based fallback (top-N global popular item). Sau khi user có đủ N transactions (vd 5), switch sang personalized model.
"Multi-model deployment?" Model registry với version tag (v1, v2, staging). Router service route theo percentage weight. Canary: v2 nhận 10% traffic, monitor metric, ramp up nếu OK.
"How do you explain model prediction for compliance?" SHAP TreeExplainer cho tree-based model — exact, fast (~10ms). LIME cho black-box model — approximate, slower. Serve SHAP on-demand (compliance endpoint) thay vì mỗi inference để tiết kiệm latency.
"Real-time vs batch inference?" Real-time: latency sensitive use case (fraud, ad ranking). Batch: throughput sensitive, latency relaxed (recommendation refresh, report). Hybrid: precompute batch + serve từ cache (recommendation). Trade-off là freshness vs cost.
"How do you retrain without downtime?" Blue-green deploy: train new model → test → promote trong registry → deploy new instances → health check pass → switch load balancer → terminate old instances.
"How do you handle feature inconsistency (training-serving skew)?" Dùng cùng feature pipeline code cho cả training và serving (feature store làm single source of truth). Log features tại serving time → join với labels để validate không có skew. Feast/Tecton giải quyết vấn đề này tự động.
13

Common Pitfalls

Lỗi Hệ quả Cách tránh
Bỏ qua training pipeline Interviewer expect cả ML lifecycle — thiếu là điểm trừ lớn Luôn vẽ cả online path và offline path trong diagram
Focus quá nhiều vào model, bỏ feature store Feature engineering là phần phức tạp nhất trong ML infra — skip = thiếu hiểu biết Giải thích rõ offline vs online feature và cách sync
Skip drift monitoring Interviewer sẽ hỏi "How do you know model still works in production?" Luôn mention drift detection và retrain trigger
Quên cost discussion Thiếu business sense Ước lượng $/tháng, $/inference — kể cả con số sơ bộ
Nhầm online inference với batch inference Architecture sai khi clarify requirement Hỏi ngay: "Is this request-response (sync) or async batch?"
Over-engineer Kubernetes + Triton + Feast cho 10 RPS — không cần Design tương xứng với scale. "Chúng ta đang ở 10 RPS, single FastAPI + Redis là đủ. Tôi sẽ explain cách scale nếu cần."
Không nói về training-serving skew Bỏ sót vấn đề thực tế nhất trong ML production Mention feature store đảm bảo consistent feature definition cho cả training và serving
14

Diagram Tips Trong Interview

  • Vẽ từ trái sang phải: User request → Gateway → Service → Model → Response. Dễ đọc, không rối chéo arrow.
  • Tách online path và offline path rõ ràng: Vẽ bằng đường kẻ ngang hoặc vùng màu khác. Interviewer muốn thấy bạn hiểu 2 luồng riêng biệt.
  • Label mỗi storage rõ ràng: Viết rõ "Redis (hot feature)" và "Postgres (cold feature)" — không viết chung "DB".
  • Đánh số arrow: ①②③... cho query path giúp interviewer theo dõi bạn giải thích từng bước.
  • Note latency trên arrow: Vd "→ Redis lookup ~5ms" — cho thấy bạn đã tính latency budget.
  • Đừng vẽ sạch ngay từ đầu: Bắt đầu bằng sketch đơn giản, bổ sung chi tiết khi interviewer hỏi — vẽ nhanh cho thấy tư duy live hơn là diagram đẹp đã chuẩn bị sẵn.
15

Practice Strategy

Tài Liệu Tham Khảo

  • "Designing Machine Learning Systems" (Chip Huyen, O'Reilly 2022) — Chapter 7 (Model Deployment), Chapter 8 (Data Distribution Shifts). Nền tảng tốt nhất cho ML system design interview.
  • Feast documentation (feast.dev) — Feature store concepts: offline vs online store, feature view, point-in-time join. Đọc Architecture guide.
  • XGBoost serving guide (xgboost.readthedocs.io) — Prediction API, DMatrix, model serialization.
  • Eugene Yan's blog (eugeneyan.com) — "Patterns for Production ML" series, "Real-time Recommendations" post.
  • ByteByteGo (bytebytego.com) — ML system design newsletter bổ sung.

Practice Plan

  1. Build mini-version của bài 11 (Churn Prediction project) với FastAPI serving endpoint — có experience thực tế trước khi design trên giấy.
  2. Thực hành design 3 variant: fraud detection (bài này), recommendation system, image moderation. Mỗi case có ít nhất 1 điểm khác biệt đáng kể.
  3. Mock với bạn: người hỏi interrupt sau Bước 3 để hỏi "What if Redis goes down?" — luyện defend on-the-fly.
  4. Sau mock: tự note lại phần nào còn vague về số liệu (latency, cost) để bổ sung.