Harbor

Mạng chia sẻ ảnh

KhóUpload ảnhFan-outCDNBộ đếmGiống Instagram, Lemon8

Hiểu đề

Mạng chia sẻ ảnh là gì? Ứng dụng đăng ảnh kèm chú thích, theo dõi người khác và lướt feed ảnh của những người mình theo dõi. Phần khó nằm ở ba chỗ: nhận và xử lý hàng triệu ảnh mỗi ngày, phát hàng petabyte ảnh qua CDN, và đếm like cho bài của người nổi tiếng.

Yêu cầu chức năng

  1. Người dùng có thể đăng bài gồm 1-10 ảnh kèm chú thích
  2. Người dùng có thể theo dõi và bỏ theo dõi người khác
  3. Người dùng có thể xem feed ảnh từ những người mình theo dõi, mới nhất trước, cuộn vô hạn
  4. Người dùng có thể like, bỏ like và bình luận; mọi người thấy số like và số bình luận của bài

Yêu cầu phi chức năng

  • Mở feed p95 < 300 ms; ảnh đầu tiên hiện trong < 1 s trên mạng 4G
  • Ảnh đã tải lên không bao giờ mất (độ bền 11 số 9 của S3)
  • Bài mới xuất hiện trong feed người theo dõi sau ≤ 10 s; số like được phép trễ vài giây
  • Chịu được bài của tài khoản 10 triệu người theo dõi nhận 1 triệu like trong 10 phút
  • Độ sẵn sàng 99,95% cho xem feed; đọc gấp khoảng 100 lần ghi

Ngoài phạm vi: Video, Reels, Stories, livestream; Tin nhắn trực tiếp; Feed khám phá bằng ML và quảng cáo; Tìm kiếm theo hashtag và địa điểm (xem bài Tìm kiếm bài viết).

Thực thể và API

User
Người dùng: user_id, username, avatar, follower_count, cờ is_celebrity (≥ 10.000 người theo dõi).
Follow
Quan hệ một chiều (follower_id, followee_id, created_at); lưu theo cả hai chiều để tra nhanh.
Post
Bài: post_id (Snowflake, sắp được theo thời gian), author_id, caption, media_ids[], status PENDING/READY, created_at.
Media
Một ảnh: media_id, khóa S3 của bản gốc, các bản resize (1080, 640, 320, 150 px), width, height, blurhash.
Like / Comment
Like (post_id, user_id) duy nhất; Comment (comment_id, post_id, user_id, text). Số đếm lưu riêng trong bộ đếm.
Timeline
Feed dựng sẵn của một người: danh sách post_id mới nhất (tối đa 500) trong Redis.
MethodEndpointGhi chú
POST/v1/media/uploadsXin presigned URL: body {contentType, size}. Trả media_id và URL PUT thẳng lên S3, hết hạn sau 10 phút.
POST/v1/postsTạo bài {caption, mediaIds[]} sau khi ảnh đã lên S3. Header Idempotency-Key, trả post ở trạng thái PENDING.
GET/v1/feed?cursor=Trả 20 bài kèm URL ảnh CDN theo kích thước phù hợp thiết bị và cursor là post_id cuối.
PUT/v1/posts/{id}/likeLike idempotent; DELETE cùng đường dẫn để bỏ like.
POST/v1/posts/{id}/commentsBình luận; GET /v1/posts/{id}/comments?cursor= để đọc.
PUT/v1/users/{id}/followTheo dõi; DELETE để bỏ theo dõi.

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ể đăng bài ảnh

File ảnh không đi qua API server. Client xin presigned URL, tải thẳng lên S3, rồi tạo bài. Worker resize ảnh thành nhiều kích thước; chỉ khi xong thì bài chuyển sang READY và được phát cho người theo dõi.

  1. 1Client nén ảnh về cạnh dài 1080 px rồi gọi POST /v1/media/uploads, nhận media_id + presigned URL
  2. 2Client PUT ảnh thẳng lên bucket uploads/ của S3
  3. 3S3 phát sự kiện ObjectCreated vào queue, worker kiểm tra định dạng thật, bỏ EXIF GPS, sinh 4 kích thước WebP và blurhash
  4. 4Client gọi POST /v1/posts {caption, mediaIds}; bài ở trạng thái PENDING
  5. 5Khi mọi media đã xử lý xong, bài chuyển READY và phát sự kiện post_ready cho fan-out

Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · mục "Detailed design" và "Stream a file" ; Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "Upload, view, and search a photo"

2) Người dùng có thể xem feed

Feed đọc rất nhiều nên được dựng sẵn khi có bài mới (push) cho phần lớn tác giả. Bài của người nổi tiếng được kéo lúc đọc (pull) rồi trộn vào. Feed chỉ chứa post_id, nội dung và URL ảnh lấy từ cache.

  1. 1Client gọi GET /v1/feed
  2. 2Feed service đọc 500 post_id gần nhất từ Redis timeline:{userId}
  3. 3Lấy thêm bài mới của những người nổi tiếng mà user theo dõi (thường vài chục người) từ cache bài theo tác giả
  4. 4Trộn theo post_id giảm dần, lấy 20 bài, lấy nội dung và số like theo lô
  5. 5Trả URL CDN dạng /m/{media_id}/640.webp, client chọn kích thước theo màn hình

Nguồn: Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "Generate a timeline" (The pull approach, The push approach, Hybrid approach)

3) Người dùng có thể like và bình luận

Bảng like là nguồn sự thật và đảm bảo mỗi người chỉ like một lần. Số like hiển thị lấy từ bộ đếm riêng, cập nhật bất đồng bộ, nên một bài nóng không biến thành một hàng bị khóa liên tục.

  1. 1Client gọi PUT /v1/posts/{id}/like
  2. 2Like service ghi (post_id, user_id) vào bảng like; trùng thì trả 200 không làm gì
  3. 3Phát sự kiện like vào Kafka
  4. 4Bộ đếm cộng dồn vào Redis (bài nóng chia nhiều shard đếm), định kỳ ghi số tổng xuống DB
  5. 5Feed đọc số like từ Redis, hiển thị dạng rút gọn (1,2 N; 3,4 Tr)

Nguồn: Grokking Modern System Design · ch.24 Sharded Counters ↗ · mục "Detailed design" (Burst of writes requests, Manage read requests) ; Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "Like or dislike posts"

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.

Người dùng
10.000 DAU
Tải đỉnh
≈ 69 req/s đỉnh
Chi phí ước lượng
≈ 150–600 USD/tháng (ước lượng, chủ yếu là CDN)

Ứng dụng ảnh cho một cộng đồng nhỏ. Hai instance Node, một Postgres, ảnh lên S3 bằng presigned URL và phát qua CDN. Feed dựng lúc đọc bằng một câu SQL.

Người dùngApp di độngCDNCDNDịch vụAPI Node.jsLưu trữS3 ảnhDatabasePostgreSQLWorkerResize (Lambda)Bên ngoàiFCM pushxem ảnhHTTPSPUT presignedoriginfeed SQLfile mớithông báo

Ước lượng

  • Request: 10.000 × 60 (feed, like, profile...) / 86.400 ≈ 6,9 req/s, đỉnh ×10 ≈ 69 req/s
  • API: ceil(69 / (1.000 × 0,6)) = 1 → lấy tối thiểu 2 instance để dự phòng
  • Ảnh mới: 10.000 × 0,1 = 1.000 ảnh/ngày × 2 MB (gốc + 4 bản resize) = 2 GB/ngày ≈ 730 GB/năm
  • Ảnh xem: 10.000 × 200 ảnh × 100 KB = 200 GB/ngày ≈ 6 TB/tháng qua CDN
  • Like: 10.000 × 20 / 86.400 ≈ 2,3/s, đỉnh ×10 ≈ 23/s; UPDATE cộng dồn trên Postgres vẫn nhẹ

Nguồn con số: Grokking Modern System Design · ch.5 Back-of-the-envelope Calculations ↗ · mục "Standard numbers to remember" và "Requests estimation" ; Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "Number of servers estimation" (500 triệu DAU, 1.157 server) ; Quy tắc ước lượng của khoá học · /hoc/chon-server

Bảng hạ tầng

Thành phầnChọnSố lượngCấu hìnhVì sao
APINode.js (NestJS), Docker trên Cloud Run22 vCPU · 4 GB RAM69 req/s đỉnh chỉ cần 1 instance; API không nhận byte ảnh nào nên rất nhẹ.
DatabasePostgreSQL managed12 vCPU · 8 GB · 50 GB SSDUser, follow, post, like, comment; feed dựng bằng WHERE author_id IN (...) ORDER BY id DESC LIMIT 20.
Lưu ảnhS3 / GCS, presigned URL1 bucket≈ 730 GB/nămClient tải thẳng lên bucket; ảnh không bao giờ nằm trong DB.
Resize ảnhLambda / Cloud Function dùng sharptheo sự kiện1-2 GB RAM1.000 ảnh/ngày × khoảng 1 s CPU, không cần server thường trực.
CDNCloudflare / CloudFront1≈ 6 TB/thángẢnh là phần băng thông lớn nhất ngay từ ngày đầu.
Push notificationFirebase Cloud Messaging1Dịch vụ bên ngoàiBáo like, bình luận, người theo dõi mới; miễn phí.
Thay đổi so với mức trước
  • Điểm xuất phát: một API, một Postgres, ảnh trên S3 qua CDN
  • Ảnh tải thẳng lên S3 bằng presigned URL ngay từ đầu
  • Feed dựng lúc đọc (pull) vì mỗi người chỉ theo dõi vài trăm tài khoản ít bài
Nút thắt tiếp theo

Ở 1 triệu DAU, câu SQL gộp bài của hàng trăm người theo dõi chạy hơn 1.000 lần/giây lúc đỉnh và chiếm hết CPU của Postgres, còn resize bằng function bắt đầu đắt và chậm khởi động.

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ầnMức 1Mức 2Mức 3
Người dùng10.000 DAU1 triệu DAU50 triệu DAU
Chi phí≈ 150–600 USD/tháng (ước lượng, chủ yếu là CDN)≈ 10.000–25.000 USD/tháng (ước lượng, CDN chiếm hơn một nửa)≈ 300.000–700.000 USD/tháng (ước lượng, CDN và lưu trữ ảnh chiếm phần lớn)
API
Node.js (NestJS), Docker trên Cloud Run
2 × 2 vCPU · 4 GB RAM
Node.js (NestJS), container autoscale
2–6 (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 · 1 TB SSD
Chưa cần
Lưu ảnh
S3 / GCS, presigned URL
1 bucket × ≈ 730 GB/năm
S3, lifecycle sang lớp IA sau 90 ngày
1 bucket × ≈ 73 TB/năm
S3 nhân bản 2 region, lifecycle IA/Glacier
multi-region × ≈ 3,65 PB/năm
Resize ảnh
Lambda / Cloud Function dùng sharp
theo sự kiện × 1-2 GB RAM
Chưa cầnChưa cần
CDN
Cloudflare / CloudFront
1 × ≈ 6 TB/tháng
CloudFront / Cloudflare, URL bất biến
1 × ≈ 600 TB/tháng
Chưa cần
Push notification
Firebase Cloud Messaging
1 × Dịch vụ bên ngoài
Chưa cầnChưa cần
QueueChưa cần
SQS / Pub/Sub
2 hàng đợi × media_uploaded, post_ready; có dead-letter queue
Chưa cần
Media workerChưa cần
Node.js + sharp
5 × 2 vCPU · 4 GB RAM
Node.js/Go + libvips trên Kubernetes
37 pod × 8 vCPU · 16 GB mỗi pod
Fan-out workerChưa cần
Node.js, ghi Redis bằng pipeline
2 × 2 vCPU · 4 GB RAM
Consumer Kafka, pipeline Redis
11 pod × 2 vCPU · 4 GB mỗi pod
RedisChưa cần
ElastiCache / Memorystore
1 primary + 1 replica × 2 vCPU · 16 GB
Chưa cần
EdgeChưa cầnChưa cần
GeoDNS + nhiều CDN + origin shield
3 region × ≈ 30 PB/tháng
API (feed, post, like)Chưa cầnChưa cần
Node.js trên Kubernetes, HPA
174 pod × 2 vCPU · 4 GB mỗi pod
Redis ClusterChưa cầnChưa cần
Timeline + cache bài + sharded counter
12 shard × (1 primary + 1 replica) × 4 vCPU · 32 GB mỗi node
Like/Comment storeChưa cầnChưa cần
ScyllaDB, partition theo post_id
9 node (3/AZ) × 8 vCPU · 64 GB · 4 TB NVMe
User/Post/Follow DBChưa cầnChưa cần
PostgreSQL shard theo user_id (Citus/Vitess)
8 shard × (1 primary + 1 replica) × 16 vCPU · 64 GB · 2 TB SSD
KafkaChưa cầnChưa cần
MSK / Confluent
6 broker (2/AZ) × Topic media, post_ready, likes, comments; RF 3

Đà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) Nhận và xử lý 5 triệu ảnh mỗi ngày thế nào mà API server không bị nghẽn?

Cách chưa tốt
Upload multipart qua API, resize đồng bộ trong request

Mỗi ảnh vài MB chạy qua Node.js, chiếm băng thông và bộ nhớ của API, rồi resize 4 kích thước ngay trong request mất 1-2 s CPU. Mạng 4G chập chờn làm request treo lâu và giữ kết nối.

Đánh đổi: Dễ viết nhất, nhưng API vừa tốn băng thông vừa bị CPU resize chặn event loop.

Nguồn: Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "Upload, view, and search a photo"

Cách tốt
Presigned URL lên S3, resize bất đồng bộ bằng worker

API chỉ ký URL, client PUT thẳng lên S3 (Grokking ch.20 Blob Store). S3 phát sự kiện, worker hoặc Lambda dùng sharp sinh các kích thước. API không chạm vào byte ảnh nào.

Đánh đổi: Phải xử lý trường hợp client tạo bài trước khi resize xong và ảnh tải lên nhưng không bao giờ được gắn vào bài.

Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · mục "Detailed design" và "Stream a file" ; Chưa có nguồn trong thư viện: presigned URL và Lambda/sharp không có trong sách

Cách tốt nhất
Pipeline đầy đủ: nén ở client, presigned có ràng buộc, xử lý theo trạng thái, dọn file mồ côi

Client nén về 1080 px trước khi tải (giảm 3 MB xuống khoảng 300-500 KB). Presigned URL giới hạn content-type và kích thước tối đa, key theo media_id; mạng yếu thì dùng multipart upload để tải tiếp phần còn thiếu. Worker kiểm tra magic bytes, bỏ EXIF GPS, sinh 1080/640/320/150 px WebP, blurhash và chạy kiểm duyệt nội dung. Post giữ PENDING tới khi mọi media READY rồi mới fan-out. Bucket uploads/ có lifecycle xóa file không được gắn vào bài sau 24 h.

Đánh đổi: Nhiều trạng thái và nhiều bước bất đồng bộ hơn; người đăng thấy bài ngay trên máy mình nhưng người khác thấy sau vài giây.

Nguồn: Grokking Modern System Design · ch.20 Blob Store ↗ · mục "Detailed design" và "Stream a file" ; Chưa có nguồn trong thư viện: chi tiết nén phía client, EXIF, lifecycle là thực hành chung

2) Dựng feed thế nào khi có cả người dùng thường và tài khoản 10 triệu người theo dõi?

Cách chưa tốt
Pull khi đọc: mỗi lần mở app thì gộp bài của mọi người mình theo dõi

Theo dõi 500 người là truy vấn bài của 500 tác giả, gộp và sắp xếp cho mỗi lần mở feed. Grokking ch.33 chỉ ra phần lớn tác giả không có bài mới nên đa số truy vấn trả về rỗng.

Đánh đổi: Ghi rẻ, nhưng đọc chậm và tốn kém trong một hệ thống đọc gấp 100 lần ghi.

Nguồn: Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "The pull approach"

Cách tốt
Push khi ghi: chép post_id vào feed của mọi người theo dõi

Khi bài READY, worker thêm post_id vào danh sách Redis của từng người theo dõi. Mở feed chỉ còn là một lệnh đọc danh sách.

Đánh đổi: Một bài của tài khoản 10 triệu người theo dõi tạo 10 triệu lần ghi, feed của mọi người bị trễ theo hàng đợi fan-out.

Nguồn: Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "The push approach"

Cách tốt nhất
Hybrid: push cho tác giả thường, pull cho người nổi tiếng, chỉ push tới người dùng còn hoạt động

Tác giả dưới 10.000 người theo dõi thì push. Người nổi tiếng không push; lúc đọc, feed service lấy bài mới của vài chục người nổi tiếng mà user theo dõi từ cache bài theo tác giả rồi trộn vào (Grokking ch.33). Chỉ push tới người đã mở app trong 30 ngày; người lâu không vào thì dựng lại feed bằng pull khi họ quay lại. Timeline chỉ chứa post_id 8 B, cắt ở 500 phần tử.

Đánh đổi: Đường đọc phức tạp hơn và phải chọn ngưỡng người nổi tiếng; người vừa vượt ngưỡng cần chuyển chế độ mà không làm mất bài.

Nguồn: Grokking Modern System Design · ch.33 Design Instagram ↗ · mục "Hybrid approach" ; Redis in Action ↗ · ch.8 · §8.2 Home timeline

3) Phát 1 PB ảnh mỗi ngày tới người dùng nhanh và không phá sản thế nào?

Cách chưa tốt
Trả ảnh qua API hoặc link thẳng tới S3, một kích thước duy nhất

Mọi lượt xem đều chạy tới một region, điện thoại tải ảnh 1080 px dù màn hình chỉ cần 320 px. Phí egress S3 cao hơn CDN nhiều lần.

Đánh đổi: Không phải cấu hình gì, nhưng chậm với người ở xa và đắt.

⚠ Chưa có nguồn trong thư viện: trả ảnh trực tiếp từ origin là nhận định chung

Cách tốt
CDN trước S3, URL bất biến, nhiều kích thước

URL chứa media_id và kích thước, nội dung không bao giờ đổi nên đặt Cache-Control immutable, max-age 1 năm (Grokking ch.11 CDN). Client chọn 320/640/1080 theo màn hình. Tỷ lệ trúng cache trên 95%.

Đánh đổi: Ảnh của tài khoản riêng tư nằm trên URL công khai, ai có link là xem được.

Nguồn: Grokking Modern System Design · ch.11 Content Delivery Network (CDN) ↗ · mục "Content caching strategies in CDN"

Cách tốt nhất
CDN đa tầng + origin shield + định dạng theo thiết bị + URL ký cho nội dung riêng tư

Thêm origin shield để mỗi ảnh chỉ kéo từ S3 một lần cho cả mạng CDN, đẩy tỷ lệ trúng lên khoảng 98%. Edge trả AVIF/WebP theo header Accept. Ảnh tài khoản riêng tư dùng URL ký hết hạn sau vài giờ. Client hiện blurhash ngay, tải trước ảnh của 3-5 bài kế tiếp khi đang cuộn. Ở quy mô lớn dùng nhiều CDN và đặt cache tại ISP; ảnh gốc ít xem sau 90 ngày chuyển sang lớp lưu trữ rẻ.

Đánh đổi: Cấu hình và chi phí vận hành phức tạp; URL ký làm giảm tỷ lệ trúng cache cho ảnh riêng tư.

Nguồn: Grokking Modern System Design · ch.11 Content Delivery Network (CDN) ↗ · mục "Content caching strategies in CDN" ; Grokking Modern System Design · ch.11 ↗ · mục "Multi-tier CDN architecture"

4) Đếm like và bình luận ở quy mô lớn, kể cả bài nhận 1.667 like/s?

Cách chưa tốt
SELECT COUNT(*) mỗi lần hiển thị, hoặc UPDATE posts SET like_count = like_count + 1

COUNT trên bài 1 triệu like là quét 1 triệu hàng cho mỗi lượt xem feed. UPDATE cộng dồn thì mọi lượt like tranh khóa trên cùng một hàng, bài viral làm nghẽn cả DB.

Đánh đổi: Đúng tuyệt đối nhưng sập đúng lúc bài đang nóng.

⚠ Chưa có nguồn trong thư viện: COUNT và UPDATE cộng dồn là nhận định chung

Cách tốt
Redis INCR làm bộ đếm, định kỳ ghi xuống DB

Bảng like (khóa chính post_id, user_id) đảm bảo không like trùng; số đếm INCR trong Redis, đọc rất nhanh, một job ghi tổng xuống DB mỗi vài giây.

Đánh đổi: Một key của bài cực nóng vẫn dồn vào một shard Redis; Redis mất dữ liệu thì số đếm lệch tới khi dựng lại.

Nguồn: Redis in Action ↗ · ch.5 · §5.2 Counters and statistics

Cách tốt nhất
Like ghi vào ScyllaDB + Kafka + sharded counter cho bài nóng + đối soát

Bảng like nằm trên ScyllaDB/Cassandra, partition theo post_id, ghi idempotent. Sự kiện like qua Kafka tới bộ đếm. Bài bình thường dùng một key; bài vượt ngưỡng tốc độ thì chia thành 16 key con like:{post}:{0..15}, mỗi lượt cộng vào một key ngẫu nhiên, đọc thì cộng 16 key (Grokking ch.24 Sharded Counters). Số tổng được ghi định kỳ xuống DB và đối soát với bảng like. Hiển thị dạng rút gọn nên lệch vài giây không ai thấy. "Tôi đã like chưa" tra theo (post_id, user_id).

Đánh đổi: Số like là gần đúng trong vài giây và cần job đối soát; nhiều thành phần hơn cho một con số.

Nguồn: Grokking Modern System Design · ch.24 Sharded Counters ↗ · mục "Detailed design" (Burst of writes requests, Manage read requests) ; Chưa có nguồn trong thư viện: ScyllaDB không có trong sách

Trong phỏng vấn

Nên nói
  • “File ảnh không bao giờ đi qua API: client lấy presigned URL và tải thẳng lên S3, worker resize bất đồng bộ.”
  • “Tôi dùng fan-out hybrid: push cho tác giả thường, pull cho người nổi tiếng, và chỉ push tới người dùng còn hoạt động.”
  • “URL ảnh là bất biến nên CDN cache được 1 năm; băng thông ảnh mới là chi phí lớn nhất của hệ thống.”
  • “Bảng like là nguồn sự thật để chống trùng, còn số like hiển thị là bộ đếm bất đồng bộ, chia shard cho bài nóng.”
Bẫy hay gặp
  • Upload ảnh qua API server và resize trong request.
  • Push bài của người nổi tiếng tới hàng triệu timeline.
  • UPDATE like_count trên hàng của bài cho mỗi lượt like.
  • Quên tính băng thông CDN: ở quy mô lớn nó lớn hơn tiền server nhiều lần.

Đọc thêm

Xử lý file lớn
Cách upload, lưu và phân phối file lớn mà không để chúng đi qua app server: presigned URL, multipart và resumable upload, chia chunk và dedup theo hash, CDN, signed URL khi tải về, pipeline hậu xử lý bằng sự kiện, tách metadata khỏi blob store.
Scale đọc
Phục vụ lượng đọc gấp hàng trăm lần lượng ghi: index, read replica và replication lag, cache nhiều tầng, CDN, read model denormalized theo CQRS, cùng cách xử lý cache stampede và hot key.
Scale ghi
Khi lượng ghi vượt sức một database: gom batch, ghi bất đồng bộ qua hàng đợi, chọn storage tối ưu cho ghi, chia dữ liệu theo key, xử lý partition nóng bằng salting, sharded counter và tổng hợp trước. Kèm con số cho từng quy mô.
Redis
Redis là kho key-value trong RAM với nhiều cấu trúc dữ liệu: dùng làm cache, bộ đếm, leaderboard, hàng đợi, GEO và pub/sub. Bài này đi qua mô hình dữ liệu, persistence, replication, Cluster, Lua và cách tính RAM.
Cassandra
Cassandra là database wide-column phân tán, ghi rất nhanh nhờ LSM tree, mở rộng gần tuyến tính bằng ring và consistent hashing. Bài này giải thích partition key, clustering column, cách mô hình hoá theo câu truy vấn, tunable consistency và những cái bẫy như tombstone.
Caching
Đặt cache ở đâu (client, CDN, app, Redis), các chiến lược đọc ghi cache-aside, write-through, write-back, write-around, eviction LRU/LFU/TTL, invalidation, chống stampede và hot key, cách tính RAM Redis và toán hit ratio.

Sách trong thư viện của bạn. Số chương có thể lệch nhẹ so với bản PDF.