Lưu trữ và đồng bộ file
Hiểu đề
Yêu cầu chức năng
- Người dùng có thể tải file lên, kể cả file vài GB qua mạng chập chờn
- Người dùng có thể tải file xuống và xem lại các phiên bản cũ
- Thay đổi trên một thiết bị được đồng bộ sang các thiết bị khác của người dùng
- Người dùng có thể chia sẻ file/thư mục cho người khác với quyền xem hoặc sửa
Yêu cầu phi chức năng
- Không mất dữ liệu: độ bền 99,999999999% (11 số 9) cho file đã tải lên xong
- Thay đổi xuất hiện trên thiết bị khác trong ≤ 5 s khi cả hai đang online
- Upload tiếp tục được sau khi rớt mạng, chỉ gửi lại phần còn thiếu (chunk 4 MB)
- API metadata p95 < 200 ms, độ sẵn sàng 99,9%
- File tối đa 50 GB
Ngoài phạm vi: Chỉnh sửa tài liệu cùng lúc kiểu Google Docs; Tìm kiếm toàn văn bên trong nội dung file; Quét virus, xem trước (preview) chi tiết từng định dạng; Thanh toán và quản lý gói dung lượng.
Thực thể và API
| Method | Endpoint | Ghi chú |
|---|---|---|
| POST | /v1/uploads | Body {path, size, chunkHashes[]}. Trả uploadId, danh sách chunk server chưa có và presigned URL cho từng chunk đó. |
| PUT | {presigned URL của blob store} | Client đẩy thẳng từng chunk lên S3/GCS, không đi qua API server. |
| POST | /v1/uploads/{uploadId}/commit | Body {baseRevision}. Tạo FileVersion mới; trả 409 nếu file đã bị sửa từ revision khác. |
| GET | /v1/files/{fileId}?rev= | Trả metadata và presigned GET URL cho từng chunk của phiên bản cần tải. |
| GET | /v1/changes?cursor= | Trả các thay đổi sau cursor cùng cursor mới. Không có gì mới thì giữ kết nối tối đa 30-60 s (long-poll). |
| POST | /v1/shares | Body {folderId, email, role}. Thêm thành viên vào namespace của thư mục chia sẻ. |
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ể tải file lên
File được cắt thành chunk 4 MB ngay trên client. Client chỉ gửi hash lên API, API trả về chunk nào còn thiếu kèm presigned URL, dữ liệu đi thẳng vào blob store. Metadata chỉ được ghi khi mọi chunk đã nằm an toàn trong storage.
- 1Client cắt file thành chunk 4 MB, tính SHA-256 từng chunk
- 2POST /v1/uploads gửi danh sách hash; API tra bảng Chunk để biết chunk nào đã có
- 3API trả presigned PUT URL (hạn 1 giờ) cho các chunk còn thiếu
- 4Client PUT song song 3-4 chunk thẳng lên S3, chunk lỗi thì gửi lại riêng chunk đó
- 5POST /commit: API kiểm tra đủ chunk, ghi FileVersion + FileEntry + ChangeEntry trong một transaction
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Detailed design" (blob chia thành chunk, manager node lưu chunk ID và data node) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Design Considerations of a Blob Store · mục "Partition data" (chọn kích thước chunk cố định) ; Microservices Patterns ↗ (.zip) · ch.3 · §3.3.7 Transactional messaging (tr. 97–100) ; Chưa có nguồn trong thư viện: presigned URL là tính năng của nhà cung cấp object storage, thư viện không có sách mô tả ; Chưa có nguồn trong thư viện: băm SHA-256 từng chunk để biết chunk đã có
2) Người dùng có thể tải file xuống và xem phiên bản cũ
Tải xuống cũng không đi qua API. API trả danh sách chunk của phiên bản cần tải kèm presigned GET URL, client tải song song và ghép lại. Phiên bản cũ chỉ là một FileVersion khác trỏ tới các chunk cũ nên không tốn thêm bản sao.
- 1GET /v1/files/{id}?rev=12 trả danh sách hash chunk theo thứ tự
- 2API ký presigned GET URL cho từng chunk (hoặc URL qua CDN với link chia sẻ công khai)
- 3Client tải song song, kiểm tra SHA-256 từng chunk, ghép thành file
- 4Chunk nào máy đã có sẵn (từ phiên bản trước) thì bỏ qua không tải
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Detailed design" (blob chia thành chunk, manager node lưu chunk ID và data node) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Workflow" (đọc: manager trả chunk và data node, client đọc chunk) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Workflow" (blob mới chỉ nhận version number, không sửa blob cũ) ; Grokking Modern System Design · ch.11 Content Delivery Network (CDN) ↗ · mục "Pull CDN" ; Chưa có nguồn trong thư viện: presigned URL là tính năng của nhà cung cấp object storage, thư viện không có sách mô tả
3) Thay đổi được đồng bộ sang thiết bị khác
Mỗi namespace có change log với seq tăng dần. Thiết bị giữ cursor (seq cuối cùng đã thấy) và hỏi phần thay đổi sau cursor đó. Ở quy mô lớn, server chỉ đẩy tín hiệu 'có thay đổi' qua kết nối mở, thiết bị tự kéo phần delta.
- 1Commit thành công ghi ChangeEntry (namespace_id, seq+1)
- 2Notification service báo cho các thiết bị đang theo dõi namespace đó
- 3Thiết bị gọi GET /v1/changes?cursor=... nhận danh sách file đổi và cursor mới
- 4Với mỗi file đổi, so danh sách chunk mới với chunk đang có, chỉ tải chunk thiếu
- 5Thiết bị offline lâu thì khi online lại cũng chỉ cần cursor để bắt kịp
Nguồn: Grokking Modern System Design · ch.36 WhatsApp ↗ · Detailed Design of WhatsApp · mục "Connection with a WebSocket server" ; Grokking Modern System Design · ch.18 Pub-sub ↗ · mục "High-level design" (broker, consumer manager) ; Microservices Patterns ↗ (.zip) · ch.3 · §3.3.7 Transactional messaging (tr. 97–100) ; Chưa có nguồn trong thư viện: mô hình change log + cursor theo namespace là thiết kế của khoá học
4) Người dùng có thể chia sẻ thư mục
Thư mục chia sẻ được tách thành một namespace riêng và gắn vào cây thư mục của từng thành viên. Quyền được kiểm tra ở mức namespace, không phải từng file, nên thêm người không cần sao chép hay cập nhật hàng nghìn bản ghi.
- 1POST /v1/shares: nếu thư mục chưa là namespace riêng thì tách ra, ghi ShareMember
- 2Người nhận nhận email/thông báo, chấp nhận thì namespace được gắn vào cây của họ
- 3Mọi request đọc/ghi kiểm tra ShareMember (cache trong Redis) theo namespace_id
- 4Thiết bị của người nhận bắt đầu theo dõi change log của namespace mới
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Workflow" (kiểm tra quyền truy cập blob ở front-end) ; 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) ; Chưa có nguồn trong thư viện: mô hình namespace dùng chung và bảng ShareMember 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.
Ổ lưu trữ cho một công ty hoặc sản phẩm mới. Hai instance API chỉ lo metadata và ký URL, dữ liệu đi thẳng vào S3, một Postgres chứa toàn bộ metadata. Đồng bộ bằng poll change log 30 s.
Ước lượng
- Upload: 10.000 DAU × 2 file × 1 MB = 20.000 MB = 20 GB/ngày → 20 GB × 365 = 7.300 GB ≈ 7,3 TB/năm trên S3
- Băng thông upload: 20.000 MB / 86.400 ≈ 0,23 MB/s, đỉnh ×10 ≈ 2,3 MB/s, đi thẳng vào S3
- Đồng bộ: 10.000 × 1,5 thiết bị × 20% online = 3.000 thiết bị, poll 30 s → 3.000 / 30 = 100 req/s
- Thao tác khác: 10.000 × 50 req / 86.400 ≈ 5,8 req/s, đỉnh ×10 ≈ 58 req/s; tổng ≈ 158 req/s
- API: ceil(158 / (1.000 × 0,6)) = 1 → lấy tối thiểu 2 instance
- Metadata: 20.000 tài khoản × 500 file × 500 B = 5.000.000.000 B ≈ 5 GB
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) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Requirements of a Blob Store's Design · mục "Resource estimation" ; 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)
Bảng hạ tầng
| Thành phần | Chọn | Số lượng | Cấu hình | Vì sao |
|---|---|---|---|---|
| API metadata | Node.js (NestJS), Docker trên Cloud Run | 2 | 2 vCPU · 4 GB RAM | 158 req/s chỉ cần 1 instance, chạy 2 để dự phòng; không có byte file nào đi qua API. |
| Database | PostgreSQL managed | 1 | 2 vCPU · 8 GB · 50 GB SSD | 5 GB metadata nằm gọn trong RAM; transaction commit đơn giản. |
| Blob storage | Amazon S3 / Google Cloud Storage | 1 bucket | Chunk 4 MB, key = SHA-256, versioning tắt | Độ bền 11 số 9 có sẵn, 7,3 TB/năm chỉ vài trăm USD/tháng. |
| Dọn dẹp | Cloud Scheduler gọi job trong API | 1 | Chạy mỗi giờ | Xóa upload session bỏ dở và chunk refcount = 0; khối lượng nhỏ, chưa cần worker riêng. |
| Amazon SES / SendGrid | 1 | Dịch vụ bên ngoài | Gửi lời mời chia sẻ. |
- Điểm xuất phát: API chỉ xử lý metadata, file đi thẳng S3 bằng presigned URL
- Upload theo chunk 4 MB có thể tiếp tục ngay từ đầu, vì đây là yêu cầu chức năng chứ không phải tối ưu
- Đồng bộ bằng poll change log 30 s là đủ cho 3.000 thiết bị online
Khi số thiết bị online lên hàng trăm nghìn, poll 30 s tạo hàng nghìn request rỗng mỗi giây và độ trễ đồng bộ 30 s là quá chậm. Cần kênh đẩy thông báo và cache quyền truy cập.
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 (khoảng 20.000 tài khoản) | 1 triệu DAU (khoảng 3 triệu tài khoản) | 50 triệu DAU (khoảng 150 triệu tài khoản) |
| Chi phí | ≈ 150–500 USD/tháng (ước lượng, tăng dần theo dung lượng tích lũy) | ≈ 15.000–35.000 USD/tháng (ước lượng, phần lớn là lưu trữ và băng thông tải xuống) | ≈ 400.000–1.000.000 USD/tháng (ước lượng, chủ yếu là lưu trữ tích lũy và băng thông) |
| API metadata | Node.js (NestJS), Docker trên Cloud Run 2 × 2 vCPU · 4 GB RAM | Node.js (NestJS), container autoscale 2–10 (autoscale) × 2 vCPU · 4 GB RAM | Chưa cần |
| Database | PostgreSQL managed 1 × 2 vCPU · 8 GB · 50 GB SSD | PostgreSQL managed (HA) 1 primary + 2 read replica × 8 vCPU · 32 GB · 2 TB SSD | Chưa cần |
| Blob storage | Amazon S3 / Google Cloud Storage 1 bucket × Chunk 4 MB, key = SHA-256, versioning tắt | S3 / GCS, lifecycle sang lớp Infrequent Access sau 30 ngày 1 bucket × ≈ 511 TB/năm sau dedup | S3 nhiều lớp (Standard → IA → Glacier) hoặc blob store tự xây dùng erasure coding Nhiều region × ≈ 25,6 PB/năm sau dedup |
| Dọn dẹp | Cloud Scheduler gọi job trong API 1 × Chạy mỗi giờ | Chưa cần | Chưa cần |
Amazon SES / SendGrid 1 × Dịch vụ bên ngoài | Chưa cần | Chưa cần | |
| Load balancer | Chưa cần | Cloud Load Balancing / ALB 1 × Hỗ trợ WebSocket, TLS | Chưa cần |
| Notification gateway | Chưa cần | Node.js WebSocket + Redis pub/sub 15 × 2 vCPU · 4 GB RAM | Node.js WebSocket trên Kubernetes 750 pod × 2 vCPU · 4 GB mỗi pod |
| Redis | Chưa cần | ElastiCache / Memorystore 1 primary + 1 replica × 2 vCPU · 8 GB | Chưa cần |
| CDN | Chưa cần | CloudFront / Cloud CDN 1 × Link chia sẻ công khai, thumbnail | Chưa cần |
| Queue + Worker | Chưa cần | SQS / Pub/Sub + Node.js consumer 1 queue, 4 worker × 1 vCPU · 2 GB mỗi worker | Chưa cần |
| API gateway + LB | Chưa cần | Chưa cần | Envoy / cloud LB, đa AZ 1 mỗi region × TLS, auth, rate limit |
| Metadata API | Chưa cần | Chưa cần | Node.js trên Kubernetes, 3 AZ 290 pod (HPA) × 2 vCPU · 4 GB mỗi pod |
| Metadata DB | Chưa cần | Chưa cần | MySQL/Vitess hoặc Postgres + Citus, shard theo namespace_id 64 shard × (1 primary + 2 replica) = 192 node × 8 vCPU · 64 GB · 2 TB SSD mỗi node |
| Chỉ mục chunk | Chưa cần | Chưa cần | DynamoDB / Cassandra Managed (hoặc 6 node Cassandra RF 3) × hash → vị trí, refcount |
| Redis Cluster | Chưa cần | Chưa cần | ElastiCache Redis Cluster 6 shard × (1 primary + 1 replica) × 4 vCPU · 32 GB mỗi node |
| Kafka | Chưa cần | Chưa cần | MSK / Confluent 3 broker mỗi region × Topic changes 24 partition, RF 3 |
| Worker | Chưa cần | Chưa cần | Node.js / Go consumer trên Kubernetes 30 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) Tải lên file 5 GB qua mạng 4G chập chờn thế nào cho chắc?
Client POST multipart lên Node.js, server ghi tạm ra đĩa rồi đẩy sang S3. Mỗi upload chiếm một kết nối và băng thông của API trong nhiều phút.
Đánh đổi: Rớt mạng ở 4,9 GB là phải tải lại từ đầu, và API phải scale theo băng thông thay vì theo số request.
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Requirements of a Blob Store's Design · mục "Throughput" và "Number of servers estimation" (front-end server không nên gánh dữ liệu lớn) ; Chưa có nguồn trong thư viện: presigned URL là tính năng của nhà cung cấp object storage, thư viện không có sách mô tả
API chỉ ký một URL có hạn cho đúng object key, client upload thẳng lên S3/GCS. API server thoát khỏi đường đi của dữ liệu, chỉ còn xử lý metadata.
Đánh đổi: Vẫn là một request duy nhất: S3 giới hạn 5 GB cho một PUT và lỗi giữa chừng vẫn phải gửi lại toàn bộ.
⚠ Chưa có nguồn trong thư viện: presigned URL là tính năng của nhà cung cấp object storage, thư viện không có sách mô tả ; Chưa có nguồn trong thư viện: giới hạn 5 GB mỗi PUT là con số của nhà cung cấp, chỉ giữ như ví dụ minh họa
Client cắt file thành chunk, tính hash, tạo upload session lưu danh sách chunk cần có. Mỗi chunk là một PUT riêng bằng presigned URL, gửi song song 3-4 chunk. Rớt mạng thì client hỏi lại session xem còn thiếu chunk nào và chỉ gửi phần đó. Khi đủ thì commit ghi metadata trong một transaction, nên người khác không bao giờ thấy file dở dang. Cách cắt blob thành chunk có kích thước cố định cũng là cách blob store tổ chức dữ liệu (Grokking ch.20).
Đánh đổi: Thêm trạng thái upload session phải dọn (session bỏ dở quá 24 giờ thì xóa chunk mồ côi), và chunk nhỏ làm bảng metadata lớn hơn.
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Detailed design" (blob chia thành chunk, manager node lưu chunk ID và data node) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Design Considerations of a Blob Store · mục "Partition data" (chunk nhỏ làm metadata lớn, chunk quá lớn lãng phí đĩa) ; Microservices Patterns ↗ (.zip) · ch.3 · §3.3.7 Transactional messaging (tr. 97–100) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Design Considerations of a Blob Store · mục "Garbage collection while deleting a blob" (dọn phần mồ côi sau)
2) Đồng bộ thay đổi giữa nhiều thiết bị và xử lý xung đột thế nào?
Client gọi API lấy cả cây thư mục và so với bản local để tìm thay đổi. Thư mục 100.000 file là vài chục MB mỗi lần hỏi.
Đánh đổi: Tốn băng thông và tải DB tỉ lệ với số file chứ không với số thay đổi, độ trễ lên tới 30 s.
Nguồn: Grokking Modern System Design · ch.36 WhatsApp ↗ · Detailed Design of WhatsApp · mục "Connection with a WebSocket server" (so với hỏi lặp lại) ; 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)
Mỗi commit ghi một dòng ChangeEntry với seq tăng dần trong namespace. Client giữ cursor và gọi /changes?cursor=; không có gì mới thì server giữ request 30-60 s rồi trả rỗng. Chỉ phần thay đổi được truyền đi.
Đánh đổi: Hàng trăm nghìn long-poll đang treo vẫn chiếm kết nối HTTP, và mỗi lần hết hạn là một request mới dù không có thay đổi.
Nguồn: Grokking Modern System Design · ch.36 WhatsApp ↗ · mục "Connection with a WebSocket server" ; Chưa có nguồn trong thư viện: long-polling không được sách trong thư viện mô tả; chỉ giữ như phương án trung gian
Notification gateway giữ kết nối nhẹ và chỉ đẩy 'namespace X có seq mới'. Thiết bị tự gọi /changes bằng cursor, nên mất tín hiệu cũng không mất dữ liệu. Commit gửi kèm baseRevision; nếu revision trên server đã khác thì trả 409, client giữ bản của mình thành file 'tên (bản xung đột của Laptop).ext' thay vì ghi đè. Không tự merge nội dung vì không hiểu định dạng file.
Đánh đổi: Người dùng phải tự xử lý bản xung đột, và phải vận hành thêm một lớp giữ hàng triệu kết nối.
Nguồn: Grokking Modern System Design · ch.36 WhatsApp ↗ · mục "Connection with a WebSocket server" ; Grokking Modern System Design · ch.9 Databases ↗ · Data Replication · mục "Multi-leader replication" (Conflict, Handle conflicts: Last-write-wins, Custom logic) ; Chưa có nguồn trong thư viện: baseRevision và file bản xung đột là cách làm của khoá học
3) Làm sao không lưu cùng một dữ liệu nhiều lần (dedup)?
Sửa một dòng trong file 1 GB là lưu thêm 1 GB và tải lại 1 GB lên. 10 phiên bản là 10 GB.
Đánh đổi: Đơn giản nhất nhưng chi phí lưu trữ và băng thông tăng theo số lần sửa.
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Workflow" (blob không sửa tại chỗ, tải bản mới) ; 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) (phép tính dung lượng)
Tính SHA-256 cả file, đã có file cùng hash thì chỉ thêm một FileEntry trỏ vào blob có sẵn. Hiệu quả với file giống hệt nhau như bộ cài, video được chia sẻ lại.
Đánh đổi: Sửa một byte là hash khác hoàn toàn, nên vẫn lưu và tải lại cả file.
⚠ Chưa có nguồn trong thư viện: dedup theo hash nội dung không có trong thư viện
Blob store là content-addressable: key của chunk là SHA-256 của nó. Phiên bản mới chỉ upload các chunk có hash mới, các chunk không đổi được dùng lại, nên sửa đầu file 1 GB chỉ tốn vài chunk. Mỗi chunk có refcount; xóa file chỉ giảm refcount và đánh dấu, garbage collector chạy sau mới xóa chunk về 0 (cách xóa lười như Grokking ch.20). Để chống lộ dữ liệu khi ai đó chỉ biết hash, chỉ dedup giữa các user nếu client đã thực sự upload chunk, hoặc giới hạn dedup trong cùng namespace.
Đánh đổi: Chunk cố định 4 MB mất tác dụng khi chèn dữ liệu vào giữa file (mọi chunk sau đó lệch hash); muốn tốt hơn phải dùng chunk theo nội dung (rolling hash) phức tạp hơn. Refcount sai là mất dữ liệu nên GC phải đối soát kỹ.
Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · Design of a Blob Store · mục "Detailed design" (blob chia thành chunk, manager node lưu chunk ID và data node) ; Grokking Modern System Design · ch.20 Blob Store ↗ · Design Considerations of a Blob Store · mục "Garbage collection while deleting a blob" (đánh dấu xóa trong metadata, collector dọn sau) ; Chưa có nguồn trong thư viện: content-addressable storage, refcount và rolling hash không có trong thư viện
4) Chia sẻ thư mục và kiểm tra quyền thế nào khi một thư mục có hàng chục nghìn file?
Mỗi người nhận có một bản riêng. Người này sửa thì người kia không thấy, và dung lượng nhân theo số người.
Đánh đổi: Sai về mặt sản phẩm và tốn lưu trữ gấp nhiều lần.
⚠ Chưa có nguồn trong thư viện: lập luận sản phẩm về chia sẻ thư mục, không phải kiến thức hệ thống có trong sách
Mỗi file có danh sách ai được đọc/ghi. Kiểm tra quyền chỉ là một lookup theo file_id.
Đánh đổi: Chia sẻ thư mục 50.000 file là ghi 50.000 dòng cho mỗi người nhận, và file mới thêm vào thư mục phải tự kế thừa quyền.
Nguồn: Chưa có nguồn trong thư viện: thiết kế ACL từng file là lựa chọn của khoá học ; Grokking Modern System Design · ch.9 Databases ↗ · Data Partitioning · mục "Sharding"
Khi chia sẻ, thư mục trở thành namespace có change log riêng và được gắn vào cây của từng thành viên. Thêm người chỉ là một dòng ShareMember, file mới tự thuộc namespace nên tự có quyền. Kiểm tra quyền = (user, namespace_id) cache trong Redis. Link công khai là token ký có hạn trỏ tới namespace hoặc file. Shard metadata theo namespace_id thì mọi thao tác trên một thư mục chia sẻ nằm gọn trong một shard.
Đánh đổi: Di chuyển file giữa hai namespace trở thành xóa ở chỗ này và tạo ở chỗ kia, có thể khác shard; thu hồi quyền phải đẩy xuống thiết bị để xóa bản local.
Nguồn: Grokking Modern System Design · ch.9 Databases ↗ · Data Partitioning · mục "Sharding" (chọn khóa phân mảnh, giữ dữ liệu liên quan trong một shard) ; 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) ; Chưa có nguồn trong thư viện: namespace dùng chung, token ký có hạn là thiết kế của khoá học
Trong phỏng vấn
- “Tôi tách đường dữ liệu và đường metadata: byte file đi thẳng vào blob store bằng presigned URL, API chỉ xử lý metadata.”
- “File được cắt chunk 4 MB, khóa bằng SHA-256, nên tôi có cùng lúc upload tiếp tục được, dedup và chỉ gửi phần đổi.”
- “Đồng bộ dựa trên change log có cursor theo namespace; thông báo đẩy chỉ là tín hiệu, mất cũng không sao.”
- “Xung đột không tự merge: commit kèm baseRevision, lệch thì giữ cả hai bản và đặt tên bản xung đột.”
- Cho file đi qua API server, khiến API phải scale theo băng thông.
- Ghi metadata trước khi chunk đã nằm trong storage, người khác thấy file hỏng.
- Đồng bộ bằng cách liệt kê lại cả thư mục định kỳ.
- Quên chi phí lưu trữ tích lũy: dữ liệu chỉ tăng, không bao giờ giảm.
Đọ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.