Chương 81. Ước lượng nhanh trước khi thiết kế
Ở chương trước, ta nói rằng thiết kế hệ thống phải bắt đầu từ yêu cầu thật.
Sau khi biết:
Ai dùng?
Họ làm gì?
Dữ liệu nào quan trọng?
Điều gì không được sai?
Việc nào cần realtime?
Việc nào xử lý sau được?
bước tiếp theo không phải là chọn công nghệ ngay.
Bước tiếp theo là ước lượng.
Không cần chính xác tuyệt đối.
Nhưng cần đủ gần để tránh thiết kế bằng cảm giác.
Ví dụ:
Một ngày có bao nhiêu request?
Giờ cao điểm là bao nhiêu?
Bao nhiêu user đồng thời?
Dữ liệu tăng bao nhiêu mỗi tháng?
Một job mất bao lâu?
Cần bao nhiêu worker?
Provider ngoài giới hạn thế nào?
Chi phí phình ở đâu?
Thông điệp chính của chương:
> Ước lượng nhanh không phải để đoán đúng từng con số. Nó giúp ta thấy hình dạng tải, điểm nghẽn, chi phí và rủi ro trước khi chọn kiến trúc. Một phép tính thô đúng hướng thường tốt hơn một kiến trúc rất phức tạp nhưng dựa trên cảm giác.
---
81.1. Vì sao phải ước lượng?
Nhiều cuộc tranh luận kiến trúc bị mơ hồ vì không có số.
Ví dụ:
Hệ thống cần scale lớn.
Lớn là bao nhiêu?
100 request/giây?
1.000 request/giây?
100.000 request/giây?
Hay:
AI chấm bài sẽ chậm.
Chậm là:
10 giây?
90 giây?
10 phút?
Hay:
Cần nhiều worker.
Nhiều là:
4 worker?
40 worker?
400 worker?
Không có số, mọi người tranh luận bằng cảm giác.
Có số thô, ta bắt đầu nhìn thấy:
Điểm nghẽn nằm ở API?
Queue?
AI provider?
Database?
Storage?
Cost?
Ước lượng là cách bật đèn trước khi bước vào phòng.
---
81.2. Ước lượng không phải dự báo chính xác
Một hiểu lầm phổ biến:
Ước lượng mà sai thì vô ích.
Không đúng.
Ước lượng hệ thống không cần đúng đến từng request.
Nó cần đúng bậc độ lớn.
Ví dụ:
10 request/giây
100 request/giây
1.000 request/giây
10.000 request/giây
Các mức này dẫn đến thiết kế khác nhau.
Nếu ta ước lượng 100 request/giây nhưng thực tế 130 request/giây, không sao.
Nếu ta tưởng 100 request/giây nhưng thực tế 20.000 request/giây, đó là vấn đề.
Mục tiêu của ước lượng nhanh:
Tránh sai bậc độ lớn.
Nó giúp ta không dùng kiến trúc quá nhỏ cho tải lớn.
Và cũng không dùng kiến trúc quá nặng cho tải nhỏ.
---
81.3. Bắt đầu từ hình dạng tải
Đừng chỉ hỏi tổng số.
Hãy hỏi hình dạng tải.
Ví dụ:
100.000 bài nộp mỗi ngày.
Nghe có vẻ lớn.
Nhưng nếu trải đều 24 giờ:
100.000 / 24 / 60 / 60 ≈ 1,16 bài/giây.
Không quá lớn.
Nhưng nếu:
80.000 bài nộp trong 10 phút trước deadline.
thì:
80.000 / 10 / 60 ≈ 133 bài/giây.
Khác hẳn.
Hệ thống không đau vì tổng ngày.
Nó đau vì peak.
Với AI Judge, deadline tạo tải theo cụm:
Ít bài cả ngày.
Rất nhiều bài ngay trước hạn.
Kiến trúc phải thiết kế theo peak shape, không chỉ average.
---
81.4. Bao nhiêu request?
Một cách bắt đầu:
Daily active users.
Actions per user per day.
Peak factor.
Ví dụ:
100.000 học sinh active/ngày.
Mỗi học sinh trung bình 20 request/ngày.
Tổng request = 2.000.000 request/ngày.
Trung bình:
2.000.000 / 86.400 ≈ 23 request/giây.
Nhưng giờ cao điểm có thể gấp 20 lần:
23 * 20 = 460 request/giây.
Con số 460 request/giây khác xa 23 request/giây.
Ước lượng nên có:
Average RPS.
Peak RPS.
Burst RPS.
Average để tính cost dài hạn.
Peak để tính capacity.
Burst để tính backpressure/rate limit.
---
81.5. Không phải request nào cũng giống nhau
Một request nhẹ:
GET /assignments
có thể đọc cache hoặc query đơn giản.
Một request nặng:
POST /submissions
có thể upload file, ghi database, enqueue job.
Một request rất nặng:
POST /bulk-regrade
có thể tạo hàng chục nghìn job AI.
Vì vậy đừng chỉ tính:
Tổng RPS.
Hãy tách theo loại:
Read requests.
Write requests.
Upload requests.
Search requests.
AI-triggering requests.
Admin/bulk requests.
Ví dụ:
500 RPS đọc assignment có thể dễ.
50 RPS upload file có thể nặng.
5 RPS bulk action có thể cực nặng.
Kiến trúc đau ở request nặng, không chỉ request nhiều.
---
81.6. Bao nhiêu user đồng thời?
User đồng thời không giống daily active users.
Ví dụ:
1.000.000 user/ngày
không có nghĩa 1.000.000 user online cùng lúc.
Một ước lượng đơn giản:
concurrent users ≈ active users trong một khoảng thời gian
Ví dụ:
100.000 học sinh làm bài trong một giờ.
Mỗi học sinh active trung bình 20 phút.
Concurrent ≈ 100.000 * 20/60 = 33.333 user.
Nếu có realtime connection:
33.333 WebSocket connections.
Đó là câu chuyện khác với 33.333 request rời rạc.
Concurrent users ảnh hưởng:
Session.
WebSocket/SSE connections.
Presence.
Cache.
Database connection gián tiếp.
Realtime fan-out.
Nếu chỉ dùng HTTP stateless, concurrent user nhẹ hơn.
Nếu mỗi user giữ connection realtime, hạ tầng cần tính khác.
---
81.7. Bao nhiêu dữ liệu tăng lên?
Dữ liệu tăng theo thời gian thường bị đánh giá thấp.
Ví dụ AI Judge:
Mỗi bài nộp có file trung bình 2 MB.
Mỗi ngày có 100.000 bài.
Storage file mỗi ngày:
100.000 * 2 MB = 200.000 MB ≈ 200 GB/ngày.
Một tháng:
200 GB * 30 = 6 TB/tháng.
Một năm:
72 TB/năm.
Nếu có backup/versioning, con số có thể tăng thêm.
Nếu lưu prompt/response đầy đủ, thêm dữ liệu nữa.
Ví dụ:
Prompt + response trung bình 50 KB/bài.
100.000 bài/ngày -> 5 GB/ngày.
150 GB/tháng.
Không lớn bằng file, nhưng nhạy cảm hơn.
Ước lượng storage giúp quyết định retention, lifecycle, backup, cost.
---
81.8. Dữ liệu nào tăng nhanh nhất?
Không phải bảng lớn nhất là vấn đề duy nhất.
Cần hỏi:
Dữ liệu nào tăng nhanh nhất?
Dữ liệu nào đọc nhiều nhất?
Dữ liệu nào ghi nhiều nhất?
Dữ liệu nào nhạy cảm nhất?
Dữ liệu nào cần giữ lâu nhất?
Ví dụ:
Files chiếm nhiều storage.
Submissions tăng theo bài nộp.
Logs tăng theo traffic.
Metrics tăng theo cardinality.
AI prompt logs nhạy cảm.
Ledger entries cần audit lâu.
Search/vector index có thể rebuild nhưng tốn.
Mỗi loại cần chiến lược khác nhau.
Không nên lưu mọi thứ mãi mãi trong database chính.
Ví dụ:
File -> object storage.
Metric -> time-series store.
Search -> index rebuild được.
Prompt raw -> secure log store retention ngắn.
Ledger -> database bền append-only.
Ước lượng dữ liệu giúp tách storage theo bản chất.
---
81.9. Job mất bao lâu?
Với hệ thống có worker, cần biết một job mất bao lâu.
Ví dụ:
Một bài chấm AI trung bình 90 giây.
Nếu có 4 worker và mỗi worker xử lý 1 job tại một thời điểm:
Throughput = 4 job / 90 giây ≈ 0,044 job/giây
≈ 2,67 job/phút
≈ 160 job/giờ
Nếu có 10.000 bài chờ:
10.000 / 160 ≈ 62,5 giờ.
Rất lâu.
Đây là lý do chỉ nói:
Celery có 4 worker.
chưa đủ.
Cần hỏi:
Mỗi worker xử lý được bao nhiêu job/giờ?
Job có bị chờ I/O không?
Có thể tăng concurrency không?
Provider ngoài cho phép bao nhiêu request đồng thời?
Ước lượng job duration là cách nhìn thấy queue backlog trước khi nó xảy ra.
---
81.10. Công thức worker đơn giản
Công thức cơ bản:
Throughput = số worker_concurrency / thời gian mỗi job
Nếu:
Mỗi job mất 90 giây.
Cần xử lý 1.000 job trong 10 phút.
Ta cần throughput:
1.000 job / 600 giây = 1,67 job/giây.
Mỗi concurrency slot xử lý:
1 / 90 = 0,011 job/giây.
Số slot cần:
1,67 / 0,011 ≈ 150 slot.
Nghĩa là nếu mỗi process worker xử lý 1 job:
Cần khoảng 150 worker processes.
Nếu worker dùng concurrency 10 cho I/O-bound AI call:
Cần khoảng 15 worker processes.
Nhưng đây mới là phía mình.
Còn phải kiểm tra provider AI có chịu được 150 concurrent requests không.
---
81.11. Worker nhiều hơn không phải lúc nào cũng nhanh hơn
Nếu bottleneck là worker CPU, thêm worker có thể giúp.
Nếu bottleneck là provider ngoài, thêm worker có thể làm tệ hơn.
Ví dụ:
Provider AI cho phép 100 concurrent requests.
Ta chạy 500 concurrent requests.
Kết quả có thể là:
429 tăng.
Timeout tăng.
Retry tăng.
Queue tệ hơn.
Cost retry tăng.
Vì vậy cần phân biệt:
Capacity của hệ thống mình.
Capacity của dependency ngoài.
Một thiết kế tốt có:
Concurrency limit.
Rate limit.
Backoff.
Queue.
Provider metrics.
Circuit breaker.
Không phải cứ tăng worker là scale.
Scale đúng là tăng đúng điểm nghẽn.
---
81.12. API ngoài giới hạn thế nào?
Nếu hệ thống phụ thuộc API ngoài, cần đọc giới hạn của họ:
Requests per minute.
Tokens per minute.
Concurrent requests.
Payload size.
Timeout.
Daily quota.
Cost per token/request.
Ví dụ:
Provider cho 100 requests/phút.
Mỗi bài cần 1 request.
Tối đa:
100 bài/phút = 6.000 bài/giờ.
Nếu deadline tạo:
60.000 bài trong 10 phút.
Provider limit 100 RPM không thể chấm hết ngay.
Ngay cả khi ta có 1.000 worker.
Khi đó kiến trúc phải:
Queue.
Thông báo chờ.
Ưu tiên.
Batch nếu provider hỗ trợ.
Nhiều provider/model nếu cần.
Tăng quota với provider.
Điều chỉnh SLO.
Giới hạn bên ngoài là một phần của kiến trúc.
Không phải chi tiết triển khai.
---
81.13. Ước lượng latency
Latency tổng là tổng các đoạn trên đường đi.
Ví dụ submit bài:
Auth: 20 ms.
Validate: 10 ms.
Upload file: phụ thuộc size/network.
Ghi database: 30 ms.
Ghi object storage: 200 ms.
Enqueue job: 20 ms.
Response: tổng khoảng vài trăm ms đến vài giây.
Nếu request submit gọi AI trực tiếp:
AI call: 90 giây.
Thì API submit có thể thành 90 giây.
Không hợp lý.
Đây là lý do việc lâu nên chạy nền.
Với latency, hãy tách:
User-facing latency.
Background completion time.
End-to-end business latency.
Ví dụ:
Submit confirmation: dưới 1 giây.
AI grading completion: 95% dưới 5 phút.
Report update: dưới 10 phút.
Một hệ thống có thể nhanh ở request nhưng chậm ở end-to-end.
Cần đo cả hai.
---
81.14. Ước lượng database load
Database load không chỉ là request count.
Cần biết mỗi request tạo bao nhiêu query và ghi gì.
Ví dụ:
500 RPS.
Mỗi request 10 queries.
=> 5.000 queries/giây.
Nếu có N+1 query:
Mỗi request list submissions tạo 1 + 100 queries.
Chỉ 50 RPS cũng thành:
5.050 queries/giây.
Với write:
100 submission/giây.
Mỗi submission ghi users? submissions? files? audit? outbox?
Có thể là:
5 writes/submission -> 500 writes/giây.
Database còn bị ảnh hưởng bởi:
Index.
Transaction.
Lock.
Connection pool.
Long query.
Report/export.
Backfill.
Ước lượng database giúp biết khi nào cần cache, read model, queue, batch, index, hoặc tách job nặng.
---
81.15. Ước lượng cache có đáng không
Cache không phải lúc nào cũng cần.
Hỏi:
Dữ liệu có đọc nhiều hơn ghi không?
Dữ liệu có chịu stale được không?
Cache miss có đắt không?
Cache key có tenant/permission không?
Invalidation có khó không?
Ví dụ:
Rubric của assignment được đọc rất nhiều khi chấm hàng nghìn bài.
Rubric ít thay đổi.
Cache có thể đáng.
Nhưng:
Điểm chính thức vừa sửa.
User cần thấy đúng ngay.
Cache phải cẩn thận.
Ước lượng đơn giản:
Rubric đọc 100.000 lần/giờ, ghi 1 lần/ngày.
Cache rất hợp.
Dashboard count thay đổi liên tục, cần gần đúng.
Có thể dùng read model hoặc cache ngắn.
Permission theo user phức tạp.
Cache dễ sai nếu key thiếu scope.
Cache là tối ưu có điều kiện, không phải phản xạ.
---
81.16. Chi phí có thể phình ở đâu?
Chi phí không chỉ là server.
Với hệ thống hiện đại, cost có thể phình ở:
AI tokens.
Storage.
Database.
Logs.
Metrics cardinality.
Search/vector index.
Bandwidth.
Queue.
Third-party APIs.
Background jobs.
Retries.
Shadow traffic.
Backups.
Với AI Judge, cost lớn có thể là:
Model calls.
Prompt quá dài.
Output quá dài.
Retry AI.
Shadow/evaluation.
File storage.
Full prompt logs.
Vector embeddings.
Ước lượng cost thô:
Số bài/ngày * token/bài * giá/token.
Ví dụ:
100.000 bài/ngày.
10.000 tokens/bài.
=> 1.000.000.000 tokens/ngày.
Nếu không tính trước, con số có thể làm giật mình.
Cost là yêu cầu kiến trúc.
Không phải chuyện cuối tháng mới xem hóa đơn.
---
81.17. Retry làm cost và tải phình
Retry nghe nhỏ nhưng ảnh hưởng lớn.
Nếu mỗi job có thể retry 3 lần:
1 lần chính + 3 retry = tối đa 4 lần gọi.
Nếu có 100.000 job:
Tối đa 400.000 calls.
Nếu lỗi provider hàng loạt, retry có thể làm:
Traffic ra provider tăng.
Worker bận hơn.
Queue lâu hơn.
Cost cao hơn.
Khi ước lượng, nên tính worst case vừa phải:
Nếu 10% job retry 1 lần, cost tăng bao nhiêu?
Nếu 30% timeout trong 10 phút, queue ra sao?
Retry không miễn phí.
Nó là nhân tử tải.
Thiết kế retry cần đi cùng backoff, jitter, limit, circuit breaker và idempotency.
---
81.18. Ước lượng theo normal, peak, failure
Đừng chỉ ước lượng normal case.
Hãy có ba kịch bản:
Normal.
Peak.
Failure.
Normal:
Ngày bình thường.
Traffic vừa.
Provider ổn.
Peak:
Deadline.
Kỳ thi.
Import lớn.
Report cuối kỳ.
Failure:
Provider timeout 30%.
Worker giảm một nửa.
Database chậm.
Webhook partner fail.
Retry tăng.
Nhiều hệ thống sống tốt ở normal nhưng chết ở failure.
Ví dụ:
Normal: 10.000 bài/giờ.
Peak: 100.000 bài/giờ.
Failure: provider lỗi làm 30% retry.
Nếu không tính failure, ta sẽ đánh giá thấp queue, retry storm và cost.
---
81.19. Một bài tính AI Judge đơn giản
Giả sử:
50.000 học sinh nộp bài trong 30 phút.
Mỗi bài cần 1 AI call.
Mỗi AI call trung bình 90 giây.
Provider cho phép 300 concurrent calls.
Thông lượng tối đa của provider:
300 calls / 90 giây = 3,33 bài/giây.
≈ 200 bài/phút.
≈ 12.000 bài/giờ.
50.000 bài cần:
50.000 / 12.000 ≈ 4,17 giờ.
Nếu yêu cầu là:
95% bài có điểm trong 5 phút.
thì không đạt.
Không phải vì Celery yếu.
Không phải vì FastAPI yếu.
Mà vì:
AI call lâu và provider concurrency không đủ.
Lúc này giải pháp có thể là:
Tăng quota/concurrency provider.
Dùng model nhanh hơn.
Chấm theo priority.
Chấp nhận SLO dài hơn.
Chấm sơ bộ trước.
Batch nếu có.
Nhiều provider.
Giảm prompt/token.
Ước lượng giúp ta tìm đúng vấn đề.
---
81.20. Tính worker khi job I/O-bound
AI call thường là I/O-bound.
Worker chờ provider trả lời.
Nếu dùng worker kiểu mỗi process chỉ xử lý một job, nhiều thời gian là chờ.
Ta có thể dùng concurrency:
Thread.
Async.
Gevent/eventlet.
Worker concurrency cao hơn.
Nhưng concurrency vẫn phải tôn trọng provider limit.
Ví dụ:
Cần 300 concurrent AI calls.
Mỗi worker process chạy concurrency 20.
=> cần khoảng 15 worker processes.
Nếu concurrency 4:
300 / 4 = 75 worker processes.
Nhưng nếu provider chỉ cho 100 concurrent:
Chạy 300 concurrent sẽ tạo lỗi.
Vậy cần:
Global concurrency limit.
Per-provider limit.
Per-tenant fairness.
Ước lượng worker không chỉ là CPU core.
Nó là bài toán thời gian chờ, concurrency và giới hạn dependency.
---
81.21. Ước lượng queue backlog
Queue backlog tăng khi:
enqueue_rate > processing_rate
Ví dụ:
Trong deadline, bài vào 1.000 bài/phút.
Worker xử lý 200 bài/phút.
Backlog tăng 800 bài/phút.
Sau 30 phút:
800 * 30 = 24.000 bài backlog.
Sau khi deadline qua, nếu không có bài mới:
24.000 / 200 = 120 phút
cần thêm 2 giờ để xử lý hết.
Đây là cách tính rất đơn giản nhưng cực kỳ hữu ích.
Nó giúp ta nói thật:
Với capacity hiện tại, sau deadline điểm sẽ ra dần trong 2 giờ.
Thay vì hứa:
Hệ thống realtime.
Queue không phải xấu.
Nhưng queue cần SLO rõ.
---
81.22. Ước lượng bandwidth và upload
File upload có thể làm hệ thống đau ở bandwidth.
Ví dụ:
50.000 học sinh upload file 2 MB trong 10 phút.
Tổng dữ liệu:
100 GB trong 10 phút.
Bandwidth trung bình:
100 GB / 600 giây ≈ 166 MB/giây.
Đó là khoảng:
≈ 1,3 Gbps
Nếu file trung bình 10 MB:
500 GB / 600 giây ≈ 833 MB/giây ≈ 6,7 Gbps.
Upload nên đi qua:
Direct-to-object-storage nếu phù hợp.
Pre-signed URL.
Size limit.
Chunked/resumable upload nếu cần.
Scan pipeline.
Không nên để app server gánh mọi file lớn nếu không cần.
Ước lượng upload giúp tránh nghẽn network/app server.
---
81.23. Ước lượng log và metrics
Observability cũng có cost.
Ví dụ:
Mỗi request log 2 KB.
10 triệu request/ngày.
Log:
20 GB/ngày.
600 GB/tháng.
Nếu log full prompt/response:
50 KB/job.
1 triệu jobs/ngày.
=> 50 GB/ngày.
Metrics cũng có vấn đề cardinality.
Nếu gắn label:
user_id.
submission_id.
request_id.
vào metrics, hệ thống metrics có thể nổ.
Ước lượng observability giúp quyết định:
Log gì.
Sample gì.
Retention bao lâu.
Metric label nào an toàn.
Full payload lưu ở đâu.
Quan sát hệ thống là cần.
Nhưng quan sát cũng phải được thiết kế.
---
81.24. Ước lượng không chắc thì ghi giả định
Nhiều con số ban đầu chưa chắc.
Không sao.
Hãy ghi giả định:
Giả định 1: 50.000 học sinh submit trong 30 phút.
Giả định 2: file trung bình 2 MB.
Giả định 3: AI call trung bình 90 giây.
Giả định 4: provider cho 300 concurrent calls.
Giả định 5: SLO grading là 95% dưới 30 phút ở peak.
Sau đó thiết kế theo giả định.
Khi có dữ liệu thật, cập nhật.
Điều nguy hiểm không phải là giả định sai.
Điều nguy hiểm là không biết mình đang giả định gì.
Một thiết kế tốt ghi rõ:
Nếu traffic gấp 10 lần giả định, điểm nghẽn đầu tiên là provider concurrency.
Nếu file trung bình 10 MB thay vì 2 MB, storage/bandwidth tăng 5 lần.
Nếu SLO đổi từ 30 phút xuống 5 phút, cần capacity lớn hơn nhiều.
Assumption rõ giúp team nói chuyện thật.
---
81.25. Đừng dùng ước lượng để giả vờ chắc chắn
Ước lượng là công cụ.
Không phải lời tiên tri.
Đừng trình bày như:
Chắc chắn cần 137 worker.
Tốt hơn:
Với giả định job 90 giây và cần 1.67 job/giây, ta cần khoảng 150 concurrency slots. Nếu job tăng lên 120 giây, cần khoảng 200 slots. Nếu provider limit chỉ 100, provider là bottleneck.
Cách nói này trung thực hơn.
Nó cho thấy biến nào quan trọng.
Nó giúp người khác kiểm tra giả định.
Senior không phải người đoán đúng mọi số.
Senior là người biết con số nào làm kiến trúc đổi hướng.
---
81.26. Từ ước lượng đến quyết định kiến trúc
Ước lượng nên dẫn đến quyết định.
Ví dụ:
AI call 90 giây, submit cần dưới 1 giây.
=> Chấm bài phải async qua queue.
Peak submit 100 bài/giây, file 2 MB.
=> Upload nên dùng object storage, không xử lý file nặng trong app server.
Provider giới hạn 100 RPM.
=> Worker concurrency không được vượt quota, cần queue và user-facing status.
Prompt logs 50 GB/ngày và nhạy cảm.
=> Không log full prompt mặc định, retention ngắn, access hạn chế.
Dashboard chỉ cần update mỗi 10 giây.
=> Polling hoặc SSE nhẹ có thể đủ, chưa cần collaboration realtime phức tạp.
Nếu ước lượng không dẫn đến quyết định, nó chỉ là bài toán vui.
Mục tiêu là chọn thiết kế tốt hơn.
---
81.27. Một bảng ước lượng mẫu cho AI Judge
Ví dụ:
| Hạng mục | Giả định | Kết quả thiết kế | |---|---|---| | Submit peak | 50.000 bài / 30 phút | API submit phải nhẹ, upload bền, queue grading | | File size | 2 MB trung bình | Object storage, lifecycle, scan pipeline | | AI latency | 90 giây/job | Không chấm trong request | | Provider limit | 300 concurrent | Global concurrency limit, queue backlog estimate | | Grading SLO | 95% dưới 30 phút peak | Cần capacity khoảng theo backlog/SLO | | Prompt log | 50 KB/job | Không log full mặc định, retention ngắn | | Dashboard latency | 10 giây đủ | Polling/SSE có thể đủ | | Billing | Tính credit theo submission | Ledger + idempotency |
Bảng này chưa phải thiết kế cuối.
Nhưng nó nối số liệu với quyết định.
Đó là giá trị của ước lượng.
---
81.28. Những sai lầm phổ biến
Sai lầm thứ nhất:
Chỉ nhìn average, quên peak.
Hệ thống thường chết ở peak.
Sai lầm thứ hai:
Tính request count nhưng quên request nặng.
Bulk, upload, search, AI call mới là chỗ đau.
Sai lầm thứ ba:
Tăng worker mà quên provider limit.
Worker nhiều hơn có thể tạo timeout/429 nhiều hơn.
Sai lầm thứ tư:
Không tính retry.
Retry là nhân tử tải và cost.
Sai lầm thứ năm:
Không tính storage/log growth.
Dữ liệu và log tăng âm thầm đến khi hóa đơn hoặc database đau.
Sai lầm thứ sáu:
Không ghi giả định.
Sau này không ai biết thiết kế dựa trên điều gì.
Sai lầm thứ bảy:
Ước lượng quá chi tiết quá sớm.
Mất thời gian vào số giả chính xác giả tạo.
Sai lầm thứ tám:
Không chuyển ước lượng thành quyết định.
Tính xong để đó, kiến trúc vẫn chọn bằng cảm giác.
---
81.29. Checklist ước lượng nhanh
Trước khi chọn kiến trúc, hãy ước lượng:
- Daily active users là bao nhiêu?
- Peak concurrent users là bao nhiêu?
- Average RPS là bao nhiêu?
- Peak RPS là bao nhiêu?
- Request nào nặng nhất?
- Upload/file size trung bình và tối đa là bao nhiêu?
- Dữ liệu tăng bao nhiêu mỗi ngày/tháng?
- Dữ liệu nào cần giữ lâu?
- Một job nền mất bao lâu?
- Enqueue rate và processing rate là bao nhiêu?
- Queue backlog tối đa có thể là bao nhiêu?
- Cần bao nhiêu concurrency slots?
- Dependency ngoài giới hạn RPM/concurrency/token ra sao?
- Retry có thể nhân tải lên bao nhiêu?
- Database query/write load ước lượng thế nào?
- Log/metrics/prompt logs tăng bao nhiêu?
- Cost lớn nhất nằm ở đâu?
- Kịch bản normal, peak, failure khác nhau thế nào?
- Giả định nào nếu sai sẽ làm kiến trúc đổi hướng?
Nếu chưa có số chính xác, hãy ghi range.
Range vẫn tốt hơn không có gì.
---
81.30. Bảng công thức nhanh
| Câu hỏi | Công thức thô | |---|---| | Average RPS | requests per day / 86.400 | | Peak RPS | average RPS peak factor | | Storage/ngày | số item/ngày size trung bình | | Worker throughput | concurrency slots / job duration | | Slot cần | required throughput job duration | | Backlog tăng | enqueue rate - processing rate | | Thời gian xả backlog | backlog / processing rate | | AI cost | jobs tokens/job price/token | | Upload bandwidth | total upload size / upload window | | Log volume | events bytes/event |
Các công thức này không hoàn hảo.
Nhưng chúng đủ để phát hiện nhiều điều quan trọng.
Ví dụ:
Nếu slot cần là 150 mà hiện có 4, ta biết có vấn đề.
Không cần mô phỏng phức tạp mới thấy.
---
81.31. Kết luận của chương
Ước lượng nhanh là bước nối giữa yêu cầu thật và kiến trúc cụ thể.
Nó giúp ta thấy:
Traffic.
Peak.
Concurrency.
Data growth.
Job duration.
Worker count.
Provider limits.
Queue backlog.
Database load.
Storage.
Cost.
Ước lượng không cần đúng tuyệt đối.
Nó cần làm lộ những điều có thể đổi hướng thiết kế.
Với AI Judge, chỉ cần tính nhanh thời gian chấm một bài, số bài trong peak, provider concurrency và worker throughput, ta đã biết liệu SLO 5 phút có thực tế không.
Thông điệp cần nhớ:
> Đừng thiết kế bằng cảm giác khi chỉ cần vài phép tính thô đã thấy điểm nghẽn. Ước lượng tốt không làm kiến trúc đúng hoàn toàn, nhưng giúp ta sai ít hơn, sớm hơn, và rẻ hơn.
Ở chương tiếp theo, ta sẽ nói về chọn kiến trúc theo giai đoạn: MVP, sản phẩm đang tăng trưởng, hệ thống scale lớn, và vì sao kiến trúc tốt hôm nay không nhất thiết là kiến trúc đúng cho hai năm nữa.