Đặc tính của giao dịch cơ sở dữ liệu (ACID)
1. Tổng quan
A. Định nghĩa
Giao dịch (Transaction) là một đơn vị công việc logic (logical unit of work) làm thay đổi trạng thái của cơ sở dữ liệu, gộp nhiều thao tác đọc/ghi lại và bảo đảm tất cả cùng thành công (Commit) hoặc tất cả cùng thất bại (Rollback). Bốn tính chất mà độ tin cậy này phải có được quy định là ACID (Atomicity·Consistency·Isolation·Durability).
Bản chất của giao dịch nằm ở nguyên tắc 'tất cả hoặc không gì cả (All or Nothing)'. Lấy ví dụ chuyển khoản ngân hàng, thao tác rút 100 nghìn won từ tài khoản A và thao tác nạp 100 nghìn won vào tài khoản B về mặt logic là một sự kiện duy nhất, nên bắt buộc phải cùng thành công hoặc cùng thất bại. Nếu việc rút tiền được ghi nhận nhưng việc nạp tiền bị bỏ sót do sự cố hệ thống, 100 nghìn won sẽ biến mất khỏi thế giới và dữ liệu rơi vào trạng thái mâu thuẫn. Giao dịch xử lý nhóm thao tác như vậy như một đơn vị, nếu có lỗi giữa chừng thì đưa trạng thái trở về thời điểm bắt đầu một cách nguyên tử (rollback).
ACID là sự phân rã độ tin cậy này thành bốn trục theo câu hỏi 'được cấu thành bởi những tính chất nào'. Tính nguyên tử bảo đảm 'không thể chia nhỏ', tính nhất quán bảo đảm 'không vi phạm quy tắc', tính cô lập bảo đảm 'thực thi đồng thời trông như thực thi tuần tự', tính bền vững bảo đảm 'một khi đã xác nhận thì không mất đi'. Chỉ khi bốn tính chất này được tuân thủ đồng thời, cơ sở dữ liệu mới vận hành như một 'hệ thống ghi nhận đáng tin cậy (system of record)' trong môi trường luôn tồn tại nhiều người dùng và sự cố. Đó là lý do ACID trở thành nền tảng của DBMS quan hệ trong các miền mà độ chính xác của dữ liệu chính là niềm tin và trách nhiệm pháp lý như ngân hàng, chứng khoán, thương mại điện tử, đặt vé máy bay.
B. Bối cảnh ra đời và sự cần thiết
Các hệ thống tệp ban đầu dễ làm hỏng dữ liệu khi nhiều người dùng cùng cập nhật một dữ liệu hoặc mất điện giữa lúc xử lý. Nếu bỏ mặc các vấn đề như mất cập nhật (lost update), cập nhật một phần, đọc bẩn (dirty read), tính toàn vẹn của dữ liệu kế toán, tồn kho, đặt chỗ sẽ sụp đổ. Khái niệm ra đời để giải quyết tận gốc vấn đề này là giao dịch, và lý thuyết xử lý giao dịch do Jim Gray (Jim Gray) xác lập trong những năm 1970~80 đã trở thành nền tảng lý thuyết của ACID ngày nay.
Sự cần thiết được tổng hợp theo hai trục. Thứ nhất là tính đồng thời (concurrency). Trong môi trường vô số người dùng cùng đọc và ghi một dữ liệu, phải bảo đảm tính đúng đắn của kết quả như thể mỗi giao dịch được thực thi một mình. Thứ hai là phục hồi sự cố (recovery). Giữa các sự cố có thể xảy ra bất cứ lúc nào như mất điện, lỗi đĩa, tiến trình bị buộc dừng, kết quả đã commit phải tồn tại còn kết quả chưa commit phải biến mất không dấu vết. ACID là hợp đồng (contract) để thỏa mãn hai yêu cầu này, và các cơ chế tuân thủ nó như khóa, log, MVCC tạo nên cốt lõi của engine DBMS.
2. Bốn đặc tính ACID
ACID là tập hợp bốn tính chất bảo đảm độ tin cậy của giao dịch từ các góc nhìn khác nhau. Sơ đồ cấu trúc dưới đây cho thấy bốn đặc tính đảm nhận góc nhìn nào dưới một khái niệm giao dịch.
flowchart TB
T["Giao dịch ACID"] --> A["Tính nguyên tử<br/>Atomicity<br/>(tất cả hoặc không)"]
T --> C["Tính nhất quán<br/>Consistency<br/>(duy trì quy tắc)"]
T --> I["Tính cô lập<br/>Isolation<br/>(chặn can thiệp đồng thời)"]
T --> D["Tính bền vững<br/>Durability<br/>(lưu giữ vĩnh viễn)"]
A -. hiện thực .-> AM["UNDO log·rollback"]
C -. hiện thực .-> CM["Ràng buộc toàn vẹn·trigger"]
I -. hiện thực .-> IM["Khóa·MVCC·mức cô lập"]
D -. hiện thực .-> DM["REDO log·WAL·sao lưu"]
style T fill:#e8f0fe,stroke:#2f6fed,stroke-width:2px
A. Tính nguyên tử (Atomicity)
Tính nguyên tử có nghĩa là các thao tác cấu thành giao dịch được xử lý như một khối không thể chia nhỏ hơn nữa. Hoặc mọi thao tác được ghi nhận thành công (Commit), hoặc chỉ cần một thao tác thất bại thì cả những thao tác đã thực thi cũng bị hủy toàn bộ (Rollback) và trở về trạng thái trước khi bắt đầu. Trạng thái trung gian (ví dụ: chỉ rút tiền mà chưa nạp tiền) tuyệt đối không bao giờ còn lại bên ngoài như một kết quả đã xác nhận.
Hãy xem lại chuyển khoản để thấy vấn đề gì xảy ra nếu không có tính nguyên tử. Nếu máy chủ sập ngay sau khi lệnh UPDATE rút tiền thành công, trong hệ thống không bảo đảm tính nguyên tử, chỉ việc rút tiền được ghi nhận và tổng tài sản bị lệch. Tính nguyên tử khi đó dùng UNDO log để hoàn tác việc rút tiền đã ghi nhằm khôi phục tính đúng đắn. Như vậy, tính nguyên tử chịu trách nhiệm về 'rút lui an toàn khi thất bại'.
Về mặt hiện thực, tính nguyên tử chủ yếu được thực hiện bằng rollback dựa trên log. DBMS ghi trước giá trị trước thay đổi vào UNDO log trước khi thực sự thay đổi dữ liệu, và khi giao dịch thất bại thì áp dụng log này theo thứ tự ngược để khôi phục nguyên trạng. Do đó, tính nguyên tử cũng như tính bền vững nêu sau đây phụ thuộc trực tiếp vào chất lượng quản lý log.
B. Tính nhất quán (Consistency)
Tính nhất quán có nghĩa là cả trước và sau khi giao dịch thực thi, cơ sở dữ liệu đều được duy trì ở trạng thái thỏa mãn các quy tắc định nghĩa trước (ràng buộc toàn vẹn). Quy tắc bao gồm ràng buộc khóa chính và khóa ngoại, NOT NULL, ràng buộc CHECK, và các quy tắc nghiệp vụ như "tổng số dư mọi tài khoản trước và sau chuyển khoản là như nhau". Giao dịch di chuyển dữ liệu từ một trạng thái nhất quán sang một trạng thái nhất quán khác, và dù quá trình trung gian có vi phạm quy tắc, tại thời điểm commit bắt buộc phải thỏa mãn mọi quy tắc.
Điểm cần lưu ý ở đây là trách nhiệm về tính nhất quán được chia giữa DBMS và ứng dụng. DBMS cưỡng chế các ràng buộc và trigger đã khai báo, nhưng các quy tắc miền như "bảo toàn tổng số tiền chuyển" chỉ được tuân thủ khi ứng dụng viết SQL đúng. Tức là dù tính nguyên tử, cô lập, bền vững được tuân thủ, nếu lập trình viên đưa vào logic sai thì tính nhất quán vẫn có thể bị phá vỡ. Ở điểm này, tính nhất quán không phải là chức năng thuần túy của engine mà là sự phối hợp 'bảo đảm của engine + thiết kế đúng'.
Hãy xem hệ thống quản lý tồn kho làm tình huống thực tế. Giao dịch đặt hàng trừ số lượng tồn kho, và nếu đặt ràng buộc CHECK(stock >= 0) để tồn kho không âm, DBMS sẽ ngăn vi phạm quy tắc và từ chối commit. Khi khai báo ràng buộc ở tầng dữ liệu như vậy, dù ứng dụng có lỗi thì tuyến phòng thủ cuối cùng vẫn hoạt động.
C. Tính cô lập (Isolation)
Tính cô lập bảo đảm dù nhiều giao dịch thực thi đồng thời, kết quả vẫn giống như mỗi giao dịch được thực thi tuần tự một mình. Tức là kết quả trung gian của giao dịch đang thực thi không được hiển thị cho giao dịch khác, và việc thực thi đồng thời không được làm tổn hại tính đúng đắn của nhau. Nếu luôn cưỡng chế cô lập hoàn toàn (tính khả tuần tự, Serializability) thì tính đồng thời giảm mạnh, nên trong thực tế đặt ra mức cô lập (Isolation Level) để đánh đổi giữa hiệu năng và tính đúng đắn.
Có ba hiện tượng bất thường tiêu biểu xuất hiện khi cô lập không hoàn toàn. Đọc bẩn (Dirty Read) là đọc thay đổi chưa commit của người khác, đọc không lặp lại được (Non-repeatable Read) là đọc cùng một hàng hai lần mà giá trị khác nhau, đọc bóng ma (Phantom Read) là truy vấn cùng điều kiện mà số hàng khác nhau. ANSI SQL định nghĩa bốn mức cô lập theo mức độ cho phép các hiện tượng bất thường này.
| Mức cô lập | Đọc bẩn | Đọc không lặp lại | Đọc bóng ma |
|---|---|---|---|
| READ UNCOMMITTED | Cho phép | Cho phép | Cho phép |
| READ COMMITTED | Ngăn chặn | Cho phép | Cho phép |
| REPEATABLE READ | Ngăn chặn | Ngăn chặn | Cho phép (tùy hiện thực có thể ngăn) |
| SERIALIZABLE | Ngăn chặn | Ngăn chặn | Ngăn chặn |
Nâng mức cô lập càng cao thì tính đúng đắn càng tốt nhưng phạm vi khóa rộng hơn hoặc số lần thử lại tăng, khiến tính đồng thời và thông lượng giảm. Chẳng hạn, quyết toán ngân hàng cần cô lập mạnh gần SERIALIZABLE, còn danh mục sản phẩm chủ yếu là truy vấn thì READ COMMITTED là đủ. Cách hiện thực cũng chia thành hai dòng. Dòng dựa trên khóa (Lock-based) truyền thống ngăn xung đột bằng khóa đọc và khóa ghi, còn MVCC (điều khiển đồng thời đa phiên bản) duy trì nhiều phiên bản (snapshot) của dữ liệu để nâng cao tính đồng thời với đặc tính "đọc không chặn ghi". Oracle, PostgreSQL, MySQL InnoDB áp dụng MVCC để bảo đảm hiệu năng đọc là ví dụ tiêu biểu.
D. Tính bền vững (Durability)
Tính bền vững có nghĩa là kết quả của giao dịch đã commit thành công được lưu giữ vĩnh viễn dù sau đó xảy ra bất kỳ sự cố nào (mất điện, crash). Người dùng đã nhận phản hồi commit phải có thể tin rằng kết quả đó sẽ không mất đi. Kỹ thuật hiện thực cốt lõi của tính bền vững là WAL (Write-Ahead Logging, ghi log trước). Trước khi ghi trang dữ liệu xuống đĩa, nội dung thay đổi được ghi an toàn vào REDO log trước, và chỉ sau khi log đã nằm yên trên đĩa mới xác nhận commit.
Nhờ WAL, dù máy chủ chết ngay sau commit, khi khởi động lại sẽ áp dụng lại REDO log (roll-forward) để khôi phục các thay đổi đã commit, và loại bỏ các giao dịch chưa hoàn tất bằng UNDO (roll-back) để khớp tính đúng đắn. Lý do nguyên tắc 'ghi log trước' này đồng thời bảo đảm hiệu năng và an toàn là vì ghi tuần tự log nhanh hơn nhiều so với mỗi lần ghi trang dữ liệu ở vị trí bất kỳ xuống đĩa, mà vẫn để lại căn cứ phục hồi.
Tuy nhiên, tính bền vững cũng có giới hạn là phụ thuộc vào độ tin cậy của tầng lưu trữ. Nếu log chỉ nằm trong bộ đệm của OS mà chưa được flush xuống đĩa thật và mất điện xảy ra thì commit có thể bị mất, nên trong thực tế tăng cường tính bền vững bằng cưỡng chế fsync, cache có pin dự phòng, nhiều bản sao (replication). Tổng hợp bốn đặc tính và kỹ thuật hiện thực bằng bảng như sau.
| Đặc tính | Nội dung bảo đảm | Kỹ thuật hiện thực tiêu biểu |
|---|---|---|
| Tính nguyên tử (Atomicity) | Ghi nhận tất cả hoặc không ghi nhận gì | Commit/rollback, UNDO log |
| Tính nhất quán (Consistency) | Duy trì quy tắc·ràng buộc | Ràng buộc toàn vẹn, trigger, logic ứng dụng đúng |
| Tính cô lập (Isolation) | Chặn can thiệp giữa các giao dịch đồng thời | Khóa·MVCC, mức cô lập |
| Tính bền vững (Durability) | Lưu giữ vĩnh viễn kết quả commit | REDO log·WAL, fsync, nhân bản·sao lưu |
3. Chuyển trạng thái giao dịch và giao thức commit
Giao dịch trải qua một vòng đời (trạng thái) xác định, và việc quản lý trạng thái này chính là hiện thực thực chất của tính nguyên tử và bền vững. Sơ đồ trạng thái dưới đây thể hiện các chuyển trạng thái của giao dịch từ lúc bắt đầu đến khi hoàn tất hoặc hủy bỏ.
stateDiagram-v2
[*] --> Active: BEGIN
Active --> PartiallyCommitted: Thực thi thao tác cuối cùng
Active --> Failed: Phát sinh lỗi
PartiallyCommitted --> Committed: Log đã ghi·COMMIT
PartiallyCommitted --> Failed: Lỗi khi commit
Failed --> Aborted: ROLLBACK
Committed --> [*]
Aborted --> [*]
Giao dịch đi vào trạng thái hoạt động (Active) cùng với BEGIN để thực hiện các thao tác, và khi hoàn thành thao tác cuối cùng thì chuyển sang hoàn tất một phần (Partially Committed). Tại thời điểm này thay đổi có thể vẫn chỉ nằm trong bộ nhớ (buffer), và chỉ khi REDO log được ghi an toàn xuống đĩa mới được xác nhận là hoàn tất (Committed). Nếu có lỗi trong khi thực thi, giao dịch vào trạng thái thất bại (Failed), khôi phục nguyên trạng bằng UNDO log thông qua ROLLBACK rồi kết thúc ở hủy bỏ (Aborted). Ở chỗ COMMIT xác nhận vĩnh viễn kết quả còn ROLLBACK đưa về trạng thái bắt đầu, bản thân chuyển trạng thái này là thủ tục thực thi cụ thể của tính nguyên tử (cấm lộ trạng thái trung gian) và tính bền vững (commit sau khi log đã ghi).
Trong môi trường phân tán, nhiều nút tham gia nên commit đơn thuần không thể giữ được tính nguyên tử. Khi đó dùng commit hai pha (2PC, Two-Phase Commit). Chia thành giai đoạn chuẩn bị (prepare) trong đó bộ điều phối (coordinator) hỏi mọi bên tham gia "có thể commit không?", và giai đoạn xác nhận (commit) ra lệnh "hãy commit" khi tất cả đồng ý; chỉ cần một nút chuẩn bị thất bại thì rollback toàn bộ. Tuy nhiên, 2PC có điểm yếu là vấn đề chặn (blocking) khiến bên tham gia chờ vô hạn khi bộ điều phối sập, và chi phí độ trễ lớn, nên trong hệ thống phân tán quy mô lớn, các phương án thay thế như Saga sẽ trình bày sau được ưa chuộng hơn.
4. Mở rộng trong môi trường phân tán — BASE·CAP·Saga
ACID vốn mạnh mẽ trên một nút đơn, nhưng ngay khi dữ liệu được phân tán ra nhiều nút thì chi phí tăng vọt. Định lý CAP giải thích lý do căn bản của điều đó. Hệ thống phân tán không thể đồng thời thỏa mãn hoàn toàn ba yếu tố tính nhất quán (Consistency), tính sẵn sàng (Availability), khả năng chịu phân vùng (Partition tolerance), và trong thực tế phân vùng mạng (P) là không tránh khỏi, phải nhượng bộ ở mức độ nào đó một trong C và A. Nếu kiên trì nhất quán mạnh (ACID) thì tính sẵn sàng giảm khi phân vùng, còn nếu ưu tiên tính sẵn sàng thì phải chấp nhận bất nhất tạm thời.
Trong đánh đổi này, mô hình mà phe chọn tính sẵn sàng và khả năng mở rộng áp dụng là BASE (Basically Available, Soft state, Eventually consistent). BASE hướng đến nhất quán cuối cùng (Eventual Consistency) thay vì luôn nhất quán tức thì. Tức là ngay sau cập nhật, giá trị giữa các nút có thể tạm khác nhau, nhưng sau một khoảng thời gian mọi bản sao sẽ hội tụ về cùng giá trị. Mô hình này phù hợp với dữ liệu mà bất nhất tức thời không gây hậu quả nghiêm trọng như số 'lượt thích' trên mạng xã hội quy mô lớn hay lượt xem sản phẩm, và NoSQL như Cassandra, DynamoDB là đại diện của mô hình này.
| Phân loại | ACID | BASE |
|---|---|---|
| Định hướng | Nhất quán mạnh·tính đúng đắn | Tính sẵn sàng·khả năng mở rộng |
| Mô hình nhất quán | Nhất quán tức thì | Nhất quán cuối cùng |
| Nơi sử dụng tiêu biểu | Tài chính·kế toán·đặt chỗ | SNS·log·gợi ý·cache |
| Công nghệ tiêu biểu | RDBMS (2PC) | NoSQL, hệ thống dựa trên message |
Trong MSA (kiến trúc microservice), mỗi dịch vụ có DB riêng và một nghiệp vụ trải qua nhiều DB nên không thể dùng giao dịch truyền thống. Khi đó mẫu Saga trở thành phương án thay thế. Saga chia nghiệp vụ dài thành chuỗi giao dịch cục bộ, và nếu thất bại giữa chừng thì thực thi giao dịch bù trừ (compensating transaction) hoàn tác các bước đã thành công trước đó để mô phỏng tính nguyên tử logic. Chẳng hạn, trong luồng đặt hàng→thanh toán→giao hàng, nếu đặt lịch giao hàng thất bại thì thực hiện các thao tác bù trừ hủy thanh toán, hủy đơn hàng theo thứ tự ngược. Saga được hiện thực theo hai cách là choreography (dựa trên sự kiện) và orchestration (bộ điều phối trung tâm), đạt được khả năng mở rộng mà không bị chặn như 2PC nhưng phải trả giá bằng 'từ bỏ nhất quán tức thì' và 'gánh nặng thiết kế logic bù trừ'.
5. Chuyên sâu — Xu hướng mới nhất và ứng dụng thực tế
Trong một thời gian, xu hướng "bỏ ACID để mở rộng" (giai đoạn đầu của NoSQL) chiếm ưu thế, nhưng gần đây NewSQL và SQL phân tán nhằm hồi sinh ACID ngay cả trong môi trường phân tán đã nổi lên mạnh mẽ. Google Spanner dùng đồng hồ nguyên tử (TrueTime) để cung cấp nhất quán mạnh và nhất quán bên ngoài (external consistency) ở quy mô toàn cầu, còn CockroachDB, YugabyteDB, TiDB hiện thực điều này trong dòng mã nguồn mở, nhắm tới cả hai mục tiêu "mở rộng ngang + ACID". Điều này cho thấy nhu cầu lớn về bảo đảm khả năng mở rộng mà không đẩy gánh xử lý phức tạp của nhất quán cuối cùng sang lập trình viên.
Bản thân xử lý giao dịch của phe quan hệ cũng đã tiến hóa. Nhiều DBMS áp dụng MVCC làm mặc định để giảm xung đột giữa đọc và ghi, và PostgreSQL cung cấp mức SERIALIZABLE mà không cần khóa bằng cô lập snapshot khả tuần tự (SSI, Serializable Snapshot Isolation). Ngoài ra, các DB được quản lý trên đám mây (như Aurora) tách log xuống tầng lưu trữ để tối ưu ghi WAL và nhân bản, qua đó đồng thời nâng cao tính bền vững và tính sẵn sàng. Trong thực tế, hiểu các đặc tính này và chọn cấp độ nhất quán phù hợp với tính chất nghiệp vụ trở thành năng lực cốt lõi của thiết kế.
Điểm ra đề theo góc nhìn Kỹ sư chuyên nghiệp Quản lý Thông tin nhìn chung có ba nhánh: ① trình bày chính xác định nghĩa và kỹ thuật hiện thực của từng đặc tính ACID, ② trình bày quan hệ tương ứng giữa mức cô lập và các hiện tượng bất thường bằng bảng và tình huống, ③ bàn về giới hạn của ACID trong môi trường phân tán bằng cách mở rộng sang CAP, BASE, 2PC, Saga. Đặc biệt, bài làm giải thích lý do của sự đánh đổi như "vì sao hạ mức cô lập", "vì sao dùng Saga trong MSA" sẽ có sức phân loại cao.
6. Lưu ý và hàm ý
Đánh đổi giữa tính cô lập và hiệu năng là cốt lõi của thực tiễn. Nâng mức cô lập thì tính đúng đắn tốt hơn nhưng tính đồng thời và thông lượng giảm do khóa và thử lại. Cần áp dụng phân cấp theo đặc tính nghiệp vụ, như nghiệp vụ chủ yếu truy vấn dùng READ COMMITTED, còn nghiệp vụ coi trọng độ chính xác như quyết toán, tồn kho đặt từ REPEATABLE READ trở lên.
Tính nhất quán là trách nhiệm chung của engine và ứng dụng. Dù DBMS cưỡng chế quy tắc bằng ràng buộc và trigger, quy tắc miền (bảo toàn tổng số tiền...) chỉ được giữ khi có thiết kế SQL đúng. An toàn hơn là khai báo ràng buộc ở tầng dữ liệu để có tuyến phòng thủ cuối cùng trước lỗi ứng dụng.
Trong môi trường phân tán, nới lỏng và tái cấu trúc ACID phù hợp với tình huống. 2PC cho tính nguyên tử mạnh nhưng chi phí chặn và độ trễ lớn, còn BASE và Saga cho khả năng mở rộng nhưng kéo theo nhất quán cuối cùng và gánh nặng logic bù trừ. Dưới ràng buộc của CAP, phải quyết định đặt trọng tâm vào nhất quán mạnh hay tính sẵn sàng tùy theo mức độ quan trọng của dữ liệu.
Phục hồi dựa trên log là nền tảng vật lý của độ tin cậy. Vì tính nguyên tử và bền vững được hiện thực bằng UNDO·REDO log (WAL), quản lý log, checkpoint, chiến lược sao lưu cùng cấu hình fsync và nhân bản quyết định thực chất của tính toàn vẹn dữ liệu. Tính bền vững phụ thuộc vào độ tin cậy của tầng lưu trữ nên phải được tăng cường bằng dự phòng kép và nhân bản.
Xem xét lại 'sự song hành của khả năng mở rộng và ACID' với NewSQL và SQL phân tán. Với sự xuất hiện của Spanner, CockroachDB..., tiền đề "muốn mở rộng thì phải bỏ ACID" đã bị lung lay. Khi thiết kế hệ thống mới, hợp lý hơn là trước khi chấp nhận nhất quán cuối cùng, hãy xem xét liệu SQL phân tán có đáp ứng được hiệu năng yêu cầu hay không.
Tài liệu tham khảo
- Wikipedia, "ACID" — https://en.wikipedia.org/wiki/ACID
- PostgreSQL Documentation, "Transaction Isolation" — https://www.postgresql.org/docs/current/transaction-iso.html
- microservices.io, "Pattern: Saga" — https://microservices.io/patterns/data/saga.html
Tóm tắt một câu: Giao dịch là đơn vị công việc logic tất cả thành công hoặc tất cả thất bại, bảo đảm độ tin cậy bằng cách hiện thực tính nguyên tử, nhất quán, cô lập, bền vững (ACID) qua khóa, MVCC và log (WAL); trong môi trường phân tán, NoSQL, MSA thì điều chỉnh đánh đổi bằng BASE, 2PC, Saga dưới ràng buộc của CAP, và gần đây NewSQL đang thử nghiệm sự song hành giữa khả năng mở rộng và ACID.