Nền tảng luyện code online
Hiểu đề
Yêu cầu chức năng
- Người dùng có thể xem danh sách bài (lọc theo độ khó, chủ đề) và đọc đề
- Người dùng có thể nộp code bằng nhiều ngôn ngữ và nhận kết quả AC/WA/TLE/MLE/RE/CE
- Người dùng có thể tham gia contest có giờ bắt đầu và kết thúc
- Người dùng có thể xem bảng xếp hạng contest gần như real-time và thứ hạng của mình
Yêu cầu phi chức năng
- Kết quả chấm p95 < 5 s ngoài contest, < 15 s lúc cao điểm contest
- Cô lập tuyệt đối: code người dùng không gọi được mạng, không đọc được test ẩn, không thoát khỏi sandbox
- Không mất submission nào trong contest 500.000 người, kể cả khi judge bị lỗi
- Bảng xếp hạng trễ tối đa 5 s; thời gian chấm đo ổn định, sai lệch < 10% giữa các lần chạy
- Độ sẵn sàng 99,9% cho đọc đề và nộp bài
Ngoài phạm vi: Diễn đàn thảo luận, lời giải cộng đồng; Gói Premium và thanh toán; Phát hiện đạo code (chỉ nhắc như một consumer của sự kiện chấm); Gợi ý bằng AI, soạn code cùng nhau.
Thực thể và API
| Method | Endpoint | Ghi chú |
|---|---|---|
| GET | /v1/problems?tag=&difficulty=&cursor= | Danh sách bài, cache ở CDN. |
| GET | /v1/problems/{slug} | Đề bài và test ví dụ. Nội dung gần như tĩnh nên cache CDN. |
| POST | /v1/problems/{slug}/submissions | Body {language, code, contestId?}. Trả 202 {submissionId} ngay, không chờ chấm. |
| GET | /v1/submissions/{id} | Trạng thái và kết quả. Client poll mỗi giây hoặc nhận đẩy qua WebSocket. |
| POST | /v1/contests/{id}/register | Đăng ký thi trước giờ bắt đầu. |
| GET | /v1/contests/{id}/leaderboard?page= | Trang bảng xếp hạng từ snapshot trên CDN; /me trả thứ hạng riêng. |
Thiết kế tổng thể
Đi lần lượt từng yêu cầu chức năng. Mục tiêu ở đây là chạy đúng, việc tối ưu để dành cho phần đào sâu.
1) Người dùng có thể xem danh sách bài và đọc đề
Đề bài gần như không đổi nên phục vụ qua CDN. API chỉ trả dữ liệu riêng của người dùng như bài nào đã AC.
- 1Client gọi GET /v1/problems/{slug} qua CDN
- 2CDN trả cache (TTL vài phút), hết hạn thì gọi API đọc Postgres
- 3Client gọi riêng một API nhỏ để lấy trạng thái đã giải của mình
Nguồn: Grokking Modern System Design · ch.11 Content Delivery Network (CDN) ↗ · Content Consistency in CDN · mục "Time-to-live (TTL)" ; Grokking Modern System Design · ch.11 CDN ↗ · mục "Pull CDN" ; Grokking Modern System Design · ch.16 Distributed Cache ↗ · Background of Distributed Cache · mục "Writing policies" (write-around: ghi vào cache sau lần trượt)
2) Người dùng có thể nộp code và nhận kết quả
Chấm bài mất 1-3 s và chạy code lạ nên không làm trong API. API lưu submission, đẩy vào queue rồi trả 202; judge worker chạy code trong sandbox và ghi kết quả.
- 1Client gửi POST /submissions, API kiểm tra rate limit và lưu code (S3) cùng metadata
- 2API đẩy {submissionId} vào queue (contest hoặc luyện tập) và trả 202
- 3Judge worker lấy job, tải test đã cache, biên dịch và chạy từng test trong sandbox có giới hạn CPU, RAM, thời gian, không có mạng
- 4Judge so output, ghi verdict, thời gian, bộ nhớ vào DB rồi xác nhận (ack) job
- 5Client poll GET /submissions/{id} hoặc nhận kết quả qua WebSocket
Nguồn: Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Motivation" (Improved performance, Granular scalability) ; Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Messaging queue use cases" (Post-processing) ; Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Task idempotency" ; Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Schedule and execute untrusted tasks" (sandbox bằng Docker hoặc máy ảo, giới hạn và dừng tác vụ vượt tài nguyên) ; Grokking Modern System Design · ch.19 Rate Limiter ↗ · mục "Where to place the rate limiter" ; Grokking Modern System Design · ch.36 WhatsApp ↗ · mục "Connection with a WebSocket server"
3) Người dùng có thể thi contest và xem bảng xếp hạng
Mỗi lần AC trong contest cập nhật điểm của người đó trong một Redis sorted set. Trang top được chụp thành snapshot đưa lên CDN, thứ hạng riêng đọc bằng ZREVRANK.
- 1Judge phát sự kiện verdict có contestId
- 2Leaderboard service tính lại điểm người đó (AC đầu tiên mỗi bài mới tính) và ghi ContestStanding vào DB
- 3ZADD contest:{id} score userId, với score = số bài × 10^7 − penalty (giây)
- 4Mỗi 2 s, job đọc ZREVRANGE top 1.000 và ghi file JSON lên CDN; client đọc file đó
- 5Thứ hạng riêng: GET /leaderboard/me → ZREVRANK
Nguồn: Redis in Action ↗ · ch.1 · §1.2.5 Sorted sets in Redis (tr. 13) ; Redis in Action ↗ · ch.3 · §3.5 Sorted sets (tr. 50) ; Grokking Modern System Design · ch.11 CDN ↗ · mục "Pull CDN" ; Chưa có nguồn trong thư viện: công thức score = số bài × 10^7 − penalty là thiết kế của khoá học
Hạ tầng theo quy mô
Cùng một sản phẩm, ba mức người dùng. Chọn từng mức để xem sơ đồ, phép tính và cấu hình server thay đổi thế nào.
Trang luyện code của một trường hoặc cộng đồng nhỏ. Một API, một Postgres vừa lưu dữ liệu vừa làm hàng đợi (SKIP LOCKED), hai máy judge chạy Docker đã khóa chặt.
Ước lượng
- Nộp bài thường: 10.000 × 2 / 86.400 ≈ 0,23/s, đỉnh ×5 ≈ 1,2/s
- Contest: 1.000 người × 6 lần nộp / 5.400 s ≈ 1,1/s, 15 phút cuối ×3 ≈ 3,3/s
- Slot judge (Little's law): 3,3/s × 2 s mỗi lần chấm ≈ 6,7 slot; máy 8 vCPU cho 7 slot → ceil(6,7 / 7) = 1 → chạy 2 máy để dự phòng
- API: 10.000 × 40 req / 86.400 ≈ 4,6 req/s, ×10 ≈ 46 req/s + poll 3,3 × 5 ≈ 17 → ≈ 63 req/s → 2 instance
- Lưu trữ: 10.000 × 2 × 365 = 7,3 triệu submission/năm × 2 KB ≈ 14,6 GB/năm; test 500 bài × 20 MB = 10 GB trên S3
Nguồn con số: Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations ↗ · mục "Examples of Resource Estimation" (Number of servers required, Storage requirements, Bandwidth requirements) ; Quy tắc ước lượng của khoá học · /hoc/chon-server (1.000 req/s mỗi máy 2 vCPU, chạy tối đa 60% CPU, Redis ×1,3) ; Lý thuyết · Định luật Little: trong hệ thống ổn định, số yêu cầu đang xử lý trung bình L bằng tốc độ đến λ nhân thời gian ở lại trung bình W, tức L = λ × W. Ví dụ λ = 470 req/s và W = 0,08 s thì L = 470 × 0,08 ≈ 38 request cùng lúc; mỗi instance xử lý được c request đồng thời thì cần ít nhất L ÷ c instance, rồi chia thêm cho 0,6 để chừa chỗ cho đỉnh. Định luật đúng cho mọi hàng đợi ổn định, không phụ thuộc phân phối thời gian đến hay thời gian xử lý, nên dùng được để kiểm tra chéo kết quả ước lượng.
Bảng hạ tầng
| Thành phần | Chọn | Số lượng | Cấu hình | Vì sao |
|---|---|---|---|---|
| CDN | Cloudflare | 1 | Cache đề bài, JS editor | Đề gần như tĩnh, CDN đỡ phần đọc. |
| API | Node.js (NestJS), Docker trên Cloud Run | 2 | 2 vCPU · 4 GB RAM | 63 req/s chỉ cần 1 instance, chạy 2 để dự phòng. |
| Database + queue | PostgreSQL managed, bảng jobs dùng SELECT ... FOR UPDATE SKIP LOCKED | 1 | 2 vCPU · 8 GB · 50 GB SSD | 3 job/s là quá nhỏ để cần hệ thống queue riêng; bảng xếp hạng 1.000 người tính bằng SQL, cache 10 s. |
| Judge | VM chạy Docker (--network none, cgroups, seccomp, read-only) | 2 | 8 vCPU · 16 GB, 7 slot mỗi máy | 6,7 slot lúc đỉnh vừa 1 máy, máy thứ 2 để dự phòng; tách khỏi API và không có credential. |
| Lưu test | S3 / GCS | 1 | 10 GB, judge cache ra đĩa local | Test lớn không để trong DB; tải một lần rồi dùng lại. |
- Điểm xuất phát: API, Postgres và máy judge tách riêng ngay từ đầu vì chạy code lạ
- Postgres kiêm hàng đợi bằng SKIP LOCKED, chưa cần Redis hay SQS
- Bảng xếp hạng là một câu SQL cache 10 s
Contest vài chục nghìn người đẩy hàng trăm bài/s: bảng jobs trên Postgres bị tranh khóa, hai máy judge không đủ slot và câu SQL bảng xếp hạng quá nặng khi hàng nghìn người cùng xem.
Cấu hình và chi phí là ước lượng để học và trình bày trong phỏng vấn. Xem cách tính ở bài Chọn server.
So sánh nhanh ba mức
| Thành phần | Mức 1 | Mức 2 | Mức 3 |
|---|---|---|---|
| Người dùng | 10.000 DAU, 500 bài, contest hằng tuần 1.000 người | 1 triệu DAU, 3.000 bài, contest 50.000 người | 10 triệu DAU; contest toàn cầu 500.000 người |
| Chi phí | ≈ 300–700 USD/tháng (ước lượng) | ≈ 8.000–20.000 USD/tháng (ước lượng, phụ thuộc số giờ contest) | ≈ 100.000–200.000 USD/tháng (ước lượng, phần lớn là máy judge) |
| CDN | Cloudflare 1 × Cache đề bài, JS editor | CloudFront / Cloudflare 1 × Đề bài, snapshot bảng xếp hạng TTL 2 s | Chưa cần |
| API | Node.js (NestJS), Docker trên Cloud Run 2 × 2 vCPU · 4 GB RAM | Node.js, container autoscale 2–9 (autoscale) × 2 vCPU · 4 GB RAM | Node.js trên Kubernetes, multi-AZ 83 pod (HPA) × 2 vCPU · 4 GB mỗi pod |
| Database + queue | PostgreSQL managed, bảng jobs dùng SELECT ... FOR UPDATE SKIP LOCKED 1 × 2 vCPU · 8 GB · 50 GB SSD | Chưa cần | Chưa cần |
| Judge | VM chạy Docker (--network none, cgroups, seccomp, read-only) 2 × 8 vCPU · 16 GB, 7 slot mỗi máy | VM + gVisor (runsc), autoscale theo độ dài queue 17–28 (theo lịch contest) × 16 vCPU · 32 GB, 14 slot mỗi máy | Firecracker microVM trên bare-metal, pool ấm 27–44 máy (theo lịch contest) × 96 vCPU · 384 GB, 88 slot mỗi máy |
| Lưu test | S3 / GCS 1 × 10 GB, judge cache ra đĩa local | Chưa cần | Chưa cần |
| Queue | Chưa cần | Amazon SQS, 3 hàng: contest, luyện tập, chạy thử 3 queue × Visibility timeout 60 s, dead-letter queue | SQS theo mức ưu tiên và theo ngôn ngữ ≈ 12 queue × Visibility timeout, dead-letter queue |
| Redis | Chưa cần | ElastiCache 1 primary + 1 replica × 2 vCPU · 4 GB | ElastiCache 1 primary + 2 replica × 4 vCPU · 8 GB |
| Database | Chưa cần | PostgreSQL managed (HA) 1 primary + 1 read replica × 4 vCPU · 16 GB · 500 GB SSD | Aurora PostgreSQL, multi-AZ 1 primary + 2 replica × 8 vCPU · 32 GB |
| Lưu trữ | Chưa cần | S3 1 × Test 3.000 bài × 20 MB = 60 GB; code 1,46 TB/năm | Chưa cần |
| CDN + WAF | Chưa cần | Chưa cần | Cloudflare / CloudFront 1 × Đề bài, snapshot bảng xếp hạng TTL 2 s |
| Submission store | Chưa cần | Chưa cần | DynamoDB (PK user_id, SK submission_id) + S3 cho code 1 bảng × ≈ 1.900 ghi/s đỉnh, 1,46 TB/năm |
| Kafka | Chưa cần | Chưa cần | MSK / Confluent 3 broker × Topic verdicts 6 partition, RF 3 |
| Leaderboard service | Chưa cần | Chưa cần | Node.js consumer, một consumer mỗi contest 3 pod × 2 vCPU · 4 GB mỗi pod |
Đào sâu
Mỗi câu hỏi đi từ cách đơn giản đến cách người phỏng vấn mong đợi ở cấp senior.
1) Chạy code bất kỳ của người lạ thế nào cho an toàn?
Code người dùng chạy cùng máy, cùng quyền với API. Một dòng đọc biến môi trường là lộ key DB, một fork bomb là sập API, và code có thể gọi mạng ra ngoài.
Đánh đổi: Dựng nhanh nhất cho demo, không bao giờ dùng được cho người lạ.
Nguồn: Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Schedule and execute untrusted tasks" (sandbox bằng Docker hoặc máy ảo, giới hạn và dừng tác vụ vượt tài nguyên) ; Chưa có nguồn trong thư viện: child_process.exec của Node.js ở mức cách ly (xem Node.js in Practice về child_process nhưng sách không nói về bảo mật chạy code lạ)
Chạy với --network none, --memory, --cpus, --pids-limit, rootfs read-only, user không phải root, seccomp mặc định, giết sau thời gian tối đa. Máy judge ở subnet riêng, không giữ credential nào.
Đánh đổi: Container dùng chung kernel với host, một lỗ hổng kernel là thoát ra ngoài; tạo container mới cho mỗi lần chấm tốn vài trăm ms.
Nguồn: Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Schedule and execute untrusted tasks" (sandbox bằng Docker hoặc máy ảo, giới hạn và dừng tác vụ vượt tài nguyên) ; Chưa có nguồn trong thư viện: các cờ --network none, --pids-limit, seccomp và cgroups cụ thể (không có sách về Docker/Kubernetes trong thư viện)
gVisor chặn syscall bằng một kernel chạy ở user space; Firecracker cho mỗi lần chạy một microVM KVM riêng, khởi động khoảng 125 ms. Giữ sẵn một pool sandbox ấm để không trả chi phí khởi động. Test ẩn mount read-only, việc so output làm bên ngoài sandbox nên code không thấy đáp án. Mỗi sandbox ghim 1 vCPU riêng và đo CPU time qua cgroup để kết quả TLE công bằng.
Đánh đổi: gVisor làm chương trình nhiều I/O chậm hơn nên phải chỉnh time limit theo ngôn ngữ; Firecracker cần máy bare-metal hoặc hỗ trợ ảo hóa lồng.
Nguồn: Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Schedule and execute untrusted tasks" (sandbox bằng Docker hoặc máy ảo, giới hạn và dừng tác vụ vượt tài nguyên) (nêu máy ảo làm cách ly) ; Chưa có nguồn trong thư viện: gVisor và Firecracker không có sách trong thư viện, giữ ở mức khái niệm; con số 125 ms là của nhà cung cấp, không đưa vào để kiểm chứng
2) Phút cuối contest, hàng trăm submission mỗi giây đổ vào. Xếp hàng thế nào?
Mỗi request chiếm connection 2-10 s. Khi judge đầy, request timeout, người dùng bấm nộp lại và tải tăng gấp đôi. API crash là mất submission.
Đánh đổi: Đơn giản nhưng sập đúng lúc quan trọng nhất.
Nguồn: Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Motivation" (Improved performance, Granular scalability) · mục "Improved performance" (tách tác vụ chậm khỏi đường chính) ; Grokking Modern System Design · ch.4 Non-functional System Characteristics ↗ · mục "Reliability"
API lưu submission rồi mới đẩy job, judge kéo job theo sức của mình. Job có visibility timeout: judge chết giữa chừng thì job tự quay lại queue. Chấm theo submissionId nên chấm lại hai lần vẫn ra cùng kết quả (Grokking ch.17).
Đánh đổi: Không mất bài nhưng contest và luyện tập chung một hàng thì người thi phải chờ sau hàng nghìn bài luyện tập.
Nguồn: Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Distributed messaging queue" và Back-end service (visibility_timeout, giao ít nhất một lần) ; Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Task idempotency" ; Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Motivation" (Improved performance, Granular scalability)
Ba hàng riêng: contest, luyện tập, chạy thử test ví dụ (nhẹ). Judge luôn lấy contest trước, giống phần ưu tiên tác vụ trong Grokking ch.23. Mỗi người tối đa 1 lần nộp mỗi 10 s cho một bài (token bucket, Grokking ch.19) để chặn spam. Penalty tính theo thời điểm API nhận bài chứ không theo lúc chấm xong, nên hàng đợi dài không làm ai thiệt. Kết quả đẩy về qua WebSocket thay cho poll.
Đánh đổi: Bài luyện tập có thể chờ vài phút trong giờ contest; cần theo dõi để hàng ưu tiên thấp không bị bỏ đói mãi.
Nguồn: Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Prioritization" (hàng ưu tiên riêng) ; Grokking Modern System Design · ch.19 Rate Limiter ↗ · mục "Algorithms for rate limiting" (Token bucket algorithm) ; Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Motivation" (Priority queue) ; Grokking Modern System Design · ch.36 WhatsApp ↗ · mục "Connection with a WebSocket server" ; Chưa có nguồn trong thư viện: penalty tính theo giờ nhận bài là quy tắc contest của khoá học
3) Bảng xếp hạng cho 500.000 người thi, cập nhật trong vài giây, làm thế nào?
Mỗi lần xem tính lại điểm cho mọi người từ hàng triệu submission. Với 50.000 lượt xem mỗi giây thì DB chết trước khi contest kết thúc.
Đánh đổi: Đúng và đơn giản cho contest vài trăm người.
Nguồn: Redis in Action ↗ · ch.1 · §1.2.5 Sorted sets in Redis (tr. 13) ; Redis in Action ↗ · ch.3 · §3.5 Sorted sets (tr. 50) ; Chưa có nguồn trong thư viện: GROUP BY/ORDER BY trên bảng lớn là ví dụ minh họa của khoá học
Sorted set giữ thứ tự sẵn nên đọc top hay hạng một người đều theo thứ tự đã giữ sẵn (Redis in Action §1.2.5). Gộp hai tiêu chí vào một score: số bài × 10^7 − penalty (giây), penalty luôn dưới 10^7 nên nhiều bài hơn luôn đứng trên.
Đánh đổi: Nhanh nhưng mọi lượt xem vẫn đến Redis; Redis mất dữ liệu thì phải có chỗ dựng lại.
Nguồn: Redis in Action ↗ · ch.1 · §1.2.5 Sorted sets in Redis (tr. 13) ; Redis in Action ↗ · ch.3 · §3.5 Sorted sets (tr. 50) (ZADD, ZREVRANGE, ZREVRANK) ; Chưa có nguồn trong thư viện: độ phức tạp O(log N) và cách gộp score là kiến thức chung/thiết kế của khoá học
Một consumer duy nhất cho mỗi contest đọc sự kiện verdict theo thứ tự, chỉ tính AC đầu tiên mỗi bài, ghi ContestStanding vào DB rồi ZADD. Mỗi 2 s chụp top 1.000 thành file JSON lên CDN, nên 50.000 lượt xem/s không chạm origin. Chỉ thứ hạng riêng mới gọi ZREVRANK, và client chỉ hỏi mỗi 30 s. Có thể đóng băng bảng trong giờ cuối như ICPC.
Đánh đổi: Bảng trễ khoảng 2 s; điểm hòa cần quy tắc phụ (ví dụ thời điểm AC cuối) và rejudge phải tính lại cả bảng từ DB.
Nguồn: Redis in Action ↗ · ch.1 · §1.2.5 Sorted sets in Redis (tr. 13) ; Redis in Action ↗ · ch.3 · §3.5 Sorted sets (tr. 50) ; Grokking Modern System Design · ch.11 CDN ↗ · mục "Time-to-live (TTL)" ; Grokking Modern System Design · ch.17 Distributed Messaging Queue ↗ · mục "Motivation" (Improved performance, Granular scalability) ; Chưa có nguồn trong thư viện: đóng băng bảng kiểu ICPC là quy tắc contest
4) Cần bao nhiêu judge worker và scale thế nào khi contest bắt đầu?
Fleet cố định thì phần lớn thời gian ngồi không. Autoscale theo CPU thì vô dụng: judge bận là CPU 100%, và máy mới cần vài phút để lên trong khi hàng đợi đã dài.
Đánh đổi: Hoặc tốn tiền, hoặc chậm đúng lúc cần.
Nguồn: Quy tắc ước lượng của khoá học · /hoc/chon-server (1.000 req/s mỗi máy 2 vCPU, chạy tối đa 60% CPU, Redis ×1,3) (autoscale theo CPU kém với tải đột biến, máy mới cần 1-3 phút) ; Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Resource capacity optimization"
Số slot cần = tốc độ nộp × thời gian chấm trung bình. Ví dụ 190 bài/s × 2 s = 380 slot. Autoscale theo số job đang chờ chia cho tốc độ xử lý, thay vì theo CPU.
Đánh đổi: Phản ứng đúng hướng nhưng vẫn trễ vài phút cho máy mới và tải image.
Nguồn: Lý thuyết · Định luật Little: trong hệ thống ổn định, số yêu cầu đang xử lý trung bình L bằng tốc độ đến λ nhân thời gian ở lại trung bình W, tức L = λ × W. Ví dụ λ = 470 req/s và W = 0,08 s thì L = 470 × 0,08 ≈ 38 request cùng lúc; mỗi instance xử lý được c request đồng thời thì cần ít nhất L ÷ c instance, rồi chia thêm cho 0,6 để chừa chỗ cho đỉnh. Định luật đúng cho mọi hàng đợi ổn định, không phụ thuộc phân phối thời gian đến hay thời gian xử lý, nên dùng được để kiểm tra chéo kết quả ước lượng. ; Quy tắc ước lượng của khoá học · /hoc/chon-server (1.000 req/s mỗi máy 2 vCPU, chạy tối đa 60% CPU, Redis ×1,3) ; Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Queueing"
Contest có giờ cố định nên scale lên đủ slot 30 phút trước khi bắt đầu. Máy judge có sẵn image ngôn ngữ, sandbox ấm và test của các bài trong contest đã tải về SSD. Chia pool theo ngôn ngữ (C++ biên dịch lâu, Python chạy chậm) để không pool nào chặn pool khác. Hàng contest chạy trên máy on-demand, hàng luyện tập có thể dùng spot.
Đánh đổi: Trả tiền cho máy chờ trước giờ thi; phải giữ cấu hình máy đồng nhất để thời gian chạy so sánh được.
Nguồn: Grokking Modern System Design · ch.23 Distributed Task Scheduler ↗ · mục "Resource capacity optimization" và "Prioritization" ; Chưa có nguồn trong thư viện: spot instance và scale theo lịch là thực hành vận hành của khoá học
Trong phỏng vấn
- “Code người dùng là code thù địch: tôi chạy trong sandbox có lớp cách ly kernel, không mạng, không credential, giới hạn CPU, RAM, số tiến trình.”
- “Nộp bài trả 202 và đi qua queue bền; penalty tính theo giờ nộp nên hàng đợi dài không làm ai thiệt.”
- “Số slot judge = tốc độ nộp × thời gian chấm; contest có lịch nên tôi scale sẵn thay vì chờ autoscale.”
- “Bảng xếp hạng là Redis sorted set với score = số bài × 10^7 − penalty, trang top là snapshot trên CDN, DB là nguồn sự thật.”
- Chạy code người dùng trên cùng máy với API.
- Giữ request HTTP mở đến khi chấm xong.
- Autoscale judge theo CPU, trong khi judge bận thì CPU luôn 100%.
- Tính bảng xếp hạng bằng SQL ở mỗi lượt xem.
Đọc thêm
Sách trong thư viện của bạn. Số chương có thể lệch nhẹ so với bản PDF.