Database Scaling: Relational vs NoSQL
Vertical/Horizontal Scaling, Replication vs Sharding, NoSQL Data Modeling (Embed vs Reference), Consistency Deep-Dive, SQL vs MongoDB vs DynamoDB
1. Scaling là gì?
Scaling là quá trình tăng khả năng xử lý của hệ thống khi lượng dữ liệu hoặc traffic tăng lên.
Hãy tưởng tượng bạn có 1 quán phở đang đông khách:
- Vertical Scaling = Mở rộng quán hiện tại: thêm bàn, mở rộng bếp, thuê đầu bếp giỏi hơn → nhưng quán chỉ có thể mở rộng đến một giới hạn nhất định (diện tích có hạn).
- Horizontal Scaling = Mở thêm chi nhánh mới: mở thêm quán phở ở các vị trí khác → gần như không giới hạn số chi nhánh.
2. Vertical Scaling (Scale Up)
Cách hoạt động
Tăng tài nguyên (CPU, RAM, Storage) cho một server duy nhất.
Ưu điểm
- Đơn giản: Không cần thay đổi code, chỉ cần nâng cấp phần cứng.
- Consistency dễ đảm bảo: Tất cả dữ liệu trên 1 server → không lo đồng bộ.
- Không cần thay đổi kiến trúc: Ứng dụng chạy y như cũ.
Nhược điểm
- Có giới hạn vật lý: Server lớn nhất cũng chỉ có một mức tài nguyên tối đa (ví dụ AWS RDS lớn nhất:
db.r6g.16xlarge= 64 vCPU, 512 GB RAM). - Single Point of Failure: Nếu server này chết → toàn bộ hệ thống sập.
- Chi phí tăng theo cấp số nhân: Server càng lớn → giá tăng rất nhanh, không tuyến tính.
Ví dụ cụ thể
3. Horizontal Scaling (Scale Out)
Cách hoạt động
Thêm nhiều server nhỏ hơn, mỗi server chịu trách nhiệm một phần dữ liệu.
Ưu điểm
- Gần như không giới hạn: Cứ thêm server khi cần.
- Fault tolerant: 1 server chết → các server khác vẫn hoạt động.
- Chi phí tuyến tính: Thêm 1 server ≈ thêm cùng 1 khoản chi phí.
Nhược điểm
- Phức tạp hơn: Cần quản lý nhiều server, đồng bộ dữ liệu.
- Consistency khó đảm bảo hơn: Dữ liệu phân tán → có thể đọc dữ liệu cũ (eventual consistency).
- Code phải thiết kế phù hợp: Không phải ứng dụng nào cũng scale out được dễ dàng.
Ví dụ cụ thể
4. Replication vs Sharding — Hai cách Scale Horizontally
Đây là 2 khái niệm rất hay bị nhầm lẫn. Cả hai đều thêm server, nhưng mục đích hoàn toàn khác nhau.
4.1. Replication — "Photocopy" dữ liệu
Replication = sao chép toàn bộ dữ liệu giống hệt nhau sang các server khác.
Tác dụng của Replication:
| Tác dụng | Giải thích | Ví dụ |
|---|---|---|
| High Availability | Server chính chết → replica lên thay ngay | RDS Multi-AZ: Primary chết → Standby tự lên thay, downtime ~30s |
| Scale READ | Chia tải đọc cho nhiều replicas | 10,000 người xem sản phẩm → chia cho 3 replicas |
| Disaster Recovery | Dữ liệu có bản sao → không sợ mất | Datacenter cháy → replica ở datacenter khác vẫn còn |
| Giảm latency | Đặt replica gần user | User ở VN đọc replica Singapore (10ms) thay vì US (200ms) |
Hạn chế: Replication CHỈ scale READ, WRITE vẫn chỉ đi vào 1 Primary duy nhất.
4.2. Sharding — "Chia bánh" dữ liệu
Sharding = chia dữ liệu ra nhiều server, mỗi server giữ một phần dữ liệu khác nhau.
Tác dụng của Sharding:
| Tác dụng | Giải thích | Ví dụ |
|---|---|---|
| Scale WRITE | Chia tải ghi cho nhiều servers | 100K đơn hàng/phút → 10 shards × 10K writes mỗi shard |
| Scale Storage | Mỗi server chỉ giữ 1 phần data | 10TB → 10 shards × 1TB, không cần 1 server khổng lồ |
| Scale READ + WRITE | Mỗi shard xử lý cả 2 | Query user A → chỉ hỏi shard chứa user A → nhanh |
4.3. So sánh Replication vs Sharding
| Replication | Sharding | |
|---|---|---|
| Ví dụ đời thường | 3 thư viện, mỗi nơi có cùng tất cả sách | 3 thư viện, mỗi nơi giữ thể loại khác nhau |
| Dữ liệu | Giống nhau trên mỗi server | Khác nhau trên mỗi server |
| Scale READ | ✅ Chia read cho nhiều replicas | ✅ Mỗi shard đọc phần của mình |
| Scale WRITE | ❌ Vẫn 1 Primary | ✅ Mỗi shard write phần của mình |
| Dung lượng | Mỗi server chứa TOÀN BỘ data | Mỗi server chứa 1 PHẦN data |
| Giải quyết | Server chết / đọc chậm | Data quá lớn / ghi chậm |
| 1 từ khóa | Availability + Read | Capacity + Write |
4.4. Thực tế: Dùng CẢ HAI cùng lúc
4.5. Vậy cái nào mới là "Horizontal Scaling thực sự"?
Khi nói "horizontal scaling", người ta chủ yếu nói về SHARDING — chia dữ liệu ra nhiều server để mỗi server xử lý write cho phần của mình. Replication chỉ là "horizontal scaling nửa vời" vì chỉ scale được read.
Trong AWS: DynamoDB tự làm cả hai (tự shard + tự replicate 3 copies across 3 AZs). RDS chỉ hỗ trợ replication (Multi-AZ, Read Replicas), còn sharding thì phải tự làm ở tầng application.
5. Tại sao Relational DB khó Scale Horizontally?
Đây là phần quan trọng nhất. Có 3 lý do chính:
4.1. Vấn đề JOIN giữa các bảng
Relational DB lưu dữ liệu theo bảng có quan hệ. Khi query, bạn thường phải JOIN nhiều bảng lại.
Ví dụ: Hệ thống quản lý đơn hàng
Query lấy thông tin đơn hàng:
Vấn đề khi scale horizontally (chia ra 3 servers):
Kết luận: JOIN giữa các bảng nằm trên các server khác nhau → phải truyền dữ liệu qua network → chậm và phức tạp.
4.2. Vấn đề ACID và Transactions
Relational DB đảm bảo ACID:
| Tính chất | Ý nghĩa | Ví dụ |
|---|---|---|
| Atomicity | Một transaction hoặc thành công toàn bộ, hoặc thất bại toàn bộ | Chuyển tiền: trừ A và cộng B phải cùng thành công |
| Consistency | Dữ liệu luôn hợp lệ sau mỗi transaction | Tổng tiền trong hệ thống không đổi sau chuyển tiền |
| Isolation | Các transaction chạy đồng thời không ảnh hưởng nhau | 2 người cùng mua hàng không bị conflict |
| Durability | Dữ liệu đã commit thì không bao giờ mất | Mất điện → dữ liệu vẫn còn |
Ví dụ: Chuyển tiền ngân hàng
Vấn đề khi dữ liệu nằm trên nhiều servers:
Kết luận: Đảm bảo ACID khi dữ liệu phân tán trên nhiều server rất khó → cần 2-Phase Commit (2PC) → chậm và phức tạp.
4.3. Vấn đề Foreign Keys và Data Integrity
6. Tại sao NoSQL dễ Scale Horizontally?
NoSQL giải quyết các vấn đề trên bằng cách thay đổi cách lưu trữ dữ liệu.
5.1. Không có JOIN → Mỗi record chứa đầy đủ thông tin
Cùng ví dụ đơn hàng, nhưng trong DynamoDB (NoSQL):
Trade-off: Dữ liệu bị lặp lại (user info lặp ở mỗi order). Nhưng disk rẻ → chấp nhận được đổi lấy tốc độ.
5.2. Eventual Consistency thay vì Strong Consistency
NoSQL chấp nhận BASE model:
5.3. Partition Key → Tự động chia dữ liệu
NoSQL dùng Partition Key để quyết định dữ liệu nằm trên server nào:
7. Ví dụ thực tế: Hệ thống E-Commerce
Scenario: Shopee/Tiki với 10 triệu users
Cách tiếp cận với Relational DB (MySQL/PostgreSQL)
Cách tiếp cận với NoSQL (DynamoDB)
8. Ví dụ thực tế: Hệ thống Chat/Messaging
Scenario: Ứng dụng chat như Zalo/Messenger
Relational DB approach
NoSQL (DynamoDB) approach
9. So sánh tổng hợp
ACID vs BASE
Bảng so sánh chi tiết
| Tiêu chí | Relational DB (SQL) | NoSQL |
|---|---|---|
| Data Model | Bảng + quan hệ (normalized) | Document, Key-Value, Graph (denormalized) |
| Schema | Cố định, phải định nghĩa trước | Linh hoạt, mỗi record có thể khác nhau |
| Scaling chính | Vertical (scale up) | Horizontal (scale out) |
| JOIN | Hỗ trợ, rất mạnh | Không hỗ trợ hoặc hạn chế |
| Transactions | ACID - strong consistency | BASE - eventual consistency |
| Query | SQL - rất linh hoạt | API-based - hạn chế hơn |
| Phù hợp cho | Dữ liệu có quan hệ phức tạp, cần chính xác | Dữ liệu lớn, cần speed, cần scale |
| Ví dụ AWS | RDS, Aurora | DynamoDB, ElastiCache, DocumentDB |
| Ví dụ ngoài | MySQL, PostgreSQL, Oracle | MongoDB, Cassandra, Redis |
| Max scale | Giới hạn bởi phần cứng lớn nhất | Gần như không giới hạn |
10. Trong AWS
RDS (Relational)
Aurora (Relational - tốt hơn RDS)
DynamoDB (NoSQL)
11. Kết luận
Câu nói gốc: "Relational databases cannot scale horizontally as easily as NoSQL databases"
→ ĐÚNG ✅
Tóm tắt lý do:
- JOIN operations → dữ liệu phân tán trên nhiều server → JOIN qua network rất chậm.
- ACID transactions → đảm bảo consistency khi dữ liệu phân tán cần 2-Phase Commit → phức tạp, chậm.
- Foreign Keys → kiểm tra ràng buộc giữa các server → overhead lớn.
- Schema cứng → thay đổi schema trên nhiều server phức tạp.
NoSQL giải quyết bằng cách:
- Denormalization → không cần JOIN.
- Eventual Consistency → chấp nhận dữ liệu tạm thời chưa đồng bộ.
- Partition Key → tự động chia dữ liệu, mỗi query chỉ cần 1 partition.
Khi nào dùng cái nào?
| Use Case | Nên dùng | Lý do |
|---|---|---|
| Ngân hàng, tài chính | Relational (RDS/Aurora) | Cần ACID, chính xác tuyệt đối |
| E-commerce catalog | NoSQL (DynamoDB) | Dữ liệu lớn, cần speed |
| User authentication | Relational | Schema rõ ràng, cần consistency |
| IoT sensor data | NoSQL | Dữ liệu khổng lồ, chỉ append |
| Chat/Messaging | NoSQL | Throughput cao, dữ liệu đơn giản |
| Accounting/ERP | Relational | Quan hệ phức tạp, transactions |
| Gaming leaderboard | NoSQL (ElastiCache) | Speed cực nhanh |
| Social media feed | NoSQL | Scale lớn, eventual consistency OK |
Lưu ý: Trong thực tế, nhiều hệ thống dùng CẢ HAI (Polyglot Persistence). Ví dụ: Shopee dùng MySQL cho orders/payments (cần ACID) + Redis/DynamoDB cho product catalog, sessions, caching (cần speed).
12. NoSQL Data Modeling — Embed vs Reference
12.1. SQL lưu 3 bảng, NoSQL lưu thế nào?
Trong SQL:
Trong NoSQL: 3 tables riêng + NHÚNG (copy) khi cần:
Quan trọng: Nhúng = COPY, không phải MOVE. Bản gốc Users và Products vẫn tồn tại, vẫn query độc lập được.
12.2. Embed vs Reference — Khi nào dùng cái nào?
Embed (nhúng): Lưu data trực tiếp vào document.
Reference: Chỉ lưu ID, query riêng khi cần.
Quy tắc chọn:
| Tiêu chí | Dùng Embed | Dùng Reference |
|---|---|---|
| Data thay đổi thường xuyên? | ❌ Ít thay đổi → embed | ✅ Thay đổi nhiều → reference |
| Cần truy cập độc lập? | ❌ Không → embed | ✅ Có → reference + collection riêng |
| Kích thước data? | Nhỏ → embed | Lớn → reference (tránh document quá to) |
| Quan hệ 1-nhiều ít? | ✅ → embed | Nhiều (hàng nghìn) → reference |
12.3. Update product khi đã nhúng — Có cần update orders cũ?
Nguyên tắc: Chỉ nhúng dữ liệu mà bạn KHÔNG CẦN đồng bộ sau này (snapshot/lịch sử). Dữ liệu "sống" (thay đổi liên tục) → lưu reference (ID) và query riêng khi cần.
12.4. Cần collection riêng không khi đã nhúng?
| Data | Cần collection riêng? | Lý do |
|---|---|---|
| Products | ✅ Cần | Cần xem, sửa, tìm kiếm độc lập |
| Users | ✅ Cần | Cần login, xem profile độc lập |
| Shipping address | ❌ Không | Chỉ tồn tại trong order |
| Order items | ❌ Không | Chỉ tồn tại trong order |
| Tags (string list) | ❌ Không | Nhúng mảng string đơn giản đủ dùng |
12.5. Lấy tất cả tags trong NoSQL?
Trong SQL: SELECT DISTINCT name FROM tags; → 1 dòng, xong.
Trong NoSQL — phổ biến nhất: tạo metadata document:
NoSQL chuyển sự phức tạp từ DATABASE sang APPLICATION.
13. Consistency Deep-Dive — Hai loại consistency khác nhau
13.1. Hai vấn đề khác nhau
13.2. Write Conflict — Giải quyết bằng Version Locking
Hoặc đơn giản hơn — Atomic Operations (cho counter):
| Trường hợp | Dùng gì | Ví dụ |
|---|---|---|
| Trừ/cộng số | Atomic Ops | stock, likes, views |
| Update nhiều fields | Version Locking | name + price + description |
| Multi-document transaction | Dùng SQL | Trừ A + cộng B cùng lúc |
13.3. Eventual Consistency — Đọc data cũ từ replica
13.4. Sync vs Async Replication
Trong AWS:
| Service | Replication | Ghi chú |
|---|---|---|
| RDS Multi-AZ (Standby) | Sync | Luôn consistent, nhưng Standby không đọc được |
| RDS Read Replicas | Async | CÓ THỂ đọc data cũ — SQL CŨNG BỊ eventual consistency! |
| Aurora | Storage sync, Replicas async | Replica lag ~10-20ms |
| DynamoDB | Ghi 2/3 replicas trước khi confirm | Default eventual, opt-in strong |
13.5. Tại sao nói NoSQL "eventual consistency" nhiều hơn?
NoSQL CHỌN eventual consistency làm mặc định, hy sinh chính xác tức thì để đổi lấy tốc độ + scalability. Khi cần chính xác → vẫn có option Strong Read (đắt hơn).
14. CRUD Thực tế trong NoSQL
Ví dụ CRUD cho hệ thống Orders (DynamoDB):
14.1. CREATE
14.2. READ
14.3. UPDATE
14.4. DELETE
15. SQL vs MongoDB vs DynamoDB
MongoDB nằm ở giữa SQL và DynamoDB:
15.1. MongoDB — "Best of both worlds" nhưng cũng "Master of none"
So với SQL, MongoDB YẾU hơn ở:
| Tiêu chí | SQL | MongoDB |
|---|---|---|
| Transaction performance | Tối ưu sẵn, nhanh | Có nhưng chậm hơn 20-50% |
| JOIN phức tạp | SQL optimizer tự động | $lookup chậm, không hoạt động cross-shard |
| Reporting / Analytics | GROUP BY, SUM, AVG cực mạnh | Aggregation phức tạp hơn, chậm hơn |
| Data integrity | FK, constraints ở DB level | App phải tự kiểm tra |
So với DynamoDB, MongoDB YẾU hơn ở:
| Tiêu chí | DynamoDB | MongoDB |
|---|---|---|
| Auto-scaling | Hoàn toàn tự động, 0 ops | Phải cấu hình sharding thủ công |
| Latency | LUÔN single-digit ms | Thay đổi tùy query phức tạp |
| Chi phí vận hành | 0 DevOps | Cần 1-2 DevOps quản lý |
| Managed service | Serverless, AWS native | DocumentDB (không phải MongoDB thật) |
15.2. Bảng so sánh tổng hợp
| Tiêu chí | SQL thắng | MongoDB thắng | DynamoDB thắng |
|---|---|---|---|
| Transactions phức tạp | ✅ | ||
| JOIN / Reporting | ✅ | ||
| Data integrity (FK) | ✅ | ||
| Linh hoạt query + scale | ✅ | ||
| Schema linh hoạt | ✅ | ||
| Auto-scale vô hạn | ✅ | ||
| Zero operations | ✅ | ||
| Latency ổn định | ✅ |
15.3. Khi nào dùng cái nào?
Kết luận: Đừng nghĩ "SQL hay NoSQL?". Hãy nghĩ "Thành phần nào dùng cái gì?". Mỗi database có thế mạnh riêng — dùng đúng chỗ thì phát huy tối đa, dùng sai chỗ thì đau khổ. E-commerce thực tế thường dùng cả SQL + NoSQL (Polyglot Persistence).