1. Vì sao có NoSQL?
Đầu thế kỷ 21, Google, Amazon, Facebook gặp vấn đề: dữ liệu lên hàng petabyte, request hàng triệu/giây — RDBMS truyền thống không scale ngang được vì:
- JOIN tốn nhiều round-trip cross-node.
- Distributed transaction (2PC) cực chậm và dễ kẹt.
- Schema rigid, hard to migrate trên cluster lớn.
2 paper huyền thoại đặt nền móng NoSQL:
- Google Bigtable (2006) — sparse distributed map, column-family. Tổ tiên Cassandra, HBase.
- Amazon Dynamo (2007) — eventual consistency, consistent hashing, vector clock. Tổ tiên DynamoDB, Cassandra, Riak.
NoSQL không phải "không SQL" — mà là "Not Only SQL". Hy sinh một số tính chất ACID/JOIN đổi lấy scale ngang và linh hoạt schema.
1.1. Bài học sau 15 năm hype
Hiện tại (2026), nhiều dự án quay lại Postgres làm "default", chỉ dùng NoSQL cho các use case cụ thể: cache (Redis), search (Elasticsearch), time-series (Prometheus), log (ClickHouse). Đừng theo trend, theo workload.
2. CAP Theorem & PACELC
Eric Brewer (2000): trong hệ phân tán, khi xảy ra Network Partition (P), bạn buộc phải hy sinh hoặc Consistency (C) hoặc Availability (A).
- C — mọi node trả về cùng dữ liệu mới nhất (linearizability).
- A — mọi request đều nhận response (không lỗi, không timeout).
- P — hệ vẫn hoạt động khi network giữa các node bị đứt.
2.1. CAP nhầm lẫn phổ biến
"Postgres là CA" — SAI. Postgres single-node không phải hệ phân tán, không có P xảy ra. CAP chỉ áp dụng khi P xảy ra.
2.2. PACELC — bổ sung của Daniel Abadi
PACELC = "If Partition, A or C; Else Latency or Consistency".
Ngay cả khi không partition, bạn vẫn phải đánh đổi giữa latency (trả nhanh từ replica gần) và consistency (chờ leader xác nhận).
| System | Khi P | Khi không P |
|---|---|---|
| Postgres (single) | — | EC (consistency over latency) |
| MongoDB (replica set) | PC | EC (đọc từ primary) |
| Cassandra | PA | EL (đọc replica gần) |
| DynamoDB | PA | EL (default) |
| Spanner | PC | EC |
3. BASE — đối lập của ACID
| ACID | BASE |
|---|---|
| Atomicity | Basically Available — luôn có response (có thể stale) |
| Consistency | Soft state — state có thể đổi do background sync |
| Isolation | Eventual consistency — sẽ nhất quán cuối cùng |
| Durability | — |
BASE phù hợp với:
- Mạng xã hội — like, comment count delay vài giây OK.
- IoT data, log, analytics — eventual aggregation.
- Catalog browsing — view sản phẩm có thể stale 1s.
KHÔNG phù hợp:
- Tài chính — chuyển tiền phải atomic.
- Booking — không thể bán 2 vé cho 1 ghế.
- Inventory hot — không thể "cuối cùng đồng bộ" khi chỉ còn 1 item.
4. Eventual Consistency — các mức
- Strong — sau write, mọi read tiếp theo (any node) thấy giá trị mới. Cao nhất, chậm nhất.
- Read-your-writes — user thấy chính ghi của mình ngay lập tức (qua sticky session hoặc primary read).
- Monotonic reads — không bao giờ "lùi thời gian" — đã thấy v2, không thấy lại v1.
- Causal — quan hệ nhân quả được preserve (B trả lời A → mọi ai thấy B cũng thấy A).
- Eventual — cuối cùng (sau finite delay) tất cả replica giống nhau.
4.1. Quorum read/write
Hệ Dynamo-style cho phép tune R + W trong N replica:
- R + W > N — strong consistency (read overlap với write).
- R = 1, W = N — fast read, slow write.
- R = N, W = 1 — fast write, slow read.
- R + W ≤ N — eventual consistency.
Ví dụ N=3, R=W=2 → strong (R+W=4 > N=3). Đa số production Cassandra dùng config này.
5. Key-Value Store — Redis là vua
Mô hình đơn giản nhất: SET key value / GET key. Hash table phân tán.
5.1. Đại diện
- Redis — in-memory, single-thread, latency <1ms.
- Memcached — in-memory đơn giản, multi-thread.
- DynamoDB — managed, auto-scale, serverless pay-per-request.
- Riak — Dynamo-style, tunable consistency.
5.2. Redis — không chỉ KV
Redis hỗ trợ nhiều data structure phức tạp:
# String
SET user:1:email "a@x.com"
GET user:1:email
INCR user:1:visits # atomic counter
# Hash (object)
HSET user:1 email "a@x.com" name "Alice" age 30
HGETALL user:1
HINCRBY user:1 age 1
# List (queue/stack)
LPUSH queue:jobs "job-data"
RPOP queue:jobs # FIFO
BLPOP queue:jobs 5 # block 5s
# Set
SADD friends:1 5 6 7
SINTER friends:1 friends:2 # bạn chung
# Sorted Set (leaderboard)
ZADD leaderboard 1500 user1 1200 user2 1800 user3
ZREVRANGE leaderboard 0 9 WITHSCORES # top 10
# Stream (log)
XADD events * type click user 5
XREAD STREAMS events $ # tail
# Pub/Sub
SUBSCRIBE channel:news
PUBLISH channel:news "hello"
# TTL
SET session:abc "userid:5" EX 3600 # tự xóa sau 1h
EXPIRE session:abc 7200
5.3. Use cases
- Session store (web).
- Cache (cache-aside, write-through).
- Rate limiter (sliding window qua Sorted Set).
- Leaderboard / ranking (Sorted Set).
- Job queue đơn giản (List + BLPOP).
- Real-time notifications (Pub/Sub, Streams).
- Geo (GEO commands).
5.4. Persistence
Redis có 2 chế độ:
- RDB snapshot — dump RAM ra disk định kỳ. Có thể mất N giây cuối nếu crash.
- AOF (Append-Only File) — ghi mỗi lệnh write vào log. An toàn hơn nhưng chậm hơn.
Production thường bật cả hai.
6. Document — MongoDB
Lưu document JSON/BSON. Mỗi document có thể có schema khác nhau (schemaless).
// MongoDB document
{
_id: ObjectId("..."),
email: "alice@x.com",
name: "Alice",
addresses: [
{ type: "home", city: "HCM", street: "..." },
{ type: "office", city: "HN", street: "..." }
],
preferences: {
theme: "dark",
notifications: { email: true, push: false }
},
tags: ["vip", "early-adopter"]
}
6.1. Cú pháp cơ bản
// Insert
db.users.insertOne({ email: "a@x", name: "Alice" });
db.users.insertMany([...]);
// Find
db.users.find({ email: "a@x" });
db.users.find({ age: { $gt: 18 } });
db.users.find({ "addresses.city": "HCM" }); // dot notation
// Update
db.users.updateOne(
{ _id: ... },
{ $set: { name: "Alice S" }, $inc: { visits: 1 } }
);
db.users.updateOne(
{ _id: ... },
{ $push: { tags: "premium" } }
);
// Aggregate (pipeline)
db.orders.aggregate([
{ $match: { status: "paid" } },
{ $group: { _id: "$user_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
]);
// Index
db.users.createIndex({ email: 1 });
db.users.createIndex({ "addresses.city": 1 });
db.users.createIndex({ name: "text" }); // full-text
6.2. Khi nào dùng MongoDB tốt?
- Dữ liệu có cấu trúc nested phức tạp, schema thay đổi nhanh.
- Document tự chứa (1 record = 1 doc, ít cần JOIN).
- Workload write-heavy, scale ngang.
- Catalog, content management, IoT.
6.3. MongoDB pitfalls
- JOIN qua
$lookupchậm hơn nhiều SQL JOIN. - Multi-document transaction từ 4.0 mới có, có overhead.
- Schema "linh hoạt" → app code phải tự validate. Dễ data lệch.
- 16MB document size limit.
Postgres + cột JSONB thường thay thế được MongoDB với phần lớn use case, mà có thêm SQL + ACID.
7. Wide-column — Cassandra & Bigtable
Mô hình: hàng tỉ row × hàng triệu cột (sparse). Mỗi row có thể có cột khác nhau. Tối ưu cho write throughput cực cao.
7.1. Cassandra cơ bản
-- CQL (Cassandra Query Language) — giống SQL nhưng hạn chế:
CREATE KEYSPACE shop WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
CREATE TABLE orders (
user_id UUID,
order_id TIMEUUID,
total decimal,
status text,
PRIMARY KEY (user_id, order_id) -- partition_key, clustering_key
) WITH CLUSTERING ORDER BY (order_id DESC);
INSERT INTO orders (user_id, order_id, total, status)
VALUES (..., now(), 100.00, 'paid');
SELECT * FROM orders WHERE user_id = ? LIMIT 20;
-- ❌ Không có WHERE on non-PK cột (không có index thông thường)
-- ❌ Không có JOIN
-- ❌ Không có IN trên partition key
7.2. Đặc điểm
- Partition key quyết định node nào lưu row → mọi query nóng phải có partition key.
- Clustering key sắp xếp trong partition.
- Schema "thiết kế quanh query" — không phải quanh entity (như SQL).
- Hỗ trợ scale từ 3 đến 1000+ node, replica đa data-center.
- Tunable consistency: ONE / QUORUM / ALL.
7.3. Use cases
- Time-series: log, metrics, sensor data.
- Activity feed (Twitter user timeline lưu trong Cassandra).
- Messaging (Discord chat history dùng Cassandra/ScyllaDB).
- Multi-region với latency thấp.
7.4. Bigtable / HBase
Tương tự Cassandra nhưng strong consistency (CP). Dùng nội bộ Google (Search index, Maps), GCP exposed như Bigtable.
7.5. ScyllaDB
Cassandra-compatible, viết bằng C++ (thay Java) → 10× throughput. Đang được nhiều team migrate sang.
8. Graph DB — Neo4j
Lưu nodes + edges (quan hệ). Tối ưu cho truy vấn quan hệ nhiều hop.
8.1. Cypher query language
// Tạo
CREATE (alice:User {name:'Alice', age:30})
CREATE (bob:User {name:'Bob', age:28})
CREATE (alice)-[:FOLLOWS]->(bob)
// Truy vấn: bạn của bạn (2 hop)
MATCH (me:User {name:'Alice'})-[:FOLLOWS]->(friend)-[:FOLLOWS]->(fof)
WHERE NOT (me)-[:FOLLOWS]->(fof) AND me <> fof
RETURN fof.name, COUNT(friend) AS mutuals
ORDER BY mutuals DESC LIMIT 10
// Đường ngắn nhất:
MATCH p = shortestPath((a:User {name:'Alice'})-[:FOLLOWS*]-(b:User {name:'Zoe'}))
RETURN p
8.2. Use cases
- Social network — bạn của bạn, recommendation.
- Fraud detection — phát hiện chuỗi giao dịch bất thường.
- Knowledge graph — Wikipedia, Wolfram Alpha.
- Network/dependency analysis.
8.3. Vì sao SQL không đủ?
Truy vấn 5-hop trong SQL = 5 self-JOIN. Trên 1 tỉ row, cực chậm. Graph DB lưu edges adjacent → traversal O(neighbors), không O(table-size).
8.4. Đại diện khác
- Amazon Neptune — managed graph (Gremlin, SPARQL).
- Dgraph — distributed, GraphQL native.
- JanusGraph — open-source, dùng HBase/Cassandra làm storage.
- Postgres + extension
ltree/ Apache AGE — Cypher trong Postgres.
9. NewSQL — vừa SQL vừa Distributed
"Có cách nào của cả 2 thế giới không?" — đáp: NewSQL.
- Google Spanner — globally distributed SQL với strong consistency. Dùng TrueTime (atomic clocks + GPS) đảm bảo external consistency.
- CockroachDB — Spanner-inspired open-source. Postgres-compatible.
- YugabyteDB — Postgres-compatible distributed. Có cả KV layer (DocDB).
- TiDB — MySQL-compatible distributed.
Đánh đổi: latency cao hơn single-node Postgres do phải consensus (Raft/Paxos). Dùng khi cần multi-region SQL với strong consistency.
10. Khi nào chọn cái nào?
| Tình huống | Chọn |
|---|---|
| App CRUD bình thường, cần JOIN, ACID | Postgres / MySQL |
| Cache, session, rate limit, leaderboard | Redis |
| Schema nested phức tạp, schema-flex | MongoDB hoặc Postgres + JSONB |
| Time-series, log, IoT, write-heavy > 100k/s | Cassandra / ScyllaDB / TimescaleDB |
| Full-text search | Elasticsearch / Postgres tsvector + GIN |
| Quan hệ nhiều hop (friends-of-friends, fraud) | Neo4j / Postgres + AGE |
| Multi-region SQL với strong consistency | Spanner / CockroachDB |
| Analytics OLAP (TB-PB scan) | BigQuery / Snowflake / ClickHouse |
| AI embeddings vector search | Pinecone / pgvector / Weaviate |
| Object storage, file lớn | S3 / GCS / Azure Blob — KHÔNG DB |
11. Bài tập
- Cài Redis local. Implement rate limiter "10 request/phút mỗi user" qua Sorted Set + ZADD/ZREMRANGEBYSCORE.
- Cài MongoDB. Tạo collection products với nested categories, viết aggregate query top-10 sản phẩm bán chạy mỗi category.
- Phân tích: Twitter timeline nên dùng DB nào? (Postgres cho user/profile, Redis cache, Cassandra cho timeline storage). Vì sao?
- Trình bày CAP cho 3 hệ: Postgres single, MongoDB replica, Cassandra. Khi network partition, mỗi hệ ưu tiên gì?
- Khi nào BẠN sẽ dùng Graph DB thay vì Postgres recursive CTE?
- So sánh Postgres JSONB vs MongoDB document. Khi nào nên chọn cái nào?
12. Quiz
Quiz cuối Chương 9
CAP theorem nói:
Cassandra là hệ:
Redis Sorted Set phù hợp nhất với:
MongoDB đặc biệt phù hợp khi:
Graph DB so với SQL recursive CTE:
N=3 replica, R=2, W=2 → consistency:
"Default: Postgres" trong 2026 nghĩa là:
CockroachDB / Spanner thuộc loại:
Hoàn thành Chương 9. Tiếp theo: Chương 10 — Replication & Sharding →