Skip to content

🎯 Mục tiêu

🎯 Sau bài này bạn sẽ nắm được:

  • Tư duy tiếp cận System Design như một Principal Architect — không phải học thuộc, mà là tư duy có hệ thống
  • 4 trụ cột thiết kế: Scalability, Reliability, Performance, Cost — và cách cân bằng chúng
  • Framework 5 bước để phân tích bất kỳ bài toán thiết kế nào
  • Triết lý trade-off: tại sao không có thiết kế hoàn hảo, chỉ có thiết kế phù hợp
  • Nhận diện và tránh 4 sai lầm phổ biến nhất khi thiết kế hệ thống

System Design Thinking — Tư duy Kiến trúc sư

Năm 2017, Airbnb có hơn 100 triệu lượt đặt phòng mỗi năm — tất cả chạy trên một monolith Ruby on Rails khổng lồ. Mỗi lần deploy mất hơn 40 phút. Một thay đổi nhỏ ở module thanh toán có thể làm sập tính năng tìm kiếm. Đội ngũ hơn 1,000 engineer push code vào cùng một codebase, merge conflict trở thành công việc hàng ngày. Chi phí vận hành tăng nhanh hơn doanh thu.

Airbnb phải mất gần 3 năm và hàng trăm engineer-years để tách monolith thành kiến trúc service-oriented. Không phải vì họ thiếu kỹ năng — mà vì thiết kế ban đầu không tính đến quy mô 100 triệu users. Bài học đau đớn nhất: chi phí redesign đắt gấp 10–100 lần chi phí design đúng từ đầu.

Đây là lý do bạn cần System Design Thinking — không phải để thiết kế hoàn hảo ngay từ đầu (điều đó bất khả thi), mà để đặt đúng câu hỏi, nhận diện đúng trade-off, và đưa ra quyết định có ý thức thay vì để hệ thống "tự phát triển" theo hướng không kiểm soát.


Bức tranh tư duy

Hãy tưởng tượng bạn là kiến trúc sư quy hoạch một thành phố mới.

Đường giao thông là network — bạn cần quyết định bao nhiêu làn xe (bandwidth), đèn giao thông đặt ở đâu (load balancer), và đường nào là cao tốc (fast path) vs đường nội thành (standard path). Hệ thống nước và điện là data flow — cần đủ áp suất cho mọi toà nhà (throughput), có máy phát dự phòng khi mất điện (redundancy), và đường ống không bị nghẽn giờ cao điểm (back-pressure). Toà nhà là services — mỗi toà có chức năng riêng (single responsibility), có cửa ra vào rõ ràng (API contracts), và có thể xây thêm tầng khi dân số tăng (scalability). Luật quy hoạch là constraints — ngân sách (cost), quy định phòng cháy (reliability requirements), giới hạn chiều cao toà nhà (technical limitations).

Không ai thiết kế cả thành phố trong một ngày. Bạn bắt đầu với master plan, rồi chi tiết hoá từng khu vực. System Design cũng vậy.

Giới hạn của analogy

Thành phố phát triển qua hàng thập kỷ, hệ thống phần mềm có thể scale trong vài giờ nhờ cloud. Nhưng nguyên tắc quy hoạch — dự tính tăng trưởng, phân vùng chức năng, hạ tầng dự phòng — hoàn toàn tương đồng.


Cốt lõi kỹ thuật

4 trụ cột thiết kế

Mọi quyết định System Design đều xoay quanh 4 trụ cột. Chúng luôn mâu thuẫn với nhau — công việc của architect là tìm điểm cân bằng phù hợp với bối cảnh cụ thể.

Trụ cộtCâu hỏi cốt lõiMetric đo lườngVí dụ thực tế
ScalabilityHệ thống xử lý được khi traffic tăng 10x không?QPS, concurrent users, data volumeNetflix xử lý 400K+ requests/giây trong giờ cao điểm
ReliabilityHệ thống có tiếp tục hoạt động khi thành phần X chết?Uptime (99.9% vs 99.99%), MTTR, MTBFAWS S3 đạt 99.999999999% durability (11 chữ số 9)
PerformanceUser có cảm nhận hệ thống nhanh không?Latency (p50, p95, p99), throughputGoogle: mỗi 100ms latency tăng → giảm 1% revenue
CostChúng ta có đủ tiền vận hành ở quy mô này không?$/request, $/GB, $/MAUStartup đốt $50K/tháng cho infra khi chưa có revenue

Không có "tối ưu cả 4"

Một hệ thống vừa scale vô hạn, vừa không bao giờ chết, vừa trả lời trong 1ms, vừa rẻ — không tồn tại. Nếu ai đó nói thiết kế của họ đạt cả 4, hãy hỏi họ đang đánh đổi gì mà chưa nhận ra.

Framework 5 bước tiếp cận System Design

Đây là quy trình mà các Principal Architect thực sự sử dụng — dù đang thiết kế hệ thống mới hay phỏng vấn System Design.

Bước 1: Clarify Requirements — "Tôi đang xây cái gì?"

Trước khi vẽ bất kỳ diagram nào, hãy hỏi cho đến khi không còn giả định. Phân biệt rõ hai loại yêu cầu:

Functional Requirements — Hệ thống làm gì:

  • User có thể đăng ảnh không?
  • Có cần hỗ trợ comments, likes?
  • Feed hiển thị theo thứ tự nào?

Non-Functional Requirements — Hệ thống làm tốt đến mức nào:

  • Latency target: p99 < 200ms hay < 50ms?
  • Availability: 99.9% (8.7 giờ downtime/năm) hay 99.99% (52 phút/năm)?
  • Data consistency: strong hay eventual?
  • Dự kiến quy mô: 10K hay 10M DAU?

Mẹo phỏng vấn

Trong phỏng vấn System Design, dành 3–5 phút đầu chỉ để hỏi requirements. Interviewer đánh giá khả năng đặt câu hỏi cao hơn khả năng vẽ diagram.

Bước 2: Back-of-Envelope Estimation — "Quy mô thực sự là bao nhiêu?"

Tính toán sơ bộ giúp bạn loại bỏ những thiết kế không khả thi trước khi đầu tư thời gian chi tiết. Ba con số cần ước lượng:

QPS (Queries Per Second):

10M DAU × 5 actions/user/ngày = 50M actions/ngày
50M / 86,400 giây ≈ 580 QPS (trung bình)
Peak = 3× trung bình ≈ 1,740 QPS

Storage:

50M posts/ngày × 1 KB/post = 50 GB/ngày
× 365 ngày × 3 năm = ~55 TB

Bandwidth:

1,740 QPS (peak) × 2 KB/response = ~3.5 MB/s outbound

Những con số này quyết định bạn cần 1 server hay 100 server, SQL hay NoSQL, cache hay không cache.

Bước 3: High-Level Design — "Các mảnh ghép là gì?"

Vẽ ra các thành phần chính và cách chúng giao tiếp. Ở bước này, chưa cần chi tiết — chỉ cần đúng các building blocks.

Checklist cho high-level design:

  • Mỗi component có chức năng rõ ràng không?
  • Data flow từ client đến storage có hợp lý không?
  • Có single point of failure nào không?
  • Đọc-ghi tách biệt chưa? (read-heavy vs write-heavy khác nhau hoàn toàn)

Bước 4: Deep Dive — "Bottleneck nằm ở đâu?"

Chọn 1–2 component quan trọng nhất để thiết kế chi tiết. Tập trung vào:

  • Database schema và indexing strategy
  • Caching layer — cache gì, TTL bao lâu, invalidation ra sao
  • Sharding strategy — shard theo user_id hay timestamp?
  • Failure scenarios — điều gì xảy ra khi component X chết?

Đây là nơi phân biệt junior và senior engineer. Junior vẽ diagram đẹp. Senior tìm ra điểm sẽ gãy đầu tiên khi traffic tăng.

Bước 5: Trade-off Discussion — "Tại sao chọn A, không chọn B?"

Mỗi quyết định thiết kế là một trade-off. Architect giỏi không phải người chọn đúng — mà là người biết mình đang đánh đổi gì và chấp nhận có ý thức.

Ví dụ:

  • "Tôi chọn eventual consistency cho feed vì user không cần thấy post ngay lập tức — đổi lại throughput cao hơn 10x."
  • "Tôi chọn SQL thay vì NoSQL vì data có quan hệ phức tạp — đánh đổi horizontal scaling sẽ khó hơn ở 10M users."

Tư duy Trade-off — "Không có thiết kế hoàn hảo"

Đây là triết lý quan trọng nhất của System Design: mọi quyết định đều có cái giá. Architect giỏi không tìm giải pháp hoàn hảo — họ tìm giải pháp mà cái giá phải trả là chấp nhận được.

Ma trận trade-off cơ bản

Trade-offChọn AChọn BKhi nào chọn AKhi nào chọn B
Consistency vs AvailabilityStrong consistency — mọi read đều thấy write mới nhấtHigh availability — hệ thống luôn trả lời, dù data có thể cũBanking, inventorySocial feed, analytics
Latency vs ThroughputLow latency — mỗi request nhanhHigh throughput — xử lý nhiều request/giâyReal-time gaming, tradingBatch processing, ETL
Simplicity vs FlexibilityMonolith — đơn giản, dễ debugMicroservices — linh hoạt, scale độc lậpStartup giai đoạn đầu, team < 10Hệ thống lớn, team > 50
Build vs BuyTự xây dựng — kiểm soát hoàn toànDùng managed service — nhanh, ít vận hànhCore business logic, competitive advantageCommodity (auth, email, payment)
Cost vs PerformanceTối ưu chi phí — chấp nhận chậm hơnTối ưu tốc độ — chấp nhận đắt hơnStartup bootstrap, internal toolsCustomer-facing, revenue-critical

CAP Theorem — Giới hạn vật lý

Trong hệ thống phân tán, khi xảy ra network partition (P), bạn chỉ có thể chọn một trong hai: Consistency (C) hoặc Availability (A). Đây không phải design choice — đây là giới hạn toán học đã được chứng minh. Hiểu CAP giúp bạn không lãng phí thời gian tìm giải pháp không tồn tại.

Day 1 vs Day 100 — Hệ thống tiến hoá thế nào?

Thiết kế cho 100 users khác hoàn toàn với thiết kế cho 100M users. Sai lầm phổ biến nhất: thiết kế cho 100M users khi bạn chỉ có 100 users (over-engineering), hoặc giữ nguyên thiết kế 100 users khi đã có 1M users (under-engineering).

Giai đoạnUsersKiến trúcDatabaseCachingDeployment
Day 1 — Startup MVP100–1KMonolith, 1 serverSingle PostgreSQLKhông cần1 VPS, manual deploy
Day 30 — Product-Market Fit1K–100KMonolith + read replicasPostgreSQL + 1 read replicaRedis cho hot data2-3 servers, CI/CD
Day 100 — Growth100K–1MModular monolith / SOASharded databaseMulti-tier cache (local + Redis + CDN)Kubernetes, auto-scaling
Day 365 — Scale1M–100MMicroservicesPolyglot persistenceDistributed cache clusterMulti-region, blue-green deploy

Điều không đổi qua mọi giai đoạn:

  • Monitoring và alerting luôn cần từ Day 1
  • Database backup và recovery plan
  • API contract rõ ràng giữa các component
  • Logging có cấu trúc (structured logging)

Điều thay đổi:

  • Kiến trúc từ monolith → microservices
  • Database từ single node → sharded cluster
  • Deploy từ manual → fully automated
  • Team từ 3 fullstack → 50+ chuyên biệt

Nguyên tắc vàng

Thiết kế cho 10× quy mô hiện tại, không phải 1000×. Nếu bạn có 10K users, hãy thiết kế cho 100K. Khi đến 100K, redesign cho 1M. Thiết kế cho 100M khi chỉ có 10K users là lãng phí tài nguyên và thời gian.


Sai lầm điển hình

⚠️ Cạm bẫy

Sai lầm 1: Over-engineering ngay từ đầu

Vấn đề: Startup 3 người xây microservices với Kubernetes, Kafka, và service mesh — khi chỉ có 50 users.

Tại sao sai: Mỗi component thêm vào hệ thống tăng complexity theo cấp số nhân, không cấp số cộng. 3 người vận hành 20 microservices = mỗi người chịu trách nhiệm 7 services, chưa kể networking, monitoring, và deployment pipeline. Thay vì ship feature, team dành 80% thời gian xử lý infrastructure.

Cách đúng: Bắt đầu với monolith có cấu trúc tốt (modular monolith). Tách service khi có bằng chứng cụ thể rằng module đó cần scale độc lập — không phải khi bạn "cảm thấy" nên tách.

⚠️ Cạm bẫy

Sai lầm 2: Bỏ qua Non-Functional Requirements

Vấn đề: Thiết kế chỉ tập trung vào "làm gì" (functional) mà quên "làm tốt đến mức nào" (non-functional). Hệ thống hoạt động đúng ở 100 users, nhưng sập ở 10K users.

Tại sao sai: Non-functional requirements (latency, availability, throughput) quyết định kiến trúc, không phải functional requirements. Một CRUD app cho 100 users và một CRUD app cho 10M users có functional requirements giống hệt nhau — nhưng kiến trúc hoàn toàn khác.

Cách đúng: Luôn xác định rõ: target QPS, latency SLA (p50 và p99), availability target (99.9% vs 99.99%), và data retention policy trước khi bắt đầu thiết kế.

⚠️ Cạm bẫy

Sai lầm 3: Resume-Driven Design

Vấn đề: Chọn công nghệ vì muốn thêm vào CV, không phải vì bài toán cần. "Chúng ta dùng Kafka nhé" — khi hệ thống có 100 messages/ngày.

Tại sao sai: Mỗi công nghệ mang theo operational cost: learning curve, monitoring, backup, upgrade, troubleshooting. Kafka cho 100 messages/ngày giống như thuê Boeing 747 để chở 3 người đi Đà Nẵng.

Cách đúng: Bắt đầu từ bài toán, không phải công nghệ. Hỏi: "Tôi cần gì?" trước "Tôi nên dùng gì?". Nếu Redis Queue giải quyết được, đừng dùng Kafka. Nếu cron job đủ, đừng dùng message queue.

⚠️ Cạm bẫy

Sai lầm 4: Không làm Back-of-Envelope Math

Vấn đề: Thiết kế mà không ước lượng QPS, storage, bandwidth. Kết quả: chọn database không chịu nổi tải, hoặc ngược lại — mua server gấp 100 lần cần thiết.

Tại sao sai: Không có con số = không có cơ sở để ra quyết định. "Hệ thống cần xử lý nhiều request" — nhiều là bao nhiêu? 100/s, 10K/s, hay 1M/s? Mỗi mức đòi hỏi kiến trúc hoàn toàn khác nhau.

Cách đúng: Luôn ước lượng 3 con số: QPS (bao nhiêu requests/giây), Storage (bao nhiêu dữ liệu tích luỹ trong 3–5 năm), Bandwidth (bao nhiêu MB/s ra/vào). Sai 2–5 lần vẫn hữu ích hơn không có con số nào.


✅ Checklist triển khai

Checklist tư duy trước mỗi thiết kế

Requirements

  • [ ] Liệt kê đầy đủ functional requirements — hệ thống làm gì?
  • [ ] Xác định non-functional requirements — latency, availability, consistency targets cụ thể
  • [ ] Phân biệt rõ "must-have" vs "nice-to-have" — tránh scope creep
  • [ ] Xác định user personas và use cases chính — ai dùng, dùng thế nào?

Estimation

  • [ ] Ước lượng QPS — average và peak (thường peak = 3–5× average)
  • [ ] Tính storage cho 3–5 năm — bao gồm cả replication và backup
  • [ ] Tính bandwidth — inbound + outbound × peak multiplier
  • [ ] Xác định read:write ratio — quyết định caching strategy

Architecture

  • [ ] Vẽ high-level diagram trước khi viết bất kỳ dòng code nào
  • [ ] Xác định single points of failure — mỗi component đều phải có fallback
  • [ ] Chọn communication pattern — sync (REST/gRPC) vs async (message queue)
  • [ ] Data flow rõ ràng — từ client → API → storage, không có vòng lặp ẩn

Trade-offs

  • [ ] Ghi lại mọi quyết định trade-off — "Chọn A vì..., chấp nhận đánh đổi B"
  • [ ] Xác định giới hạn của thiết kế — "Thiết kế này hoạt động tốt đến X users, sau đó cần redesign"
  • [ ] Xem xét Build vs Buy cho mỗi component — đừng tự build commodity
  • [ ] Validate với team — một architect không bao giờ thiết kế một mình

Operational Readiness

  • [ ] Monitoring và alerting plan — biết hệ thống chết trước khi user biết
  • [ ] Disaster recovery — backup, failover, data recovery procedure
  • [ ] Deployment strategy — blue-green, canary, hay rolling update?
  • [ ] Capacity planning — khi nào cần scale, trigger là gì?

Bài tập luyện tập

🧠 Quiz

Câu 1: Một startup fintech đang xây hệ thống chuyển tiền. Họ cần chọn giữa strong consistency và high availability. Theo CAP theorem, đâu là lựa chọn đúng?

  • [x] Strong consistency — vì giao dịch tài chính không thể chấp nhận dữ liệu sai
  • [ ] High availability — vì hệ thống luôn phải online
  • [ ] Cả hai đều đạt được nếu thiết kế tốt
  • [ ] Tuỳ vào ngân sách

Giải thích: Trong fintech, một giao dịch bị ghi đúp hoặc mất tiền là thảm hoạ. Consistency phải được ưu tiên — chấp nhận hệ thống tạm thời không available (trả lỗi) còn hơn trả kết quả sai. Đây là lý do hầu hết hệ thống banking dùng ACID transactions.

🧠 Quiz

Câu 2: Team của bạn có 5 engineer, sản phẩm có 2K DAU. CTO đề xuất chuyển sang microservices. Bạn nên phản hồi thế nào?

  • [ ] Đồng ý — microservices là best practice hiện đại
  • [ ] Đồng ý nhưng bắt đầu với 3 services trước
  • [x] Phản đối — đề xuất modular monolith, chỉ tách service khi có bằng chứng cụ thể cần scale độc lập
  • [ ] Đề xuất serverless thay thế

Giải thích: 5 engineer + 2K DAU = monolith là lựa chọn tối ưu. Microservices tăng operational complexity (networking, deployment, monitoring, debugging distributed systems) mà 5 người không thể vận hành hiệu quả. Modular monolith cho phép tách service sau này khi thực sự cần, mà không phải trả chi phí phân tán trước.

🧠 Quiz

Câu 3: Hệ thống social media có 50M DAU, mỗi user xem feed 10 lần/ngày. Ước lượng QPS cho feed API là bao nhiêu?

  • [ ] 50,000 QPS
  • [ ] 500,000 QPS
  • [x] ~5,800 QPS trung bình, ~17,400 QPS peak
  • [ ] 5,000,000 QPS

Giải thích: 50M DAU × 10 views/ngày = 500M requests/ngày. 500M / 86,400 giây ≈ 5,787 QPS (trung bình). Peak thường gấp 3× trung bình ≈ 17,361 QPS. Đây là mức cần horizontal scaling (nhiều server + load balancer), nhưng chưa đến mức cần kiến trúc cực kỳ phức tạp.

🧠 Quiz

Câu 4: Đâu là thứ tự đúng của 5 bước tiếp cận System Design?

  • [ ] High-level design → Estimation → Requirements → Deep dive → Trade-offs
  • [ ] Requirements → High-level design → Deep dive → Estimation → Trade-offs
  • [x] Requirements → Estimation → High-level design → Deep dive → Trade-offs
  • [ ] Estimation → Requirements → High-level design → Trade-offs → Deep dive

Giải thích: Phải hiểu yêu cầu trước (Requirements), rồi ước lượng quy mô (Estimation) để biết cần kiến trúc phức tạp đến đâu, sau đó mới vẽ tổng quan (High-level design), đi sâu vào chi tiết (Deep dive), và cuối cùng thảo luận đánh đổi (Trade-offs). Estimation trước high-level design vì con số quy mô quyết định bạn cần bao nhiêu component.