Clarify SLOs & workload
I’d confirm traffic shape (QPS (queries per second), burstiness), input sizes, and correctness/latency trade-offs (accuracy vs quantization). Aim: p50 20ms, p99 200ms for a heavy model.
High-level architecture
- Ingress → lightweight front proxy (Envoy) → request router (per-model) → inference tier (GPU/CPU/TPU pools) → response.
- Observability: latency/queue metrics, per-stage tracing.
Serving frameworks
- Consider Triton for multi-backend, batching, model versioning; TorchServe for PyTorch pipelines; BentoML for flexible pipelines. Triton’s dynamic batching and model repository help meet SLOs.
Batching / dynamic batching
- Use small fixed batch sizes for p50; enable dynamic batching with max latency budget (e.g., 5–10ms wait) to increase throughput without exceeding p99.
- Adaptive batching: adjust batch timeout based on current tail latency and queue length.
Autoscaling & warm pools
- Combine reactive autoscaling (CPU/GPU util, queue length) with predictive scaling from traffic forecasts.
- Maintain a warm pool of pre-loaded model instances (or containers) to avoid cold starts. Keep a small number of GPU-backed instances idle.
Cold-start mitigation
- Lazy-weighted routing to warm instances; lightweight fallback to smaller/quantized model for quick responses when heavy model not ready.
Model partitioning & compilation
- Use model compilation (ONNX Runtime with TensorRT/XLA) and quantization (FP16/INT8) to reduce latency.
- Consider model sharding for extremely large models (sequence parallelism or pipeline parallelism) but weigh added network latency.
Hardware
- Use GPUs for heavy models; choose A100/H100 or inference-optimized instances with Tensor Cores. For low-cost/less heavy models, CPU with AVX512 and ONNX may suffice.
Caching
- Cache recent/identical inputs and partial outputs (embedding cache) at front proxy. Use TTL and cache hit-miss metrics.
Throughput vs tail-latency trade-offs
- Larger batches maximize throughput but increase tail latency. Use hybrid strategy: benchmark batch-size vs p99, enforce max wait time, and prefer smaller batches under bursty/latency-sensitive traffic.
Monitoring & iterative tuning
- Continuously monitor p50/p99, per-batch latency, queue times. Run canary experiments for quantized/compiled models and measure accuracy-latency trade-offs.
Worked capacity example (from a folded near-duplicate): with single-request GPU compute time of 25ms at batch size 1 and a CPU fallback of 80ms/request, one GPU replica saturates at 1/0.025s = 40 requests/sec, and one CPU replica at 1/0.080s = 12.5 requests/sec. Targeting 1000 requests/sec (queries per second) while keeping utilization at roughly 60% (so bursts do not blow through the p99 target) needs about 1000/(400.6) ≈ 42 GPU replicas, versus roughly 1000/(12.50.6) ≈ 133 CPU replicas for the same throughput - a concrete illustration of why the GPU path is chosen for this SLO (service-level objective) even though a single GPU instance costs more than a single CPU instance: replica count, not raw compute, is what needs to be provisioned and paid for at this scale.