Cách Sharding trong Cơ sở dữ liệu Hoạt động
Sharding là gì?
Sharding (Phân mảnh), còn gọi là Phân vùng theo chiều ngang (Horizontal Partitioning), chia một tập dữ liệu lớn (Dataset) thành các phần nhỏ hơn gọi là Shard (Mảnh), mỗi phần được lưu trữ trên một máy chủ cơ sở dữ liệu riêng biệt. Thay vì một máy khổng lồ chứa mọi thứ, dữ liệu được phân phối (Distributed) trên một cụm (Cluster) nhiều máy.
Sharding khác với Replication (Sao chép) — Replication sao chép cùng một dữ liệu đến nhiều Nodes để đảm bảo tính sẵn sàng (Availability), trong khi Sharding phân phối khác dữ liệu đến các Nodes khác nhau để mở rộng khả năng (Scalability).
Tại sao cần Sharding?
| Vấn đề | Sharding giúp gì |
|---|---|
| Dữ liệu quá lớn cho một máy | Mỗi Shard giữ một phần (Subset) — tổng dung lượng = tổng tất cả các Shard |
| Nút thắt thông lượng ghi (Write Throughput Bottleneck) | Ghi được phân tán (Spread) across các Shard — không có Node đơn lẻ phải xử lý tất cả |
| Độ trễ truy vấn cao (High Query Latency) | Mỗi Shard lập chỉ mục (Index) tập dữ liệu nhỏ hơn — truy vấn chạy nhanh hơn |
| Chi phí | Sử dụng nhiều máy phổ thông (Commodity Machines) thay vì một máy chủ đắt tiền |
Thuật ngữ quan trọng (Key Terminology)
- Shard Key (Khóa phân mảnh) — cột (hoặc tập hợp các cột) dùng để quyết định Shard nào chứa một dòng (Row) (ví dụ:
user_id,region) - Shard Router (Bộ định tuyến) — thành phần chặn truy vấn và chuyển tiếp đến Shard đúng
- Hash Function (Hàm băm) — hàm ánh xạ Shard Key đến số Shard (ví dụ:
hash(key) % num_shards) - Hotspot (Điểm nóng) — một Shard nhận lượng truy cập nhiều hơn đáng kể so với các Shard khác
- Resharding (Tái phân mảnh) — quá trình phân phối lại dữ liệu khi thêm hoặc xóa Shard
Cách Sharding hoạt động (đơn giản hóa)
1. Client sends a query (read or write) with a shard key
2. Router evaluates the shard key → determines target shard
3. Router forwards the query to the target shard only
4. Target shard processes the query
5. Router collects the result and returns it to the client
Quyết định thiết kế quan trọng là: làm sao Router quyết định Shard nào được sử dụng? Điều này quyết định chiến lược Sharding (Sharding Strategy).
Trực quan hóa
Xem cách các thao tác ghi được định tuyến đến các Shard khác nhau dưới ba chiến lược phổ biến. Chuyển đổi giữa các chế độ để so sánh phân phối (Distribution), mẫu truy vấn (Query Patterns) và đánh đổi (Trade-offs):
Applies a hash function to the shard key and uses modulo to assign data to shards. Provides even distribution but makes range queries across shards expensive.
So sánh các chiến lược Sharding
| Khía cạnh | Dựa trên Hash (Hash-Based) | Dựa trên Range (Range-Based) | Dựa trên Directory (Directory-Based) |
|---|---|---|---|
| Định tuyến (Routing) | hash(key) % N → số Shard | Khoảng giá trị Key → Shard | Bảng tra cứu ánh xạ Key → Shard |
| Phân phối (Distribution) | Đồng đều (nếu Hash đồng nhất) | Không đồng đều nếu phân bố Key bị lệch | Có thể cấu hình — ánh xạ tùy ý |
| Truy vấn Range | Tốn kém — phải truy vấn tất cả Shard | Hiệu quả — truy vấn đến một Shard | Phụ thuộc vào ánh xạ |
| Thêm Shard | Cần Resharding hầu hết dữ liệu | Thêm Range mới, di chuyển dữ liệu biên | Chỉ cập nhật bảng tra cứu |
| Độ phức tạp | Thấp — chỉ Hash + Modulo | Thấp — kiểm tra Range | Trung bình — duy trì bảng tra cứu |
| Nguy cơ Hotspot | Thấp | Cao (ví dụ: Timestamp gần đây) | Phụ thuộc vào thiết kế ánh xạ |
| Trường hợp sử dụng | User ID, Session Token | Chuỗi thời gian (Time-series), dữ liệu đã sắp xếp | Phân tán theo địa lý (Geo-distributed), Multi-tenant |
Chọn Shard Key
Shard Key quyết định mọi thứ về hiệu năng Sharding của bạn. Shard Key tồi dẫn đến Hotspot, truy vấn Cross-shard và Resharding đau đớn.
Tính chất của Shard Key tốt
- Độ phân biệt cao (High Cardinality) — nhiều giá trị khác nhau để dữ liệu phân bổ đồng đều
- Tần suất thấp (Low Frequency) — không có giá trị đơn lẻ nào chiếm ưu thế (tránh Hotspot)
- Liên quan đến truy vấn (Query-relevant) — hầu hết truy vấn bao gồm Shard Key nên chỉ truy cập một Shard
- Bất biến (Immutable) — thay đổi Shard Key nghĩa là phải di chuyển dòng sang Shard khác
Lựa chọn Shard Key phổ biến
| Shard Key | Chiến lược | Ghi chú |
|---|---|---|
user_id | Hash | Phân phối người dùng đồng đều; truy vấn cho một người dùng chỉ truy cập một Shard |
created_at | Range | Phù hợp cho chuỗi thời gian; dữ liệu gần đây tạo Hotspot ở Shard "hiện tại" |
region | Directory | Sharding theo địa lý; dữ liệu mỗi vùng nằm trong Data Center gần đó |
tenant_id | Hash hoặc Directory | SaaS Multi-tenant; cách ly Tenant ở cấp Shard |
Thách thức của Sharding
Truy vấn Cross-shard (Cross-shard Queries)
Các truy vấn không bao gồm Shard Key phải được gửi đến tất cả Shard và kết quả được gộp lại. Điều này gọi là truy vấn Scatter-gather và chậm hơn nhiều so với truy vấn có định hướng.
JOIN across Shard (Cross-shard JOINs)
JOIN giữa các bảng trên Shard khác nhau rất tốn kém hoặc không được hỗ trợ. Các giải pháp thay thế phổ biến:
- Nhân đôi bảng nhỏ (Duplicate Small Tables) đến mọi Shard (dữ liệu tham chiếu - Reference Data)
- JOIN ở mức ứng dụng (Application-level JOINs) — truy vấn từng Shard riêng biệt, gộp kết quả trong Code
- Co-shard các bảng liên quan — sử dụng cùng Shard Key cho các bảng có liên quan
Resharding (Tái phân mảnh)
Khi bạn thêm hoặc xóa Shard, dữ liệu phải được phân phối lại. Các phương pháp:
- Consistent Hashing (Băm nhất quán) — giảm thiểu di chuyển dữ liệu khi thêm/xóa Shard
- Double-write (Ghi kép) — ghi vào cả bố cục Shard cũ và mới trong quá trình Migration
- Online Migration (Di chuyển trực tuyến) — các công cụ như Vitess hoặc Balancer của MongoDB di chuyển dữ liệu từng phần
Sharding trong Thực tế
- MongoDB: Sharding native với Mongos Router. Hỗ trợ Shard Key Hash và Range. Auto-balancer di chuyển các Chunk giữa các Shard.
- PostgreSQL: Không có Sharding native. Sử dụng Citus Extension, Pgpool-II hoặc Sharding ở mức ứng dụng. Table Partitioning tích hợp sẵn (không phải Sharding thực sự — cùng một máy chủ).
- MySQL: Sử dụng Vitess (được YouTube sử dụng) hoặc Sharding ở mức ứng dụng. MySQL Cluster (NDB) có Automatic Sharding.
- Redis Cluster: Sharding dựa trên Hash với 16384 Hash Slot. Mỗi Node sở hữu một khoảng Slot. Hỗ trợ Resharding không gây gián đoạn (Zero Downtime).
Khi nào nên Sharding
Sharding thêm độ phức tạp đáng kể. Chỉ nên xem xét Sharding khi:
- Bạn đã chạm đến giới hạn mở rộng theo chiều dọc (Vertical Scaling Limits) — không thể thêm CPU/RAM cho một máy duy nhất
- Read Replica chưa đủ — ghi mới là điểm nghẽn (Bottleneck), không phải đọc
- Tập dữ liệu vượt quá dung lượng lưu trữ của một máy — dữ liệu không vừa trên một ổ đĩa
- Bạn cần định vị dữ liệu đa vùng (Multi-region Data Locality) — người dùng ở các vùng khác nhau cần dữ liệu cục bộ
Nếu bạn chưa chạm đến các giới hạn này, hãy bắt đầu với Replication và mở rộng theo chiều dọc trước. Sharding quá sớm (Premature Sharding) là nguyên nhân phổ biến gây ra độ phức tạp không cần thiết.
Tìm hiểu thêm
Đọc lý thuyết đầy đủ tại Cơ sở dữ liệu > Thiết kế Cơ sở dữ liệu.