Nền tảng Cơ bản 6 phút đọc

Toán ước lượng nhanh cho thiết kế hệ thống

Cách ước lượng QPS, storage, băng thông, ngân sách độ trễ trên bảng trong hai phút. Những con số mọi phỏng vấn system design và planning capacity đều tái dùng.

Mục lục
  1. Khi nào toán ước lượng nhanh thật sự cứu bạn?
  2. Bốn con số nào estimate nào cũng phải có?
  3. Cần ghi nhớ hằng số tròn nào?
  4. Estimate 30 giây trên bảng diễn biến ra sao?
  5. Trong planning capacity .NET trông ra sao?
  6. Estimate back-of-envelope sai ở đâu?
  7. Khi nào nên bỏ qua back-of-envelope và đo trực tiếp?
  8. Đi tiếp đâu từ đây?

Một engineer kỳ cựu trong phỏng vấn system design nhận đề "thiết kế Twitter". Họ cầm bút, viết một cột bốn số - 100M DAU, 50K QPS, 200 TB/năm, p99 < 100 ms - và phần còn lại của cuộc nói chuyện chảy từ đó. Cột số đó là toán ước lượng nhanh, và kỷ luật đứng sau nó là điều chương này dạy.

Khi nào toán ước lượng nhanh thật sự cứu bạn?

Ba tình huống.

Một, mở đầu phỏng vấn. Người phỏng vấn kỳ vọng bạn ước lượng tải trước khi vẽ hộp. Bỏ qua estimate báo hiệu bạn không biết kiến trúc nào là quá liều. Hai phút số học cho bạn quyền đề xuất thiết kế "buồn tẻ" chỉ Postgres, hoặc bảo vệ một cluster Cassandra shard.

Hai, planning capacity ở chỗ làm. Trước khi spin tier database production, bạn nợ team câu trả lời "lớn cỡ nào". Đoán quá là phí tiền; đoán thiếu là sự cố 3 giờ sáng. Toán này gọn trong một thread Slack.

Ba, review kiến trúc. Ai đó đề xuất Kafka cho event stream. Có xứng không? Ước lượng QPS - nếu là 10/s thì không. Nếu 100K/s thì có. Estimate kết thúc tranh luận.

Bốn con số nào estimate nào cũng phải có?

Mọi bài tập back-of-envelope rút gọn thành cùng bốn con số, vì chúng map sang cùng bốn dòng chi phí trên hoá đơn cloud:

QPS và storage là quan trọng nhất; băng thông và latency xác nhận thiết kế sau đó.

Cần ghi nhớ hằng số tròn nào?

Thuộc một lần và đừng tính lại nữa:

THỜI GIAN
1 ngày            ~ 100,000 giây   (thực 86,400, làm tròn lên cho biên)
1 tháng           ~ 30 ngày        ~ 2.5M giây
1 năm             ~ 30M giây

DỮ LIỆU
1 row text nhỏ        1 KB         (tweet, comment, log line)
1 thumbnail           50 KB
1 ảnh                 500 KB
1 video ngắn          10 MB
1 row trong users     200 bytes

MẠNG
LAN round-trip        0.5 ms
Cross-AZ round-trip   1-2 ms
Cross-region          50-150 ms
Internet round-trip   10-200 ms

ĐĨA / BỘ NHỚ
RAM read             100 ns
SSD random read      100 µs
SSD sequential       300 MB/s
HDD random read      10 ms
HDD sequential       100 MB/s

QUY MÔ CPU
1 core hiện đại      100K-1M op đơn giản/giây
1 ASP.NET Core box   ~10K QPS đơn giản, ~1K với query EF Core
1 node Postgres      5K-20K write/giây, 30K-100K read/giây
1 node Redis         100K-1M op/giây
1 broker Kafka       ~1M msg/giây ở cấu hình mặc định

Đây là số tròn rộng tay; đo thực thường nằm trong 2x. Mẹo 100K giây/ngày là hữu ích nhất: 1000 RPS thành 100M req/ngày trong đầu không cần máy tính.

Estimate 30 giây trên bảng diễn biến ra sao?

Lấy Twitter làm ví dụ kinh điển. Người phỏng vấn nói "100M DAU, thiết kế timeline". Dòng chảy trong đầu:

flowchart LR
    DAU[100M DAU] --> QPS[QPS đỉnh<br/>= 100M / 100k s<br/>* 5 hệ số đỉnh<br/>= 5K req/s read<br/>= 500 req/s write]
    QPS --> Storage[Storage<br/>= 500 write/s<br/>* 100k s/ngày<br/>* 1 KB<br/>* 365 ngày<br/>= 18 TB/năm]
    Storage --> BW[Băng thông<br/>= 5K read/s<br/>* 50 KB tweet+meta<br/>= 250 MB/s out]
    BW --> Lat[Latency<br/>p99 100 ms<br/>= 50ms cache<br/>+ 30ms net<br/>+ 20ms render]

Đó là ngân sách 30 giây. Phần còn lại của cuộc trò chuyện - database nào, shard ra sao, cache như thế nào - đều dẫn ngược về bốn số này. Nếu ai đề xuất một node Postgres duy nhất, bạn nói "500 write/s thì một máy chịu được nhưng 18 TB/năm bắt phân vùng theo năm" và thiết kế tự ra.

Trong planning capacity .NET trông ra sao?

Chuyển sang đô la bằng cách đi ngược từ các số ở trên. Giả sử bạn thiết kế chương URL shortener:

// Workload ước lượng, đặt thành hằng để test sanity-check:
public static class CapacityEstimate
{
    public const int    DailyShortens     = 1_000_000;       // 1M URL mới/ngày
    public const int    DailyRedirects    = 100_000_000;     // 100M read/ngày (read/write 100:1)
    public const int    PeakRedirectsPerSec = DailyRedirects / 100_000 * 5; // 5K req/s đỉnh
    public const int    AvgUrlBytes       = 200;             // short + long + meta
    public const long   StorageOneYearGb  = (long)DailyShortens * 365 * AvgUrlBytes / 1_000_000_000; // 73 GB
    public const int    CacheHitRatePct   = 90;              // 1% URL hot phục vụ 90% read
    public const int    DbReadsPerSec     = PeakRedirectsPerSec * (100 - CacheHitRatePct) / 100; // 500 RPS
}

Bây giờ lựa chọn kiến trúc đã có bằng chứng:

Cả thiết kế là một Postgres + một Redis + hai web node stateless, và bạn bảo vệ được bằng số. Không có estimate, cùng bài tập sẽ ra một cơn ác mộng over-engineer Cassandra + Kafka.

Estimate back-of-envelope sai ở đâu?

Hai chế độ lỗi.

Một, workload bursty. Hệ số đỉnh 5x trong ví dụ Twitter giả định traffic theo chu kỳ ngày đêm. Nếu workload nhảy 100x cho flash sale, QPS trung bình vô nghĩa - thiết kế cho đỉnh. Chương 14 (rate limiting) cho cách chặn đỉnh khi không scale kịp để hấp thu.

Hai, storage tăng nhanh hơn tốc độ write. Ảnh, video, embedding ML - kích thước row lớn và bạn đo storage bằng byte/giây, không phải row/giây. Cập nhật hằng số là estimate dùng lại được, nhưng một service "nhỏ" với 1M user upload mỗi người 5 MB ảnh vẫn là bài toán 5 TB.

Khi nào nên bỏ qua back-of-envelope và đo trực tiếp?

Khi hệ thống đã tồn tại và bạn đang tinh chỉnh. Metric thật từ chương 13 (observability) đánh bại estimate một bậc cường độ. Nhiệm vụ của estimate là thiết kế phiên bản đầu - loại các kiến trúc rõ ràng sai - không phải cạnh tranh với telemetry. Khi hệ vào production, estimate trở thành check sanity cho dashboard, không phải nguồn sự thật.

Đi tiếp đâu từ đây?

Chương kế tiếp: CAP và consistency - bộ từ vựng thứ hai, bộ quyết định bạn dùng được một database hay phải nghĩ đến quorum. Sau đó bạn có bộ công cụ đầy đủ để bắt đầu chọn các khối xây dựng .NET cụ thể.

Câu hỏi thường gặp

Sao mấy con số này lại xấp xỉ thế?
Vì câu trả lời cần là bậc cường độ, không phải số chính xác. Quyết định 'một máy hay cluster shard' nằm giữa 100 GB và 10 TB - sai 5x cũng không nhảy biên đó. Nhiệm vụ của estimate là loại bỏ kiến trúc sai, không phải dự đoán hoá đơn.
Mấy số latency lấy ở đâu?
Bài 'Numbers Every Programmer Should Know' của Jeff Dean năm 2010, cập nhật cho SSD và 10 GbE. Số chính - 1 ns L1, 100 ns RAM, 100 µs SSD random read, 500 µs LAN round-trip, 50 ms cross-region - đứng trong khoảng hai lần suốt mười lăm năm. Đó là tiếng nói chung trong phòng họp system design.
Làm sao luyện nhanh kỹ năng này?
Chọn ba dịch vụ thật bạn dùng (Twitter, Uber, Spotify), đoán QPS hàng ngày trong 30 giây, rồi tra số công khai. Sau mười lần đoán, trực giác về 'bận' vs 'thật sự khổng lồ' sẽ được hiệu chỉnh. Phỏng vấn không cần con số chính xác; cần con số bảo vệ được.
Còn quan trọng không khi đã đo được?
Có - vì lúc thiết kế bạn chưa có gì để đo. Estimate quyết định phiên bản đầu tiên của hệ thống. Khi hệ chạy thì thay estimate bằng metric từ chương 13 (observability), nhưng kiến trúc đã đúc.