TL;DR

API phản hồi dưới 100ms không đến từ một lần tối ưu cuối sprint. Đó là kết quả của năm nguyên tắc kỷ luật được áp dụng liên tục: latency budget, async fan-out, layered caching, circuit breakersobservability bám tail. Và quan trọng hơn: kiến trúc làm ra tốc độ, nhưng chỉ văn hóa đội mới giữ được nó khi hệ thống tiếp tục phát triển.

Bài tổng hợp từ Engineering Speed at Scale (InfoQ, 2026) cùng báo cáo SRE và case study AdTech/HFT 2026.

Vì sao 100ms lại đáng để chiến đấu

Dữ liệu cũ nhưng vẫn đúng: Amazon đo được mỗi 100ms latency bằng 1% doanh số. Google từng A/B test 10 vs 30 kết quả tìm kiếm — trang 30-kết-quả chậm hơn 500ms (0.4s → 0.9s) đã làm traffic và doanh thu giảm 20%. Người dùng không đo bằng đồng hồ, họ cảm thấy. Khác biệt giữa checkout 120ms và 80ms vô hình với mắt thường, nhưng trên hàng triệu phiên nó biến thành conversion rate, abandoned cart và revenue.

Tệ hơn, latency không suy giảm đẹp đẽ — nó compound. Một dịch vụ cộng 30ms lúc bình thường sẽ cộng 60ms khi peak, 120ms khi downstream lung lay. Tail latency (p95, p99) khi đã drift sẽ âm thầm "đánh thuế" mọi service upstream phụ thuộc vào nó.

Latency budget — biến mục tiêu thành ràng buộc

Thay vì nói "API phải dưới 100ms", team cao cấp chia ngân sách ra từng chặng:

LayerBudget (ms)
Edge / CDN10
Gateway5
Service logic30
Database / Cache40
Network jitter10–15

Ngân sách biến performance từ khái niệm mơ hồ thành ràng buộc cụ thể. Mỗi feature mới phải trả lời: "Nếu cộng 20ms ở service layer, tầng nào chịu cắt bớt?" Cuộc hội thoại đó — kỹ thuật, văn hóa, tổ chức — chính là nơi hệ thống nhanh được sinh ra.

Async fan-out: song song hoá nhưng đừng giấu block

Nguyên nhân gốc của API chậm thường rất đơn giản: serial dependencies. Ba downstream call 40ms chạy tuần tự = 120ms, chưa làm gì thực sự. Parallel lại thành max(40ms, 40ms, 40ms) = 40ms.

Cảnh báo hiếm khi được nói: async không triệt tiêu blocking — nó chỉ giấu vào thread pool. Executor sai kích thước gây CPU thrashing, queue buildup, OOM, và cascading slowdown khắp fleet. Rule-of-thumb cho IO-bound: 2 × CPU cores × số parallel downstream call mỗi request, rồi tinh chỉnh bằng p95/p99 load test.

Layered caching: tránh làm lại việc đắt

Hệ thống nhanh không loại bỏ công việc — chúng tránh làm lại công việc đắt. Hierarchy điển hình:

  • Caffeine local — dưới 1ms
  • Redis — 3–5ms
  • Database — 20–60+ ms

Nhưng cache hit chỉ thắng khi dữ liệu đúng. Ba chiến lược invalidation:

  1. TTL-based — đơn giản, rủi ro stale tăng khi TTL dài
  2. Event-based — producer phát sự kiện invalidate, yêu cầu data ownership rõ
  3. Version-based keyproduct:v2:12345, bump version là vô hiệu hoá tức thì

không phải dữ liệu nào cũng được cache. PCI (card number, CVV) không cache ở đâu hết. PII cache phải encrypt + TTL ngặt. Một bảng phân loại data trước khi viết code cache sẽ tránh vi phạm compliance.

Cái bẫy ít ai nhắc: trong kiến trúc fan-out 5 call, nếu hit rate không đạt 99%+, thêm cache có thể không cải thiện p99 — chỉ một miss đẩy request về slow path là tail đã hỏng.

Circuit breakers: đừng để downstream chậm lây nhiễm tail của bạn

Downstream không cần phải chết — chỉ cần chậm bền bỉ là đủ phá tail. Mỗi request đợi → thread bị giữ → queue xếp → slowdown lan ra toàn hệ thống.

Circuit breaker (Resilience4j và tương tự) đặt ranh giới: khi lỗi/timeout vượt ngưỡng, breaker mở, traffic fail-fast dưới 1ms với fallback dự đoán được. Thông điệp: phản hồi một phần, nhanh, gần như luôn thắng phản hồi hoàn hảo nhưng muộn.

Timeout phải align với latency budget và p95/p99 của dependency. Một timeout mặc định "vài giây" đủ để huỷ diệt mục tiêu sub-100ms trong đường fan-out.

Những con số biết nói (2026)

  • Fan-out math: 5 call song song mỗi call 99% dưới 100ms → chỉ ~95% request toàn chặng dưới 100ms (0.99⁵). Muốn p99 tổng 100ms, mỗi call cần ~p99.8.
  • HFT trên AWS: một trading firm đạt p99 = 62µs, median 50µs — tail chỉ hơn 12µs sau khi disable hyper-threading, pin thread vào core, busy-wait polling.
  • AdTech edge: deploy edge service tại đúng các thành phố client → p99 ~6ms ở throughput cao (internal ~3ms), trong khi trước đó trượt mục tiêu 10ms.
  • Average lừa: log 135k request trong 10 phút, average < 50ms nhưng p99 spike ~1000ms — 1% user chịu delay 1 giây mà dashboard không hiện.
  • Cassandra + GC: hầu hết read 2ms, định kỳ stall 50ms vì garbage collection — hiện lên đúng p99.

Top những thứ giết p99 âm thầm

  • Thread pool exhaustion & "async pile-up" — triệu chứng là waiting chứ không phải CPU cao
  • Retry storm / thundering herd khi downstream chậm
  • GC pause trong runtime managed (Java/.NET/Python)
  • DB query index sai → 10ms thành 120ms, cộng với lock contention
  • Cold start serverless (500ms+)
  • Noisy neighbor trong môi trường multi-tenant
  • Payload JSON bloat — serialization đắt hơn người ta nghĩ
  • Anti-pattern: logging đồng bộ trên hot path, business logic nhồi vào API gateway, một cache khổng lồ thay cho layered, reactive programming không isolation

Bài học cô đọng: variance hại hơn speed. Dependency luôn 50ms an toàn hơn dependency dao động 10–300ms. Predictability đánh bại raw throughput.

Observability — không phải dashboard, là văn hóa

Phần lớn dashboard khoe average latency, gần như vô dụng trong hệ thống phân tán. Đo cái users thực sự cảm:

  • p50 — user điển hình
  • p95 — user hơi kém may
  • p99 — khách sắp bỏ sản phẩm nếu điều này lặp lại

Stack tối thiểu: Micrometer/Prometheus cho histogram; OpenTelemetry + Jaeger cho distributed tracing ("metrics nói bao lâu, tracing nói vì sao"); tag semantic đầy đủ (region, device, cache hit/miss, fallback triggered); instrument thread pool (active, queue size, rejection count).

SLO thực tế: p95 < 120ms rolling 30 ngày, error budget 5%. Burn-rate alert rule được dùng rộng: fire khi burn rate > 14.4 trong 10 phút — tốc độ đó sẽ đốt sạch error budget 30 ngày trong ~50 giờ, tương đương 2 ngày. Burn-rate fire sớm, ngay khi regression còn nhỏ, đủ thời gian pause rollout.

Architecture là bản vẽ, culture là động cơ

Speed tự phân rã theo thời gian: feature creep, dependency mới, traffic shift, team thay đổi. Team giữ được tốc độ dài hạn làm khác:

  • Service team sở hữu p99 SLO của endpoint mình, được page khi burn rate vượt ngưỡng
  • Design review có câu hỏi bắt buộc: "Thêm bao nhiêu hop?", "Cacheable không?", "Worst-case p99 impact?"
  • Weekly: review p99 trend + top slow trace. Monthly: SLO + error budget. Quarterly: chaos test tập trung vào tail
  • Canary release với p99 compare vs baseline, auto-rollback khi breach
  • Cache hit rate tracked như uptime
  • Mọi thay đổi đều có "performance blast radius" được ghi nhận
  • Regression nào cũng trigger blameless postmortem

Tóm lại

Sub-100ms là một lựa chọn tổ chức. Nó bắt đầu từ latency budget bạn viết ra giấy, tiếp tục qua fan-out đúng kích thước thread pool, layered cache có strategy invalidation, circuit breaker bảo vệ tail, observability đo đúng percentile. Và nó chỉ sống sót nếu team coi p99 quan trọng ngang correctness — một thói quen, không phải dự án quý.

Nguồn: InfoQ — Engineering Speed at Scale, SRE School — P99 Latency Guide 2026, Aerospike — What Is P99 Latency, Last9 — Latency is the new downtime, laud.cloud — Layered Caching 2026.