Harbor

Con số cần thuộc

Bộ con số để ước lượng nhanh trong phỏng vấn: quy đổi lưu lượng theo ngày ra theo giây, độ trễ tham khảo, kích thước dữ liệu, năng lực một node cho từng thành phần, bảng số 9 của availability và một ví dụ ước lượng trọn vẹn.

13 phút đọcKhái niệm cốt lõi

Con số dùng để làm gì và vì sao quan trọng

Bước ước lượng trong phỏng vấn trả lời ba câu hỏi: hệ thống nhận bao nhiêu request mỗi giây lúc đỉnh, lưu bao nhiêu dữ liệu sau một năm, và cần bao nhiêu máy cho mỗi thành phần. Bạn không cần con số chính xác. Bạn cần đúng bậc độ lớn (10, 100, 1.000 hay 10.000 request/s) để quyết định có cần cache, có cần shard, có cần queue hay không. Grokking ch.5 viết: chọn con số không hợp lý trong các phép tính này dẫn tới thiết kế sai; ở mức thiết kế, ước lượng thô là phù hợp vì mục đích là tìm cận trên hợp lý của tài nguyên cần dùng.12

Thuộc sẵn vài con số giúp bạn:

  • Tính nhẩm trong 3–5 phút thay vì loay hoay chia số.
  • Nhận ra ngay một thiết kế vô lý, ví dụ một node Postgres nhận 200.000 ghi/giây.
  • Giải thích lựa chọn bằng số: "đỉnh khoảng 17.000 request/s, Redis một node chịu 100.000 ops/s nên một cụm nhỏ là đủ".

Người phỏng vấn đánh giá cách bạn lập luận hơn là độ chính xác. Hãy nói rõ giả định, làm tròn mạnh tay, và dùng kết quả cho một quyết định cụ thể. Mọi con số về năng lực và độ trễ trong bài là ước lượng để lập kế hoạch, cần đo lại trên hệ thống thật; Grokking cũng nói ước lượng dung lượng là bài toán khó và các tổ chức cải thiện nó dần theo thời gian, nhờ giám sát.2

Cách ước lượng: từ người dùng tới số máy

Quy trình gần như giống nhau cho mọi bài:

Đang vẽ sơ đồ…

Quy đổi lưu lượng

Một ngày có 86.400 giây (Grokking ch.5 chia cho 86.400 khi đổi request mỗi ngày ra mỗi giây).3 Làm tròn thành 100.000 để nhẩm, kết quả lệch khoảng 15%, chấp nhận được (mẹo của khoá học). Các bảng dưới là số học thuần túy từ đó.

Mỗi ngàyTrung bình mỗi giâyĐỉnh ×5
100.000~1,2~6
1 triệu~12~58
10 triệu~116~580
100 triệu~1.157~5.800
1 tỷ~11.574~58.000
10 tỷ~115.741~580.000
  • Tải đỉnh thường gấp 3–10 lần trung bình. Sự kiện mở bán vé, flash sale có thể gấp 50–100 lần trong vài phút. Hệ số ×5 và các khoảng này là giả định của khoá học.4 Grokking ch.5 dùng cách thận trọng hơn: coi mọi request của DAU đến cùng một giây để ước lượng tải đỉnh.5
  • 1 request/s đều đặn ≈ 86.400 request/ngày ≈ 2,6 triệu/tháng.
Băng thôngMỗi ngàyMỗi tháng
1 MB/s~86 GB~2,6 TB
100 MB/s~8,6 TB~260 TB
1 Gbps (~125 MB/s)~10,8 TB~324 TB

Cách đổi giữa byte và bit (nhân 8) và chia cho 86.400 giây theo Grokking ch.5, mục "Bandwidth requirements".6

Độ trễ tham khảo

Bảng của khoá học là ước lượng, cột đối chiếu với Grokking ch.5 nằm ngay sau bảng.7

Thao tácĐộ trễ
Đọc RAM~100 ns
Đọc tuần tự 1 MB từ RAM~3–10 µs
Đọc ngẫu nhiên SSD NVMe~20–100 µs
Đọc tuần tự 1 MB từ SSD~0,2–1 ms
Round trip trong cùng data center~0,5 ms
Round trip giữa hai zone trong một region~1–2 ms
Đọc Redis qua mạng nội bộ~0,5–1 ms
Truy vấn Postgres có index, dữ liệu trong RAM~1–5 ms
Seek ổ HDD~5–10 ms
Round trip Việt Nam – Singapore~30–50 ms
Round trip Việt Nam – Mỹ~150–250 ms

Bảng của Grokking ch.5 có cùng thứ tự độ lớn: tham chiếu bộ nhớ chính 100 ns, round trip trong data center 500 µs, đọc 1 MB tuần tự từ SSD (~1 GB/s) 1 ms, gói tin San Francisco tới New York 71 ms.7 Redis in Action cho Redis dưới 1 ms nếu cùng máy và dưới 5 ms nếu cùng data center.8 Các dòng còn lại (NVMe, giữa hai zone, Postgres, HDD, Việt Nam – Singapore/Mỹ) là ước lượng của khoá học, cần đo lại.9 Ba hệ quả thực tế (suy luận của khoá học):

  • Gọi tuần tự cộng dồn nhanh. Một request gọi 10 truy vấn DB lần lượt tốn 10–50 ms. Gộp truy vấn hoặc gọi song song quan trọng hơn tối ưu từng truy vấn.
  • Khoảng cách địa lý thắng mọi tối ưu code. Người dùng ở Việt Nam gọi server ở Mỹ mất ít nhất 150 ms mỗi round trip, chưa tính TLS handshake thêm 1–2 round trip. Đặt server ở Singapore hoặc dùng CDN.
  • RAM nhanh hơn mạng hàng nghìn lần. Cache trong process (LRU trong Node.js) cho dữ liệu cực nóng nhanh hơn Redis, đổi lại khó đồng bộ giữa các instance.

Kích thước dữ liệu

Các kích thước dưới đây là giả định của khoá học để nhẩm. Grokking ch.5 dùng các giá trị tương tự trong ví dụ Twitter: văn bản tweet kèm metadata 250 B, ảnh 200 KB, video 3 MB.10 UUID là số 128 bit.11

Dữ liệuKích thước
Ký tự ASCII / tiếng Việt có dấu (UTF-8)1 B / 2–3 B
int / bigint, timestamp4 B / 8 B
UUID nhị phân / dạng chuỗi16 B / 36 B
Một bản ghi người dùng hoặc đơn hàng~0,5–2 KB
Tin nhắn chat kèm metadata~200 B–1 KB
Bài đăng ngắn kèm metadata~0,5–1 KB
Ảnh đại diện / thumbnail~20–100 KB
Ảnh đã nén~200 KB–2 MB
1 phút video 720p~20–40 MB
1 phút video 1080p~60–120 MB

Mẹo nhân nhanh: 1 triệu × 1 KB = 1 GB. 1 tỷ × 1 KB = 1 TB. 1 triệu × 1 MB = 1 TB. Khi ước lượng dung lượng database, nhân thêm 1,5–2 cho index và overhead (giả định của khoá học), rồi nhân hệ số replication (thường 3 với kho phân tán; Grokking ch.10 dùng n = 3 làm ví dụ và nói n là tham số cấu hình được).12

Năng lực một node cho từng thành phần

Đây là con số để lập kế hoạch, cố ý thận trọng. Khi tính số instance, cho mỗi máy chạy tối đa 60% để còn chỗ cho đỉnh bất ngờ và lúc một máy chết. Toàn bộ bảng dưới là quy tắc ước lượng của khoá học, xem bài Chọn server.13 Riêng mốc Redis một node ~100.000 ops/s khớp với Redis in Action (100.000 thao tác mỗi giây trên phần cứng gần đây) và với mốc cache server 100.000 tới 1 triệu QPS của Grokking ch.5.1415 Các số của Kafka, WebSocket, Elasticsearch không có trong sách của thư viện.16

Thành phầnCấu hìnhNăng lực lập kế hoạch (ước lượng)
API Node.js, I/O là chính2 vCPU · 4 GB~1.000 req/s (~500 req/s mỗi vCPU)
PostgreSQL4 vCPU · 16 GBvài nghìn truy vấn đơn giản có index mỗi giây, thoải mái tới ~1–2 TB
Redis1 node~100.000 ops/s
Kafka1 partition~10 MB/s hoặc vài nghìn message/s
Kafka1 broker~50–100 MB/s
WebSocket gateway2 vCPU · 4 GB~20.000–50.000 kết nối ít hoạt động
Elasticsearch8 vCPU · 32 GBshard 10–50 GB mỗi shard

Công thức số instance cho tầng API:

instances = max(2, ceil(QPS đỉnh / 600))

600 là 1.000 req/s × 60%. Tối thiểu 2 để deploy hay hỏng một máy không gây downtime.

Công thức RAM cho Redis:

RAM = số item × (key + value + ~100 B) × 1,3

Grokking ch.5 dùng các mốc khác: khoảng 8.000 request/s mỗi server (suy ra từ server 72 luồng, request CPU-bound 200 ms, memory-bound 50 ms, rồi lấy trung bình), MySQL khoảng 1.000 QPS, kho key-value khoảng 10.000 QPS, cache server 100.000 tới 1 triệu QPS; sách lưu ý các số này xấp xỉ và đổi nhiều theo loại query, cấu hình máy, thiết kế và index.315 Hãy coi đó là mức trần tham khảo. Khóa này dùng số thận trọng hơn cho API để số máy sát với thực tế chạy Node.js có gọi database. Chi tiết chọn loại máy nằm ở bài Chọn server, và bạn có thể thử số trong Máy tính hạ tầng.

Availability: bảng số 9

Availability thường được nói bằng số chữ số 9: Grokking ch.4 định nghĩa availability là tỷ lệ thời gian dịch vụ chạy trên tổng thời gian, và có bảng "The Nines of Availability".17 Bảng dưới tính theo năm 365 ngày, tháng bằng 1/12 năm, nên số tháng lệch nhẹ so với sách (sách dùng tháng 30 ngày, ví dụ 99% là 7,20 giờ mỗi tháng); các dòng năm và tháng cho 99%, 99,5%, 99,9%, 99,99%, 99,999% khớp sách, cột "mỗi ngày" và dòng 99,95% do khoá học tự tính.17

AvailabilityDowntime mỗi nămDowntime mỗi thángDowntime mỗi ngày
99%~3,65 ngày~7,3 giờ~14,4 phút
99,5%~1,83 ngày~3,65 giờ~7,2 phút
99,9%~8,76 giờ~43,8 phút~1,44 phút
99,95%~4,38 giờ~21,9 phút~43 giây
99,99%~52,6 phút~4,4 phút~8,6 giây
99,999%~5,26 phút~26 giây~0,86 giây

Hai phép tính cần biết (phép tính xác suất cơ bản của khoá học, không phải đoạn trích từ sách):18

  • Nối tiếp: request đi qua các thành phần lần lượt, availability nhân với nhau. Load balancer, API, database mỗi cái 99,9% thì cả chuỗi khoảng 99,7%, tức gần 26 giờ downtime mỗi năm.
  • Song song: có bản dự phòng độc lập, chỉ hỏng khi tất cả cùng hỏng. Hai replica mỗi cái 99% thì 1 - 0,01 × 0,01 = 99,99%.

Mỗi số 9 thêm vào thường tốn gấp nhiều lần: 99,9% làm được với một region và failover tự động, 99,99% cần nhiều zone, deploy không downtime và giám sát tốt, 99,999% thường cần nhiều region (nhận xét thực hành của khoá học; Grokking ch.16 cũng nói tăng availability bằng cách tách replica sang nhiều data center phải đánh đổi consistency).1918 Với 4,4 phút mỗi tháng, một lần rollback thủ công đã dùng hết ngân sách.

Ví dụ ước lượng trọn vẹn

Đề: một ứng dụng chia sẻ ảnh, 10 triệu DAU. Giả định mỗi người gọi khoảng 30 API mỗi ngày, trong đó 20 lần tải feed. 10% người dùng đăng 1 ảnh mỗi ngày. Đỉnh gấp 5 lần trung bình. Toàn bộ là giả định của khoá học; cách tính theo trình tự của Grokking ch.5 (DAU × request ÷ 86.400, chia cho RPS một server, dung lượng = số bản ghi × kích thước, băng thông = dữ liệu ÷ 86.400 × 8), với các hệ số 600 req/s, ×1,3 của Redis từ quy tắc ước lượng của khoá học.310613

1. Lưu lượng

  • Tổng request: 10 triệu × 30 = 300 triệu/ngày ≈ 3.500 req/s trung bình, đỉnh ≈ 17.400 req/s.
  • Tải feed: 10 triệu × 20 = 200 triệu/ngày ≈ 2.300/s, đỉnh ≈ 11.600/s.
  • Đăng ảnh: 1 triệu/ngày ≈ 12/s, đỉnh ≈ 60/s. Luồng ghi rất nhẹ, luồng đọc là chính.

2. Tầng API

  • ceil(17.400 / 600) = 29 instance 2 vCPU · 4 GB, thêm dự phòng thành khoảng 30–32 instance, chia đều 2–3 zone.

3. Cache

  • Mỗi lần tải feed khoảng 2 thao tác Redis (lấy danh sách ID, lấy nội dung bài), đỉnh ≈ 23.000 ops/s. Một node Redis đủ về throughput.
  • RAM cho feed đã tính sẵn: mỗi user giữ 200 post ID × 8 B = 1.600 B. 10 triệu × (20 + 1.600 + 100) × 1,3 ≈ 22 GB.
  • Cache bài đăng 2 ngày gần nhất: 2 triệu × (20 + 1.000 + 100) × 1,3 ≈ 3 GB.
  • Tổng khoảng 25 GB: Redis Cluster 3 primary × 16 GB, mỗi primary 1 replica. Throughput một node đã đủ, ta chia 3 để giới hạn RAM mỗi node và chịu lỗi tốt hơn.

4. Lưu trữ

  • Metadata: 1 triệu × 1 KB = 1 GB/ngày ≈ 365 GB/năm, nhân 1,5 cho index ≈ 550 GB/năm. Một node Postgres 4–8 vCPU giữ được khoảng 2 năm, sau đó tính partition theo thời gian hoặc shard theo user.
  • Ảnh: 1 triệu × 1 MB (gồm bản gốc nén và vài kích thước) = 1 TB/ngày ≈ 365 TB/năm. Chỉ object storage hợp lý ở mức này.

5. Băng thông

  • Mỗi lần tải feed hiển thị khoảng 10 thumbnail × 50 KB = 500 KB. 200 triệu × 0,5 MB = 100 TB/ngày ≈ 1,16 GB/s ≈ 9,3 Gbps trung bình, đỉnh khoảng 46 Gbps.
  • Kết luận: bắt buộc dùng CDN. Server gốc chỉ phục vụ phần cache miss (suy luận của khoá học). Grokking ch.5 cũng nêu blob storage cho video đã mã hóa và nói dữ liệu loại này cần kho riêng, khớp với việc đặt ảnh vào object storage ở bước 4.20

6. Tổng kết để nói với người phỏng vấn

TầngƯớc lượngQuyết định
API~17.400 req/s đỉnh~30 instance 2 vCPU · 4 GB, autoscale
Redis~23.000 ops/s, ~25 GBCluster 3 primary + 3 replica
Postgres~60 ghi/s, ~550 GB/năm1 primary + replica đọc, partition sau 1–2 năm
Ảnh~1 TB/ngàyObject storage, lifecycle sang lớp rẻ
Egress~9 Gbps trung bìnhCDN

Sai lầm hay gặp

Sai lầm hay gặp: Tính xong rồi bỏ đó. Mỗi con số phải dẫn tới một quyết định: cần cache không, cần shard không, cần CDN không. Một con số không dùng tới chỉ tốn thời gian phỏng vấn.

  • Quên tải đỉnh. Thiết kế cho trung bình 3.500 req/s sẽ sập lúc 8 giờ tối.
  • Nhầm bit và byte. 1 Gbps chỉ khoảng 125 MB/s.
  • Quên replication và index khi tính dung lượng. 1 TB dữ liệu thô với RF = 3 và index có thể thành 4–6 TB đĩa.
  • Dùng số trần làm số lập kế hoạch. "Một server chịu 8.000 req/s" là mức trần cho request đơn giản. Sách nói thẳng đây là xấp xỉ bỏ qua disk seek, độ trễ database, loại query và sự cố.3 Với API Node.js có gọi database, lập kế hoạch ở mức thấp hơn nhiều (quy tắc của khoá học).13
  • Tính quá chi tiết. Không cần 86.400 chính xác, không cần 3 chữ số thập phân. Làm tròn và nói rõ đã làm tròn (Grokking cũng chỉ lấy "khoảng" 115K, 8.000).3
  • Hứa 99,999% mà chỉ có một region. Một sự cố region đã vượt ngân sách downtime của cả năm: bảng nines cho 99,999% chỉ khoảng 5,26 phút mỗi năm.17

Mẹo: Viết các giả định thành một dòng trên bảng trắng trước khi tính, ví dụ "10M DAU, 30 req/ngày, đỉnh ×5, ảnh 1 MB". Người phỏng vấn có thể chỉnh giả định mà không phải nghe lại cả phép tính.

Khi nào nhắc tới trong phỏng vấn

Bước ước lượng xuất hiện trong mọi bài, nhưng mỗi bài có một con số quyết định (tóm tắt của khoá học; ví dụ tương ứng trong Grokking ch.5 là Twitter-like với 500 triệu DAU):3

BàiCon số quyết định
URL shortenerTỷ lệ đọc/ghi khoảng 100:1, dung lượng mapping sau 5 năm
News feedQPS đọc feed lúc đỉnh, RAM cho feed đã tính sẵn
ChatSố kết nối đồng thời, số gateway WebSocket
YouTubeDung lượng video mỗi ngày, băng thông egress
Đặt vé sự kiệnĐỉnh ×50–×100 khi mở bán, kích thước hàng đợi
Flash saleRequest mỗi giây trong vài phút đầu, ops/s trên Redis
Gọi xeSố cập nhật vị trí mỗi giây từ tài xế
Metrics monitoringSố điểm dữ liệu mỗi giây, dung lượng sau downsample
Ad click aggregatorClick mỗi giây, số partition Kafka
DropboxTổng dung lượng người dùng, băng thông đồng bộ

Đọc tiếp: Khung trả lời để biết bước ước lượng nằm ở đâu trong buổi phỏng vấn, Chọn server và Hạ tầng theo quy mô để biến số thành sơ đồ hạ tầng.

Nguồn trích dẫn

  1. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · mục "Why do we use back-of-the-envelope calculations?". ↩

  2. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · bài "Examples of Resource Estimation", mục "Number of servers required" (các điểm 1 và 2 và Note cuối bài "Put Back-of-the-envelope Numbers in Perspective"). ↩ ↩2

  3. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · mục "Requests estimation" và bài "Examples of Resource Estimation", mục "Number of servers required". ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  4. Giả định của khoá học: hệ số đỉnh ×3–×10 và ×50–×100 là giả định để nhẩm, cần thay bằng số liệu thật của hệ thống. ↩

  5. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · bài "Examples of Resource Estimation", mục "Number of servers required" (giả định mọi request đến cùng một giây). ↩

  6. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · bài "Examples of Resource Estimation", mục "Bandwidth requirements". ↩ ↩2

  7. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · mục "Standard numbers to remember", bảng "Important Latencies". ↩ ↩2

  8. Redis in Action · ch.2 · §2.3 Web page caching (tr. 31): Redis dưới 1 ms nếu cùng máy, dưới 5 ms nếu cùng data center. ↩

  9. Ước lượng của khoá học, cần đo lại trên hệ thống thật. ↩

  10. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · bài "Examples of Resource Estimation", mục "Storage requirements". ↩ ↩2

  11. Grokking Modern System Design · ch.12 Sequencer · bài "Design of a Unique ID Generator", mục "First solution: UUID" (UUID là số 128 bit). ↩

  12. Grokking Modern System Design · ch.10 Key-value Store · bài "Ensure Scalability and Replication", mục "Data replication" (n là tham số cấu hình, ví dụ n = 3). ↩

  13. Quy tắc ước lượng của khoá học, xem bài Chọn server. ↩ ↩2 ↩3

  14. Redis in Action · ch.6 · §6.2.2 Simple locks (tr. 120–121): Redis làm được 100.000 thao tác mỗi giây trên phần cứng gần đây. ↩

  15. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · mục "Standard numbers to remember", bảng "Important Rates". ↩ ↩2

  16. Chưa có nguồn trong thư viện: năng lực một node của Kafka, WebSocket gateway, Elasticsearch không có trong các sách của thư viện; giữ lại như số lập kế hoạch, cần load test. ↩

  17. Grokking Modern System Design · ch.4 Non-functional System Characteristics · bài "Availability", mục "Measuring availability", bảng "The Nines of Availability". ↩ ↩2 ↩3

  18. Lý thuyết · Availability: A = thời gian chạy ÷ tổng thời gian = MTBF ÷ (MTBF + MTTR). Các thành phần nối tiếp (hỏng một cái là hỏng cả chuỗi) và hỏng độc lập thì nhân với nhau: A = A1 × A2 × A3; ví dụ 99,99% × 99,5% × 99,95% ≈ 99,44%. Chạy song song n bản độc lập thì cả hệ thống chỉ hỏng khi cả n cùng hỏng: A = 1 − (1 − p)^n; ví dụ p = 99,5%, n = 2 cho 1 − 0,005² = 99,9975%. Hai công thức giả định các lần hỏng độc lập; lỗi chung như cùng zone hoặc cùng đợt deploy làm kết quả thực tế thấp hơn. ↩ ↩2

  19. Grokking Modern System Design · ch.16 Distributed Cache · bài "Evaluation of a Distributed Cache Design", mục "High availability". ↩

  20. Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations · mục "Types of data center servers" → "Storage servers" (YouTube dùng blob storage cho video đã mã hóa). ↩