Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 16 — NoSQL — DynamoDB, Firestore, Cosmos DB

Đã đọc 0/15 mục · còn khoảng 12 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn đang xây một ứng dụng gọi xe kiểu Grab hay Be. Mỗi giây có hàng chục nghìn tài xế gửi toạ độ GPS về server, hàng nghìn khách hàng mở app cùng lúc, và mỗi cuốc xe sinh ra một loạt sự kiện: đặt xe, ghép tài xế, đón khách, hoàn thành, thanh toán. Nếu bạn nhét toàn bộ dữ liệu này vào một database quan hệ (relational) truyền thống với các JOIN phức tạp và schema cứng nhắc, đến một ngưỡng nào đó hệ thống sẽ nghẹt thở. Đây chính là lúc NoSQL bước lên sân khấu.

Ở Bài 15 bạn đã học về Relational Database quản lý (RDS, Cloud SQL) — nơi dữ liệu có cấu trúc bảng chặt chẽ và tính nhất quán mạnh. Bài 16 này là "mặt còn lại của đồng xu": các cơ sở dữ liệu NoSQL được cloud cung cấp dưới dạng dịch vụ quản lý (managed service). Cụ thể, chúng ta sẽ đi sâu vào ba "ông lớn" tương ứng với ba nhà cung cấp: DynamoDB (AWS), Firestore (Google Cloud) và Cosmos DB (Azure).

Vì sao một kỹ sư DevOps hay backend cần nắm chắc nhóm này? Bởi vì lựa chọn database sai ngay từ đầu là một trong những "món nợ kỹ thuật" (technical debt) đắt đỏ nhất. Đổi database khi hệ thống đã chạy production với hàng triệu người dùng còn khó hơn thay động cơ máy bay đang bay. Hiểu đúng NoSQL cloud giúp bạn chọn đúng công cụ cho đúng bài toán, thiết kế mô hình dữ liệu (data model) hợp lý, và tránh những hoá đơn cloud "trên trời" do query kém tối ưu.

Khái niệm cốt lõi

NoSQL là gì và tại sao nó ra đời

NoSQL không có nghĩa là "no SQL" (không dùng SQL) mà thường được hiểu là "Not Only SQL". Đây là nhóm cơ sở dữ liệu không tuân theo mô hình bảng quan hệ cứng nhắc. Chúng ra đời để giải quyết ba bài toán mà relational database gặp khó khi quy mô cực lớn:

  • Scale ngang (horizontal scaling): thay vì mua một server ngày càng mạnh (scale dọc), NoSQL cho phép chia dữ liệu ra hàng trăm máy nhỏ.
  • Schema linh hoạt (flexible schema): mỗi bản ghi có thể có cấu trúc khác nhau, thêm trường mới không cần chạy migration đau đớn.
  • Hiệu năng cao ở quy mô lớn: đọc/ghi ở độ trễ mili-giây với hàng triệu request mỗi giây.
Cái giá phải trả thường là bạn phải hy sinh một phần tính nhất quán mạnh (strong consistency) hoặc khả năng query linh hoạt kiểu JOIN. Đây là bản chất của định lý CAP: giữa Consistency (nhất quán), Availability (sẵn sàng) và Partition tolerance (chịu phân mảnh mạng), một hệ phân tán chỉ đảm bảo trọn vẹn được hai trong ba.

Bốn loại NoSQL chính

Đây là "bản đồ" giúp bạn định vị mọi công nghệ NoSQL:

LoạiVí dụUse case điển hình
Key-valueDynamoDB, RedisSession người dùng, cache, đọc/ghi khối lượng lớn theo khoá
DocumentFirestore, MongoDB, Cosmos DBHồ sơ người dùng, catalog sản phẩm, dữ liệu JSON lồng nhau
Wide-columnCassandra, BigtableTime-series, IoT, log ở quy mô petabyte
GraphNeptune, Neo4jMạng xã hội, gợi ý, phát hiện gian lận
Trong bài này ta tập trung vào hai loại phổ biến nhất trên cloud managed: key-value (DynamoDB) và document (Firestore, Cosmos DB). Cosmos DB đặc biệt ở chỗ nó là "multi-model" — hỗ trợ nhiều API khác nhau (document, key-value, graph, column) trong cùng một dịch vụ.

DynamoDB — key-value/document của AWS

DynamoDB là dịch vụ NoSQL fully-managed và serverless của AWS. Điểm mạnh cốt lõi:

  • Partition key và Sort key: DynamoDB phân phối dữ liệu dựa trên partition key (băm ra để chia đều lên các node). Sort key cho phép sắp xếp và query dải dữ liệu trong cùng một partition. Thiết kế đúng cặp khoá này là 80% thành công khi dùng DynamoDB.
  • Hiệu năng ổn định: dù bảng có 10 dòng hay 10 tỷ dòng, độ trễ vẫn ở mức mili-giây một chữ số.
  • Hai chế độ tính phí: On-demand (trả theo request thực tế, không cần dự đoán) và Provisioned (đặt trước capacity, rẻ hơn khi tải ổn định).
  • DynamoDB Streams: ghi lại mọi thay đổi để kích hoạt Lambda — nền tảng cho kiến trúc event-driven.
Điểm yếu: DynamoDB "ghét" các query không dùng khoá. Nếu bạn cần query linh hoạt kiểu "tìm tất cả đơn hàng ở TP.HCM giá trên 500k", bạn phải thiết kế trước bằng Global Secondary Index (GSI), nếu không sẽ phải scan toàn bảng — cực kỳ tốn kém.

Firestore — document database của Google Cloud

Firestore (thuộc họ Firebase, nay tích hợp sâu vào Google Cloud) là document database lưu dữ liệu dưới dạng collection chứa các document (JSON-like). Điểm nổi bật:

  • Realtime listeners: client có thể "lắng nghe" thay đổi và tự cập nhật ngay — cực hợp cho chat, bảng điểm trực tiếp, cộng tác thời gian thực.
  • Đồng bộ offline: SDK Firebase tự lưu cache và sync lại khi có mạng — lý tưởng cho app mobile ở vùng sóng yếu.
  • Query mạnh hơn DynamoDB một chút: hỗ trợ composite index, where nhiều điều kiện, nhưng vẫn tránh các phép quét toàn bộ.
Firestore được yêu thích trong giới startup và team mobile vì tốc độ phát triển nhanh, gần như không cần backend cho các tính năng cơ bản.

Cosmos DB — multi-model của Azure

Cosmos DB là "con dao đa năng" của Azure. Đặc trưng lớn nhất:

  • Phân phối toàn cầu (global distribution): bật một nút là dữ liệu được nhân bản ra nhiều region trên thế giới, ghi được ở nhiều nơi (multi-region write).
  • Năm cấp độ consistency: từ Strong (mạnh nhất) đến Eventual (lỏng nhất), cho bạn tinh chỉnh cân bằng giữa nhất quán và độ trễ — điều hiếm dịch vụ nào cho.
  • Đơn vị tính phí RU (Request Unit): mọi thao tác được quy đổi ra RU, giúp dự đoán chi phí nhưng cũng dễ gây bất ngờ nếu query nặng.
  • Nhiều API: SQL (Core), MongoDB, Cassandra, Gremlin (graph), Table.

Tình huống thực tế

Tình huống 1: Sàn thương mại điện tử Việt Nam và giỏ hàng ngày sale

Một sàn TMĐT giả định tên "ChợViệt" gặp vấn đề vào các đợt sale lớn kiểu 6/6, 9/9. Vào giờ vàng, lượng thao tác thêm/xoá sản phẩm trong giỏ hàng tăng vọt lên khoảng 40.000 request mỗi giây. Database MySQL của họ cho phần giỏ hàng liên tục bị nghẽn, thời gian phản hồi có lúc lên 3-4 giây, nhiều khách bỏ giỏ.

Đội kỹ thuật quyết định tách riêng giỏ hàng ra DynamoDB với partition key là user_id và sort key là product_id. Vì mỗi giỏ hàng chỉ đọc/ghi theo user_id — đúng kiểu key-value — DynamoDB xử lý ngon lành. Họ dùng chế độ On-demand để không phải lo dự đoán capacity trong đợt sale. Kết quả: độ trễ giảm về dưới 20ms, tỷ lệ bỏ giỏ giảm rõ rệt.

Bài học: Không phải toàn bộ hệ thống cần chuyển sang NoSQL. Chỉ cần tách đúng phần "nóng" có mẫu truy cập đơn giản (access pattern) sang key-value store là đủ. Đây gọi là kiến trúc polyglot persistence — dùng nhiều loại database cho từng bài toán.

Tình huống 2: Startup edtech dùng Firestore cho lớp học trực tuyến

Một startup edtech ở Singapore phục vụ thị trường Đông Nam Á xây tính năng lớp học tương tác: giáo viên đặt câu hỏi, học sinh trả lời, kết quả hiện lên bảng xếp hạng ngay lập tức trên màn hình của cả lớp. Với 5.000 lớp đồng thời, mỗi lớp 30 học sinh, họ cần cập nhật realtime mà không muốn tự dựng WebSocket server.

Họ chọn Firestore với realtime listeners. Mỗi khi học sinh submit đáp án, document được cập nhật và toàn bộ client đang lắng nghe tự động nhận thay đổi trong khoảng 100-200ms. Tính năng offline sync còn giúp học sinh ở vùng mạng chập chờn (như một số tỉnh xa của Indonesia, Philippines) không bị mất dữ liệu — app tự đồng bộ khi có sóng lại.

Bài học: Khi bài toán cần realtime và đồng bộ đa thiết bị, Firestore giúp bỏ qua cả một tầng backend phức tạp. Đổi lại, bạn phải cẩn thận với chi phí — Firestore tính tiền theo số document đọc/ghi, và một bảng xếp hạng cập nhật liên tục có thể tạo ra hàng triệu lượt đọc.

Tình huống 3: Ngân hàng số cần dữ liệu đa vùng với Cosmos DB

Một ngân hàng số giả định hoạt động ở cả Việt Nam và Nhật Bản cần lưu hồ sơ khách hàng và trạng thái tài khoản sao cho người dùng ở mỗi nước truy cập với độ trễ thấp, đồng thời tuân thủ yêu cầu dữ liệu phải nhân bản để phòng thảm hoạ. Họ chọn Cosmos DB với global distribution, đặt bản sao ở region Đông Nam Á và Nhật Bản.

Cái hay là họ chọn mức consistency Session cho phần lịch sử giao dịch (đảm bảo mỗi người dùng luôn thấy đúng dữ liệu mình vừa ghi), nhưng dùng Eventual cho phần dữ liệu ít nhạy cảm như cấu hình hiển thị — tiết kiệm RU và giảm độ trễ. Nhờ tinh chỉnh này, họ cân bằng được giữa an toàn dữ liệu và chi phí.

Bài học: Global distribution và consistency có thể tinh chỉnh là "vũ khí" riêng của Cosmos DB. Nhưng RU rất dễ đội chi phí — cần giám sát chặt và thiết kế partition key khéo để tránh "hot partition" (một phân vùng bị dồn quá nhiều tải).

Hướng dẫn từng bước

Dưới đây là quy trình chọn và thiết kế một NoSQL cloud database cho dự án của bạn:

  • Xác định access pattern trước khi chọn database. Đây là bước quan trọng nhất và thường bị bỏ qua. Viết ra: ứng dụng sẽ đọc/ghi dữ liệu này bằng cách nào? Query theo khoá nào? Cần lọc theo điều kiện gì? Với NoSQL, bạn thiết kế database theo query, ngược hoàn toàn với relational (thiết kế theo dữ liệu rồi mới query).
  • Chọn loại NoSQL phù hợp. Nếu chỉ đọc/ghi theo khoá đơn giản (session, cache, giỏ hàng) → key-value như DynamoDB. Nếu cần document lồng nhau linh hoạt và realtime → Firestore. Nếu cần đa vùng toàn cầu và tinh chỉnh consistency → Cosmos DB.
  • Thiết kế partition key cẩn thận. Chọn khoá phân phối dữ liệu đều, tránh dồn tải vào một phân vùng. Ví dụ đừng dùng ngày tháng làm partition key cho dữ liệu log vì hôm nay tất cả ghi vào một partition — sẽ tạo hot partition.
  • Lập chỉ mục (index) cho query phụ. Với DynamoDB, xác định trước các Global Secondary Index. Với Firestore, tạo composite index. Đừng để đến production mới phát hiện query cần index mà chưa có.
  • Chọn chế độ tính phí. Tải khó dự đoán, dao động mạnh → dùng on-demand. Tải ổn định, biết trước → provisioned/reserved để tiết kiệm.
  • Bật monitoring và alert chi phí. Theo dõi consumed capacity (DynamoDB), số document đọc (Firestore), RU tiêu thụ (Cosmos DB). Đặt budget alert ngay từ đầu.
  • Thiết lập backup và point-in-time recovery. Cả ba dịch vụ đều hỗ trợ khôi phục về thời điểm cụ thể — hãy bật lên, đừng đợi sự cố mới hối tiếc.

Lỗi thường gặp & mẹo

Lỗi 1 — Dùng NoSQL như relational. Nhiều người mang tư duy JOIN, normalize sang NoSQL rồi than "sao chậm thế". Trong NoSQL, denormalize (nhân bản dữ liệu để tránh JOIN) là chuyện bình thường. Đừng sợ lặp dữ liệu nếu nó giúp query nhanh.

Lỗi 2 — Scan toàn bảng. Trên DynamoDB, một lệnh Scan quét toàn bộ bảng có thể ngốn hàng nghìn đô nếu bảng lớn. Luôn dùng Query với khoá, hoặc thiết kế GSI phù hợp.

Lỗi 3 — Hot partition. Chọn partition key kém khiến toàn bộ tải dồn vào một node, dù bảng có phân tán vẫn nghẽn. Mẹo: thêm hậu tố ngẫu nhiên (write sharding) hoặc chọn khoá có độ phân tán cao.

Lỗi 4 — Quên chi phí đọc trên Firestore. Một listener realtime lắng nghe collection lớn có thể tạo ra hàng triệu lượt đọc mỗi ngày. Mẹo: giới hạn bằng query, phân trang, và cân nhắc gom dữ liệu để giảm số document.

Lỗi 5 — Hiểu sai consistency. Với eventual consistency, dữ liệu vừa ghi có thể chưa đọc thấy ngay. Đừng dùng cho luồng cần chính xác tức thì như số dư tài khoản. Mẹo: DynamoDB có tuỳ chọn strongly consistent read, Cosmos DB có Session consistency — chọn đúng theo nghiệp vụ.

Mẹo tổng quát: Bắt đầu bằng on-demand khi mới ra mắt để không lo capacity, sau khi có dữ liệu tải thực tế thì chuyển sang provisioned để tiết kiệm. Và luôn dùng single-table design một cách có cân nhắc với DynamoDB — mạnh nhưng khó, đừng lạm dụng nếu team chưa quen.

Bài tập thực hành

  • Phân tích access pattern: Chọn một ứng dụng bạn biết (ví dụ app đặt đồ ăn). Liệt kê 5 mẫu truy cập dữ liệu chính (đọc/ghi gì, theo khoá nào). Từ đó đề xuất nên dùng DynamoDB, Firestore hay Cosmos DB cho từng phần.
  • Thiết kế khoá DynamoDB: Cho một bảng lưu tin nhắn chat giữa các user. Hãy thiết kế partition key và sort key sao cho query "lấy 20 tin nhắn mới nhất trong một cuộc trò chuyện" chạy hiệu quả mà không cần scan.
  • Thực hành thực tế: Tạo một tài khoản free-tier trên AWS hoặc dự án Firebase miễn phí. Tạo một bảng/collection, thêm vài bản ghi, rồi thử một query có index và một query phải scan. Quan sát sự khác biệt về tốc độ và capacity tiêu thụ.
  • Bài toán chi phí: Giả sử app của bạn có 1 triệu lượt đọc và 200.000 lượt ghi mỗi ngày. Hãy tra bảng giá của DynamoDB on-demand và ước tính chi phí hàng tháng. So sánh với provisioned nếu tải ổn định.
  • Chọn consistency: Với ba tính năng — số dư ví điện tử, danh sách bài viết blog, và trạng thái "đang gõ..." trong chat — hãy chọn mức consistency phù hợp (strong hay eventual) và giải thích lý do.

Tóm tắt

NoSQL cloud database không phải là "kẻ thay thế" relational database mà là công cụ bổ sung, giải quyết các bài toán về quy mô lớn, schema linh hoạt và hiệu năng cao. Ba dịch vụ managed tiêu biểu:

  • DynamoDB (AWS): key-value/document serverless, hiệu năng mili-giây ổn định ở mọi quy mô, mạnh khi access pattern rõ ràng theo khoá. Chú ý thiết kế partition key và tránh scan.
  • Firestore (Google Cloud): document database với realtime listeners và offline sync, tuyệt vời cho app mobile và tính năng cộng tác thời gian thực. Chú ý chi phí đọc.
  • Cosmos DB (Azure): multi-model, global distribution và năm cấp consistency tinh chỉnh được. Chú ý đơn vị RU và hot partition.
Nguyên tắc vàng: thiết kế database theo access pattern, không theo dữ liệu. Denormalize khi cần, lập index cho query phụ, giám sát chi phí ngay từ đầu, và chọn đúng mức consistency theo nghiệp vụ. Nắm chắc những điều này, bạn sẽ tránh được những sai lầm đắt giá nhất khi đưa hệ thống lên quy mô hàng triệu người dùng — điều mà các bài sau về data warehouse (Bài 17) và cache (Bài 18) sẽ tiếp tục bổ trợ.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi