High-level read/write flows và bottleneck
Bắt đầu với architecture nhỏ nhất đáp ứng nhu cầu hiện tại, rồi chỉ thêm component khi một constraint cụ thể thực sự yêu cầu. Mục tiêu của high-level architecture không phải làm diagram “trông scale”, mà là làm rõ flow, state, source of truth, bottleneck và cách hệ thống thất bại.
1. Baseline architecture
Baseline nhỏ nhất trong bài là client → edge/load balancer → stateless application → primary datastore. Đây là điểm xuất phát để reasoning trước khi tách thêm component. Khi vẽ, cần tách riêng read flow và write flow, đồng thời chỉ rõ auth boundary và source of truth.
Read flow
Đi theo đường dữ liệu mà một request đọc thực sự phải qua. Việc vẽ riêng read path giúp bạn thấy request bị chặn ở đâu, dữ liệu được lấy từ nguồn nào và component nào nằm trên critical path.
Write flow
Write path cần làm rõ nơi nhận write, nơi dữ liệu trở thành authoritative và bước nào quyết định request được xem là thành công. Nếu một datastore là source of truth, diagram nên thể hiện điều đó thay vì để nhiều box có vẻ cùng sở hữu dữ liệu.
Auth boundary và source of truth
- Auth boundary: chỉ rõ điểm nào xác thực/ủy quyền trước khi request chạm business logic hay dữ liệu.
- Source of truth: chỉ rõ nơi dữ liệu authoritative được lưu và component nào chỉ giữ bản sao hay derived state.
- Read/write separation: cùng một sơ đồ có thể có hai flow khác nhau; đừng giả định read và write có cùng bottleneck.
2. Horizontal scaling
Stateless compute có thể scale horizontally phía sau load balancer. Khi application node không giữ state phiên cục bộ, nhiều instance có thể phục vụ request mà không buộc client phải quay lại đúng một node.
Session state
Nếu session state đang nằm trong memory của một application instance, việc scale ngang sẽ khó hơn. Bài nguồn đề xuất chuyển state đó sang signed token hoặc một store dùng chung khi cần, để application layer giữ được tính stateless.
Scale app chưa chắc đã hết nghẽn
CPU của application không phải bottleneck duy nhất. Khi thêm instance, các giới hạn khác có thể chạm trần trước:
| Điểm có thể nghẽn | Vì sao cần kiểm tra |
|---|---|
| Connection pools | Nhiều app instance có thể làm tổng số connection tới datastore/downstream tăng nhanh. |
| Downstream quotas | Provider hay service phía sau có rate/quota riêng; thêm app instance không làm quota đó tăng. |
| Database capacity | Database có thể trở thành giới hạn trước khi CPU ở application layer bận. |
Rollout cũng là một phần của scaling
Health check, readiness và graceful drain quyết định một rollout có an toàn hay không. Instance chỉ nên nhận traffic khi thực sự sẵn sàng, và khi rời pool cần có thời gian hoàn tất request đang xử lý thay vì bị cắt đột ngột.
3. Sync hay async?
Chọn synchronous flow khi caller cần immediate result. Chọn asynchronous flow khi workload có burst, tác vụ kéo dài hoặc cần decoupling. Với async, request thường cần một trạng thái trung gian như PENDING thay vì giả vờ rằng công việc đã hoàn tất ngay.
| Kiểu flow | Phù hợp khi | Điểm phải reasoning |
|---|---|---|
| Sync | Caller cần kết quả ngay trên request/response path. | Latency và availability của downstream trở thành một phần của critical path. |
| Async | Burst, long-running work hoặc decoupling cần tách khỏi request path. | Cần trạng thái PENDING và phải định nghĩa semantics vận hành của queue. |
Queue không chỉ là một box
Khi thêm queue, architecture phải trả lời thêm các vấn đề về delivery, ordering, retry, DLQ và reconciliation. Nói cách khác, queue làm flow linh hoạt hơn nhưng cũng mở rộng failure model và correctness model của hệ thống.
- Delivery: message được giao theo semantics nào?
- Ordering: thứ tự có cần giữ không, và ở phạm vi nào?
- Retry: lỗi tạm thời được thử lại thế nào?
- DLQ: message không xử lý được sẽ đi đâu?
- Reconciliation: làm sao phát hiện và sửa trạng thái lệch giữa các bước?
4. Chọn bottleneck để deep dive
High-level design không cần deep dive mọi box như nhau. Hãy dùng estimate và dominant path để chọn nơi có khả năng quyết định capacity hoặc latency của hệ thống.
| Ứng viên bottleneck | Điều cần đặt câu hỏi |
|---|---|
| DB write | Write capacity có giới hạn nào và workload ghi có phải dominant path không? |
| Hot cache key | Một key hoặc một nhóm key có tạo tải tập trung bất thường không? |
| Fan-out | Một request/event có nhân thành quá nhiều call hay work item không? |
| Storage bandwidth | Throughput đọc/ghi dữ liệu lớn có bị giới hạn bởi bandwidth không? |
| Provider rate limit | External provider có quota/rate limit thấp hơn khả năng xử lý nội bộ không? |
| WebSocket connections | Số connection đồng thời có trở thành resource limit chính không? |
Mẫu deep dive tối thiểu
Với bottleneck đã chọn, mô tả ba thứ: capacity limit, mitigation và metric. Nhờ vậy, câu trả lời System Design đi từ “tôi đoán đây là bottleneck” sang “tôi biết giới hạn nào cần theo dõi và hành động nào dùng khi tới gần giới hạn”.
5. Failure matrix
Với mỗi box trong architecture, hãy lập một failure matrix gồm: failure mode, blast radius, detection, degraded behavior, recovery và data correctness. Đây là cách biến một sơ đồ happy-path thành một thiết kế có thể reasoning về reliability.
| Trường | Câu hỏi cần trả lời |
|---|---|
| Failure mode | Component có thể fail theo cách nào? |
| Blast radius | Phần nào của hệ thống/user bị ảnh hưởng? |
| Detection | Tín hiệu nào cho biết lỗi đang xảy ra? |
| Degraded behavior | Hệ thống có thể tiếp tục phục vụ ở mức giảm chức năng nào? |
| Recovery | Khôi phục component hoặc flow như thế nào? |
| Data correctness | Sau lỗi, dữ liệu có thể mất, trùng, lệch hay cần reconciliation không? |
6. Checklist review high-level architecture
- Architecture bắt đầu từ baseline nhỏ nhất hay đã thêm component không có constraint?
- Read flow và write flow đã được tách rõ chưa?
- Auth boundary và source of truth đã rõ chưa?
- Application layer có stateless để scale ngang không; session state đang ở đâu?
- Khi scale app, connection pools, downstream quotas và database capacity có bị bỏ quên không?
- Health/readiness/graceful drain đã được nghĩ tới cho rollout chưa?
- Sync/async được chọn theo immediate result, burst, long work hoặc decoupling chứ không chỉ vì “scale”?
- Nếu có queue, delivery, ordering, retry, DLQ và reconciliation đã có owner/behavior chưa?
- Đã chọn dominant bottleneck dựa trên estimate và mô tả capacity limit, mitigation, metric chưa?
- Mỗi critical box đã có failure mode, blast radius, detection, degraded behavior, recovery và data correctness chưa?
- Redundancy có được quyết định theo SLO thay vì nhân đôi mọi thứ không?