← Quay lại Trang Chủ Blog
Thiết Kế Hệ Thống

Thiết Kế Hệ Thống: Từ Một Server Đến Triệu Người Dùng

3 tháng 8, 2026 · Lộ trình 18 bài học · Read in English

Hai track song song: thấy được và chạy thật

Phần lớn tài liệu System Design dạy bằng sơ đồ tĩnh và câu chữ: "thêm cache để giảm tải", "dùng load balancer để scale ngang". Vấn đề là những thứ quan trọng nhất của hệ phân tán — độ trễ hàng đợi, replication lag, cascade failure, cái giá của một network hop — đều là hành vi động. Sơ đồ chỉ gợi ý được; muốn hiểu thì phải thấy nó xảy ra, và muốn tin thì phải tự đo.

Vì vậy mỗi bài trong series này có hai track chạy song song:

  • Track "Thấy" — mô phỏng ngay trên trang. Kéo thanh RPS và xem p99 dựng đứng, giết một replica và xem hàng đợi dồn sang node còn lại, bật retry không jitter và xem hệ thống tự đánh sập mình. Không cần cài gì.
  • Track "Chạy thật" — lab Docker trên máy bạn. nginx, app Node, Redis, PostgreSQL thật; bạn tự chạy tải và đọc số đo của chính máy mình. Mọi con số trong bài học đều lấy từ đây, không có con số nào được bịa.
🔬 Vì sao phải có track chạy thật?
Một ví dụ có thật từ chính lab này. Câu "handler đồng bộ chặn event loop nên làm chậm request khác" ai cũng đọc qua rồi. Nhưng khi đo thật trên một app giới hạn 1 CPU, endpoint /fast tụt từ khoảng 29.000 req/s xuống 116–137 req/s và p99 nhảy từ 0,71 ms lên khoảng 160 ms — sụp 200–250 lần (đo lặp 3 lần). Con số đó thay đổi cách bạn viết code theo cách mà một câu văn không làm được.
🏗️

Về Series này

Xương sống track mô phỏng là một lõi mô phỏng sự kiện rời rạc tự viết (sysdesign-sim-engine.js) — đã được đối chiếu với lý thuyết hàng đợi M/M/1 và định luật Little, sai số dưới 4% ở mọi mức tải. Bạn có thể tự kiểm bằng node sysdesign-engine-selftest.mjs (42 mục kiểm chứng). Cột mốc trung tâm là Traffic Lab: dựng topology, kéo tải, tiêm sự cố và xem hệ thống suy thoái hay sụp hoàn toàn.

🧪 Traffic Lab — thử ngay không cần cài gì
Kéo thanh RPS lên và quan sát p99: độ trễ không tăng tuyến tính theo tải mà bùng nổ khi mức chiếm dụng tiến tới 100%. Đây là hiện tượng quan trọng nhất của cả series và cũng là thứ khó tin nhất nếu chỉ đọc.

Mở Traffic Lab →

Trước khi bắt đầu

📚 Điều kiện tiên quyết
Bắt buộc: biết JavaScript ở mức đọc hiểu code Node cơ bản (nếu chưa, xem Series JavaScript).
Nên có: Series SQL — phần index, query plan và transaction/ACID được dùng lại ở Bài 7–9; Series Git cho phần quy trình deploy ở Bài 15–17.
Cho track chạy thật: Docker + Docker Compose v2. Nếu chưa có Docker, bạn vẫn học được toàn bộ track mô phỏng — nhưng sẽ mất phần đáng giá nhất là tự đo số thật.
🕳️ Cạm bẫy ngay từ bước dựng lab
Nếu bạn dùng máy Apple Silicon mà image Docker đang là linux/amd64, container sẽ chạy qua tầng giả lập: chậm nhiều lần và độ trễ nhiễu nặng. Docker chỉ in một dòng cảnh báo mờ nhạt rồi vẫn chạy, nên rất dễ lọt — và khi đó mọi số đo về sau đều vô nghĩa. Bài 2 có bước tiền kiểm bắt buộc cho việc này.

Bảng thuật ngữ nền tảng (Glossary)

Các thuật ngữ dưới đây xuất hiện xuyên suốt 18 bài, nên ghi nhớ trước sẽ đọc nhẹ hơn nhiều:

Thuật ngữ Nghĩa trong series này
Latency Thời gian phục vụ một request. Khác throughput — và tối ưu cái này thường làm hại cái kia.
Throughput Số request phục vụ được trong một đơn vị thời gian (req/s).
p50 / p95 / p99 Phân vị latency. p99 = 99% request nhanh hơn giá trị này. Con số trung bình che mất phần đuôi, nên p99 mới phản ánh trải nghiệm tệ nhất mà người dùng thực sự gặp.
Utilization (ρ) Tỉ lệ chiếm dụng của một tài nguyên, ρ = λ/μ. Khi ρ tiến tới 1, độ trễ tiến tới vô cùng — không phải tuyến tính.
Little's Law L = λ·W. Số request đang nằm trong hệ bằng tốc độ đến nhân thời gian mỗi request nằm trong hệ. Dùng để ước lượng số worker và kích thước connection pool.
Backpressure Cơ chế báo ngược lên phía trên khi hệ đã quá tải, thay vì âm thầm nhận thêm rồi xếp hàng vô hạn.
Cache hit ratio Tỉ lệ request được cache trả lời. Nâng từ 90% lên 99% giảm tải phía sau 10 lần, không phải 10%.
Replication lag Khoảng thời gian replica chưa bắt kịp primary. Hệ quả người dùng thấy được: ghi xong đọc lại ra dữ liệu cũ.
Consistent hashing Cách gán key cho node sao cho thêm/bớt một node chỉ phải di trú ~1/N số key, thay vì gần như toàn bộ như hash % N.
Idempotency Tính chất "lặp lại không đổi kết quả". Đây là điều kiện để retry an toàn, và là cách duy nhất tạo ra hiệu ứng exactly-once.
Cascade failure Sự cố lan truyền: một dependency chậm làm cạn connection pool của caller, rồi lan ngược lên toàn hệ thống — thường do retry khuếch đại.
SLI / SLO / error budget Chỉ số đo từ góc người dùng / mục tiêu có số / ngân sách lỗi được phép tiêu. Dùng để điều tiết tốc độ ship tính năng.

Lộ trình 18 bài học

Thứ tự đã được sắp theo chuỗi phụ thuộc: mỗi bài chỉ dùng khái niệm đã dạy ở các bài trước nó. Vài mắt xích cố ý đặt như vậy — idempotency trước message queue (vì at-least-once tất yếu sinh trùng lặp), và microservices đặt gần cuối (chỉ đánh giá đúng đánh đổi sau khi đã tự trả giá cho network hop, lock phân tán và nhất quán cuối). Các bài sẽ được mở khoá dần khi xuất bản.

Chặng 1 — Nền tảng đo lường
01

Latency, Throughput & Lý Thuyết Hàng Đợi

Tail latency và vì sao p99 mới là con số thật; bậc độ lớn latency từ L1 cache tới RTT liên lục địa; Little's Law; vì sao ở ρ = 0,7 thời gian chờ trong hàng đợi đã gấp 2,3 lần thời gian phục vụ. Demo: Traffic Lab một node với đường lý thuyết vẽ chồng lên số mô phỏng.

02

Dựng Lab & Đo Giới Hạn Một Server

Vòng đời request qua kernel queue → libuv → event loop; handler blocking và cái giá thật của nó; đo cho đúng (warm-up, coordinated omission, đừng tranh CPU với server); tìm knee point. Lab: dựng stack Docker dùng cho cả series.

Chặng 2 — Scale tầng stateless
03

Scale Ngang & Load Balancing

L4 vs L7; Round Robin / Least Connections / Random of two choices; health check chủ động vs thụ động; đo thật cho thấy graceful shutdown không đổi gì với request ngắn nhưng giảm đuôi latency 2,9 lần với request dài; cái giá của sticky session.

04

Reverse Proxy & API Gateway

Ba khái niệm bị dùng lẫn là ba mức trách nhiệm; TLS tốn ~10% khi có keep-alive nhưng 5,6 lần khi không; vì sao không được tin X-Forwarded-For do client gửi; phép đo file tĩnh đi ngược dự đoán; aggregation song song 208 ms so với tuần tự 386 ms; gateway là single point of failure.

05

Caching: Cache-Aside, TTL & Vô Hiệu Hoá

Mỗi số 9 thêm vào hit ratio là một lần chia 10 tải database; đo thật cho thấy tụt 4 điểm hit ratio làm p99 nhảy 9,4 lần trong khi p50 không đổi; bốn mẫu cache; TTL vs xoá tường minh vs key có version; single-flight giảm 20 lần truy vấn DB nhưng lại làm p50 tệ hơn; thiết kế cache key sai làm hit ratio về 0.

06

CDN & Edge Caching

Tốc độ ánh sáng là giới hạn cứng không code nào vượt được; tầng edge đo được 25 lần throughput với origin chỉ xử lý 4 trong 208.173 request; no-cache vẫn cache; ETag304; trả bản cũ khi origin sập — và giới hạn của nó; cache key chứa tham số theo dõi làm tải origin tăng 251 lần mà mọi số liệu phía client không đổi.

Chặng 3 — Tầng dữ liệu
07

Replication & Scale Tầng Đọc

Ba mục đích của replica cần ba cấu hình khác nhau; từ async lên sync độ trễ ghi tăng 79% và throughput ghi giảm 44%; đo thật cho thấy lag chỉ 0,557 ms vẫn phá vỡ read-your-writes trong 87,21% lệnh đọc; hai bản vá đều cho 0% với giá 4,6% và 12,6% throughput; split-brain tái tạo thật bằng pg_promote.

08

Sharding & Consistent Hashing

Vì sao shard là bước cuối; modulo hashing từ 4 lên 5 shard buộc 79,97% dữ liệu di trú, consistent hashing chỉ 18,78%; không có virtual node thì một shard nhận 66 key còn shard khác nhận 25.465; shard key lệch có p50 và p95 tốt hơn nhưng p99 tệ hơn 10,3 lần.

09

CAP & Các Mô Hình Nhất Quán

P không phải lựa chọn; PACELC là phần bạn gặp hằng ngày; phổ nhất quán kèm giá đo được; R+W>N cho đúng 0 lần đọc ra bản cũ còn R+W=N vẫn cho 33%; LWW mất dữ liệu âm thầm khi đồng hồ lệch 50 ms; partition thật làm request đầu treo 30 giây.

10

Distributed Lock

Lock cho hiệu quả khác lock cho đúng đắn; đo thật cho thấy lock đúng chuẩn nhưng TTL ngắn hơn thời gian xử lý cho 79/80 xung đột — tệ hơn cả không dùng lock; GC pause dài hơn TTL cho 31/80 mà Redis không hề sai; fencing token ngăn thiệt hại chứ không ngăn xung đột.

Chặng 4 — Giao tiếp & tin cậy
11

Idempotency & Retry An Toàn

Exactly-once là ảo tưởng — bài toán hai vị tướng; idempotency key cho ý định chứ không cho lần thử; dedup và nghiệp vụ phải cùng một transaction; đo thật 78.774 request đồng thời cùng một key cho đúng 1 bản ghi và 1 mã 201, tắt đi thì 14.236 bản ghi và số dư âm.

12

Message Queue & Xử Lý Bất Đồng Bộ

Ack sai thời điểm làm mất 352 job không dấu vết — số job mất tối đa đúng bằng kích thước prefetch; poison message không chặn queue trong Redis Streams mà tồn đọng âm thầm; gấp bốn consumer chỉ nhanh 2,68 lần; queue depth là chỉ số sức khoẻ số một.

13

Rate Limiting & Backpressure

Fixed window cho lọt 200 request/giây khi hạn mức là 100 — đo được ở mốc giao cửa sổ; bốn thuật toán chênh nhau không đáng kể về tốc độ nhưng hơn 10 lần về bộ nhớ; INCR rồi EXPIRE tách rời làm 20/200 khoá kẹt vĩnh viễn; ba replica dùng chung script Lua giữ hạn mức toàn cục sai 0,13%.

14

Event Sourcing & CQRS

Projection không idempotent chạy lại lần hai cho số dư gấp đúng 2,00 lần mà không một cảnh báo nào; replay 200.000 sự kiện mất 235 ms nên sửa bug rồi dựng lại là việc trong giờ hành chính; snapshot nhanh 6,6 lần với aggregate dài nhưng chậm hơn với aggregate ngắn.

Chặng 5 — Kiến trúc & vận hành
15

Monolith vs Microservices

Cùng use case bốn bước: monolith p99 2,06 ms · 18.887 req/s, microservices 8,25 ms · 3.744 req/s; độ khả dụng nhân dồn đo được khớp công thức trong 0,1 điểm phần trăm; saga thiếu hành động bù để lại 200 đơn đã thu tiền và 0 lần giữ hàng.

16

Observability: Metrics, Logs & Tracing

Với sự cố làm 1% request chậm 300 ms, p99 đo được là 0,90 ms — hoàn toàn mù, phải tới p99,9 mới thấy 474 ms; thêm đúng một nhãn user_id làm số chuỗi thời gian nhảy từ 2 lên 49.317; quên truyền correlation ID không làm bạn thiếu dữ liệu mà làm bạn có dữ liệu SAI — 100% thời gian bị quy cho service vô tội.

17

Chế Độ Lỗi & Khả Năng Chống Chịu

Chuỗi ba tầng mỗi tầng thử lại ba lần biến 30 request thành 810 lần đập vào service tận cùng; retry budget kéo xuống 69; backoff không jitter dồn cục gấp 19,6 lần còn có jitter chỉ 5,3 lần và lại xong sớm hơn; timeout đặt sai chỗ khiến server làm trọn 50.000 ms công toi mà dashboard vẫn xanh.

Chặng 6 — Dự án tổng kết
18

Capstone: Thiết Kế & Chạy Thật Một Hệ Thống

Ghép cả 17 bài thành hệ rút gọn URL chạy thật: throughput ×4,2 và p99 tốt hơn 11,5 lần. Nhưng cache — tối ưu ai cũng nghĩ tới đầu tiên — xoá 99% truy vấn đọc mà chỉ tăng 16% throughput; còn read replica, hợp lý trên mọi sơ đồ, cho đúng 0%.

Series liên quan

Series này giao với vài series khác trên blog, và có thể học chéo: SQL trong Trình duyệt (index, query plan, transaction/ACID — nền cho Bài 7–9), Cơ Sở Dữ Liệu Vector (chỉ mục & phân cụm, và chính bài toán sharding), Kỹ Thuật Hệ Thống AI (orchestration, blackboard, deadlock — cùng họ vấn đề với Bài 15–17).

Bình luận