Part 10 · System Design · 10.1.05

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.

Nguyên tắc xuyên suốt: trước khi thêm cache, queue, replica hay microservice, hãy chỉ ra constraint nào đang buộc bạn phải thêm nó. Nếu chưa có constraint, architecture đơn giản thường dễ triển khai, quan sát và phục hồi hơn.

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 boundarysource of truth.

Client → Edge / Load Balancer → Stateless Application → Primary Datastore

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

Tránh over-design ở MVP. Một deploy cùng managed database thường là MVP hợp lý hơn việc tách microservices khi chưa có constraint rõ ràng. Microservices không tự động giải quyết scale, reliability hay ownership.

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ẽnVì sao cần kiểm tra
Connection poolsNhiều app instance có thể làm tổng số connection tới datastore/downstream tăng nhanh.
Downstream quotasProvider hay service phía sau có rate/quota riêng; thêm app instance không làm quota đó tăng.
Database capacityDatabase 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, readinessgraceful 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 flowPhù hợp khiĐiểm phải reasoning
SyncCaller 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.
AsyncBurst, 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, DLQreconciliation. 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.

Không dùng async chỉ để diagram “scale”. Nếu workload không cần burst handling, long work hoặc decoupling, queue có thể chỉ làm hệ thống phức tạp hơn mà không giải quyết constraint thật.

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 writeWrite capacity có giới hạn nào và workload ghi có phải dominant path không?
Hot cache keyMột key hoặc một nhóm key có tạo tải tập trung bất thường không?
Fan-outMột request/event có nhân thành quá nhiều call hay work item không?
Storage bandwidthThroughput đọc/ghi dữ liệu lớn có bị giới hạn bởi bandwidth không?
Provider rate limitExternal provider có quota/rate limit thấp hơn khả năng xử lý nội bộ không?
WebSocket connectionsSố 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, mitigationmetric. 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”.

Bottleneck → Capacity limit → Mitigation → Metric

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, recoverydata 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ườngCâu hỏi cần trả lời
Failure modeComponent có thể fail theo cách nào?
Blast radiusPhần nào của hệ thống/user bị ảnh hưởng?
DetectionTín hiệu nào cho biết lỗi đang xảy ra?
Degraded behaviorHệ thống có thể tiếp tục phục vụ ở mức giảm chức năng nào?
RecoveryKhôi phục component hoặc flow như thế nào?
Data correctnessSau lỗi, dữ liệu có thể mất, trùng, lệch hay cần reconciliation không?
Reliability theo SLO, không theo bản năng “nhân đôi mọi thứ”. Loại bỏ single point of failure khi SLO yêu cầu. Redundancy ở mọi layer có cost và complexity; bài toán là chọn đúng nơi cần redundancy, không phải clone toàn bộ diagram.

6. Checklist review high-level architecture

Tài liệu chính thức trong source BK: Azure Architecture Styles · AWS Well-Architected