Khi tìm hiểu về database, chúng ta thường nghe đến các khái niệm như định lý CAP, tính chất ACID, tính chất BASE. Các khái niệm này là gì mà đi đâu ta cũng gặp phải? Hãy cùng tôi tìm hiểu trong bài này!

CAP nghĩa là cái nón?

CAP là từ viết tắt của Consitency, Availability, Partition-tolerance được giới thiệu bởi Eric Brewer vào năm 2000 trong một buổi diễn thuyết. Brewer cho rằng, trong một hệ thống phân tán (distributed system) khi một sự kiện chia cách (network partition) xảy ra, hệ thống chỉ có thể lựa chọn giữa consistency hoặc availability. Vậy ba tính chất này là gì mà các hệ thống phân tán lại muốn có, và tại sao chúng không thể cùng lúc thoả mãn cả ba?

C có nghĩa là consistency

Trong ngành khoa học máy tính, đặc biệt trong ngữ cảnh về dữ liệu, từ consistency có thể nói bị quá tải về nghĩa. Khi nó được sử dụng trong quá nhiều định nghĩa (consistency đều có mặt trong CAP, ACID, BASE) nên thường dẫn đến nhầm lẫn. Trong định lý CAP, một hệ thống thoả được tính chất consistency khi tất cả mọi máy khách của hệ thống đều có cùng một phiên bản dữ liệu tại bất kỳ điểm thời gian nào. Nói cách khác, sau một hành động viết hoặc cập nhật dữ liệu vào hệ thống thì các hành động đọc tiếp theo đó đều phải cùng thấy được phiên bản dữ liệu mới nhất. Consistency theo định lý CAP còn thường được gọi là strong consistency khác với eventual consistency trong tính chất BASE.

Consistency là một tính chất được nhiều người theo đuổi, do đây là một tính cất cần thiết trong các hệ thống mang tính chất giao dịch. Tưởng tượng trong hệ thống ngân hàng, bạn vừa gửi 1.000.000.000 tỷ VNĐ tại ngân hàng (whao!) nhưng khi tra cứu tài khoản lại không thấy khoản tiền đó! Một thảm hoạ!

A có nghĩa là availability

Theo như Seth Gilbert và Nancy Lynch, một hệ thống phân tán thoả được tính chất availability khi tất cả mọi yêu cầu đến một node đang hoạt động trong hệ thống đều phải được nhận lại được phản hồi hợp lệ. Nói cách khác hệ thống phải có uptime là 100%, miễn là kết nối mạng vẫn còn hoạt động được thì người dùng phải sử dụng được hệ thống.

Định nghĩa trên về availability là không thực tiễn, do các hệ thống hiện nay đều có downtime ví dụ như đa phần sản phẩm của Google Cloud có SLA về uptime là 99,99% (mỗi năm sẽ có khoảng 52 phút 9,8 giây downtime) sẽ không thoả mãn được yêu cầu này. Nhưng tôi cảm thấy nó dễ hiểu hơn so với định nghĩa ban đầu của Brewer rằng: “data is considered highly available if a given consumer of the data can always reach some replica”, tạm dịch: “Dữ liệu có tính sẵn sàng cao khi bất cứ một yêu cầu nào về dữ liệu phải luôn luôn có được một bản sao nhất định của dữ liệu đó”.

Availability là một tính chất được nhiều người chú trọng, mọi hệ thống đều được kỳ vọng phải luôn sẵn sàng tại mọi thời điểm. Nếu hệ thống không hoạt động có thể dẫn đến nhiều hệ luỵ nghiêm trọng, trong e-commerce chúng ta có thể mất khách hàng, hay trong hệ thống bệnh viện có thể dẫn đến trì hoãn hoạt động của bệnh viện.

P có nghĩa là partition-tolerance

Một hệ thống gọi là partition-tolerance trong trường hợp nếu một phần của hệ thống đó bị chia cách (partition) do crash, mất kết nối mạng, … thì các phần còn lại của hệ thống đó vẫn phải hoạt động như thường.

Tại sao không thể thoả mãn đồng thời CAP?

Trong một hệ thống có hai node A và B, nếu trong trường hợp có hiện tượng phân cách (partition) xảy ra. Node A sẽ không thể giao tiếp được với node B, nhưng vì hệ thống này thoả điều kiện partition-tolerance nên vẫn tiếp tục hoạt động, người dùng vẫn có thể tương tác với hệ thống điều này thoả availability. Tuy nhiên, khi dữ liệu được ghi vào A thì sẽ không tồn tại ở B, do hai node này không thể giao tiếp được với nhau, điều này không thoả được consistency. Như vậy hệ thống này chỉ thoả được AP.

Trong một hệ thống khác tương tự như trên, vì muốn dữ liệu phải consistent giữa cả hai node. Nên khi node A phát hiện kết nối đến node B đã mất, nó sẽ cố kết nối lại khiến cho người dùng không thể tương tác được đến hệ thống làm mất đi tính availability. Tuy nhiên điều này cũng đảm bảo được rằng tại bất kỳ điểm thời gian nào, dữ liệu ở cả hai node là giống nhau. Như vậy hệ thống này chỉ thoả được CP.

ACID là chất có tính ăn mòn?

ACID là một đặc trưng thường thấy trong các cơ sở dữ liệu quan hệ, được viết tắt từ Atomicity, Consistency, Isolation, Durability. Gần như bất cứ cơ sở dữ liệu nào cũng phải có được những đặc trưng này, và chúng cũng thường được dùng làm thước đo độ tin cậy của một cơ sở dữ liệu bất kỳ.

A có nghĩa là Atomicity

Atomicity là đặc trưng của database về toán tử nhỏ nhất mà các database cần phải thực hiện không phải là một query (truy vấn) mà là một transaction (giao dịch). Một transaction là một tập hợp của một hoặc nhiều query. Một transaction chỉ thành công khi tất cả các query trong nó thành công.

Điều này là rất quan trọng, vì trong thực tế, các giao dịch nghiệp vụ thường bao gồm một chuỗi các hành động. Vi dụ như giao dịch chuyển khoản ngân hàng, thì ngân hàng của bạn cần phải trừ tiền từ tài khoản của bạn và cộng tiền vào tài khoản mà bạn chuyển đến, và bất kỳ hành động nào bị thất bại thì toàn bộ giao dịch sẽ thất bại. Với atomicity, chúng ta có thể dễ dàng quản lý một transaction mà không cần quan tâm đến các state của dữ liệu trong từng query.

C có nghĩa là Consistency

Consistency trong ACID là một khái niệm khác so với consistency trong CAP hay BASE, nó mang ý nghĩa tất cả dữ liệu trong database sẽ luôn luôn tuân thủ theo các constraint/schema được định nghĩa. Các constraint này bao gồm số trường của dữ liệu, loại dữ liệu của từng trường, các khoá chính, khoá ngoại, khoá đặc biệt khác, trigger, …

I có nghĩa là Isolation

Isolation là một đặc tính dùng để cô lập các transaction chạy song song với nhau, mục tiêu chính của isolation là tránh data race xảy ra, khi có nhiều transaction cùng một lúc truy cập vào cùng một vùng dữ liệu (page, table, record). Isolation thường được thực hiện bằng cách khoá (bảng, record, index) cho các câu truy vấn dạng Data Manipulation Language (DML như INSERT, UPDATE, DELETE); khoá (bảng, record, index) hoặc tạo snapshot cho các câu truy vấn dạng Data Query Language (DQL như SELECT). Có bốn cấp độ isolation, lựa chọn cấp độ isolation cao sẽ giúp tránh được data race tuy nhiên đổi lại sẽ giảm hiệu năng của database:

Read-committed

Read-committed là mức isolation thứ hai, tuy nhiên được đề cập đầu tiên do theo tôi để hiểu các cấp độ khác cần phải hiểu về read-committed. Trong read-committed, các thay đổi trong một transaction sẽ không thấy được bởi các transaction khác, cho đến khi transaction được commit thành công.

-- Bắt đầu một transaction
BEGIN;

-- Thêm một record mới vào bảng 'example' của database 'acid'
INSERT INTO 'acid'.'example'('id', 'name')
VALUES 
    -- Các transaction khác sẽ không thấy được record này trong bảng example của database acid
    -- do transaction hiện tại chưa được commit thành công
    (2, "Chuồn chuồn bay cao thì nắng, bay vừa thì râm");

-- Commit transaction, nếu thành công các transaction khác sẽ thấy record ở trên được thêm bào bảng
COMMIT;

Repeatable-read

Repeatable-read là mức isolation thứ ba, không chỉ đảm bảo các đặc điểm của read-commited mà còn đảm bảo thêm rằng trong toàn bộ thời gian mà transaction tồn tại, các trường dữ liệu liên quan sẽ không bị thay đổi.

-- Bắt đầu một transaction
BEGIN;

-- Record này sẽ bị khoá, đảm bảo không bị transaction khác thay đổi
-- cho đến khi transaction hiện tại được commit
SELECT 'name' FROM 'acid'.'example' WHERE 'id' = 1;

-- Các câu query khác
-- ...

-- Giá trị vẫn sẽ giữ nguyên không thay đổi
SELECT 'name' FROM 'acid'.'example' WHERE 'id' = 1;

-- Commit transaction, và thả các khoá
COMMIT;

Serializable

Serializable là cấp độ isolation cao nhất, đảm bảo tất cả những đảm bảo của repeatable-read, thêm vào đó còn đảm bảo thêm rằng sẽ không record mới xuất hiện cho đến khi transaction hiện tại kết thúc.

-- Bắt đầu một transaction
BEGIN;

-- Lần query đầu tiên.
SELECT 'name' FROM 'acid'.'example' WHERE 'id' < 9999;

-- Các câu query khác
-- ...

-- Giá trị các record vẫn sẽ giữ nguyên không thay đổi
-- và số lượng record không đổi
SELECT 'name' FROM 'acid'.'example' WHERE 'id' < 9999;

-- Commit transaction, và thả các khoá
COMMIT;

Dirty-read

Dirty-read là mức isolation thấp nhất, ở dirty read thì hoàn toàn không tồn tại sự cô lập giữa các transaction.

D có nghĩa là Durability

Durability là một đặc trưng tạo nên độ tin cậy của cơ sở dữ liệu, đặc trưng này đảm bảo rằng khi một transaction đã được commit thành công thì dữ liệu sẽ tồn tại vĩnh viễn, tất nhiên miễn là ổ cứng lưu trữ không bị hư hỏng. Điều này thường được thực hiện bằng kỹ thuật two-phase commit, backup, hay replicate. Như trong MySQL, với mỗi commit, database sẽ ghi dữ liệu vào binlog trước khi ghi dữ liệu vào page lưu trữ, nếu MySQL crash trong lúc viết vào page thì có thể đọc từ binlog để khôi phục lại dữ liệu. Ngoài ra binlog còn được dùng để sync dữ liệu giữa các replica. Tương tự trong MongoDB thì có oplog.

BASE!?

BASE là một thuật ngữ thường được các cơ sở dữ liệu phân tán sử dụng. Các database được thiết kế theo BASE, tập trung vào tính availability của hệ thống bằng cách hy sinh tính strong consistency. Cả hai khái niệm về availabilitystrong consistency là các định nghĩa được sử dụng trong CAP đề cập bên trên.

BA có nghĩa là Basically Available

Đảm bảo rằng hệ thống sẽ luôn luôn sẵn sàng, và tất cả mọi yêu đến hệ thống đều sẽ nhận được một phản hồi hợp lệ.

S có nghĩa là Soft-State

Soft-State là đặc tính của database cho rằng state (trạng thái, dữ liệu) của database có thể thay đổi ngay cả khi không có input từ user. Đây được xem là một kết quả của tính eventual consistency, khi người dùng viết dữ liệu vào database, trạng thái của database sẽ không thay đổi ngay lập tức mà sẽ cần một khoảng thời gian để thay đổi có thể được truyền tải đến tất cả các node.

E có nghĩa là Eventual Consistency

Eventual consistency đảm bảo sau một khoảng thời gian thì tất cả các node trong hệ thống đều sẽ được đồng bộ với nhau. Kết quả mang lại là trong tại cùng một thời điểm các node trong hệ thống có thể chứa các phiên bản dữ liệu khác nhau. Điều này khác với strong consistency đảm bảo tất cả các node trong hệ thống sẽ luôn luôn được đồng bộ ngay lập tức, tất cả các node có cùng một phiên bản dữ liệu.

Đọc thêm

  • Seth Gilbert and Nancy Lynch, “Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services”, comp.nus.edu.sg
  • ScylaDB, “CAP Theorem”, scylladb.com
  • Martin Kleppmann, “A Critique of the CAP Theorem”, arXiv:1509.05393
  • MySQL, “InnoDB and the ACID Model”, dev.mysql.com
  • PostgreSQL, “Concurrency Control”, postgresql.org
  • MongoDB, “A Guide to ACID Properties in Database Management Systems”, mongodb.com
  • MongoDB, “Multi-Document ACID Transactions on MongoDB”, mongodb.com
  • AWS, “Điểm khác biệt giữa ACID và cơ sở dữ liệu BASE là gì?”, aws.amazon.com