Mình bắt gặp rất nhiều cuộc trò chuyện và hội thoại trong cuộc sống hàng ngày, nói về transaction trong Database, nhưng đa phần đều là quan niệm sai lầm:
- Database A có transaction còn Database B không có transaction
- Transaction phải bao gồm 4 yếu tố ACID
- Chán cái bọn NoSQL mãi không chịu hỗ trợ transaction!
Qua bài này, mình sẽ giới thiệu lại tổng quan một chút về Transaction để mọi người hiểu rõ hơn về nó. Lợi ích ngay trước mắt mà anh em có thể nhận được qua bài viết này, đó là khi mình sẽ không bị bối rối và nhầm lẫn giữa các thuật ngữ khi đọc tài liệu của bọn nước ngoài.
Vậy Transaction là gì?
Transaction chính là cái chữ cái T ở trong thuật ngữ OLTP (Online transaction processing). OLTP là hệ thống phục vụ các hoạt động tương tác của ứng dụng, ghi nhận dữ liệu mới liên tục, và cho phép truy xuất nhanh các dữ liệu gần đây. Hầu hết các mô hình Database hiện nay đều phục vụ cho mục đích OLTP: từ thanh toán mua sắm, đặt hàng, giao hàng cho tới đăng bài viết, cập nhật profile trên mạng xã hội… còn 1 loại khác là OLAP thì dùng cho mục đích thống kê, không cần liên tục cập nhật realtime, xấp xỉ là đủ. Chi tiết hơn sự khác nhau giữa 2 loại này thì mọi người xem trong bài Database 302: OLTP hay OLAP?
Transaction chính là đại diện cho những cái hoạt động tương tác bên trong ứng dụng OLTP. Định nghĩa về mặt kỹ thuật thì Transaction là một đơn vị công việc nhỏ nhất của Database (không thể nhỏ hơn được nữa), nó có thể chỉ là 1 thao tác đơn giản như SELECT, INSERT hay UPDATE, hoặc cũng có thể là 1 nhóm bao gồm nhiều operation bên trong. Sở dĩ nó có cái tên gọi như vậy vì ban đầu vốn OLTP thường được dùng cho mục đích tài chính (giao dịch với khách hàng, đối tác, tính toán trả lương cho nhân viên,…).
Qua thời gian bị biến tướng và lạm dụng đánh bóng Marketing bởi những người không hiểu về kỹ thuật, từ transaction không còn mang nghĩa “giao dịch” như ban đầu nữa. Đó là một lẽ tất yếu của ngôn ngữ thôi, dù tiếng Anh hay tiếng Việt thì cũng đều gặp rất nhiều những trường hợp như vậy. Tuy nhiên, vì đặc thù của ngành kỹ thuật, ta nên biết rõ hơn về nguồn gốc của nó để không bị ngộ nhận “Transaction phải bao gồm 4 yếu tố ACID”.
Có tồn tại Database nào không có Transaction hay không?
Như đã nói ở trên, Transaction là một đơn vị công việc nhỏ nhất của Database (không thể nhỏ hơn được nữa). Bản chất, những cái thao tác đơn giản như Put hoặc Get bản ghi trong 1 con Key-Value Store thôi cũng được coi là 1 transaction.
Transaction có thể gồm 1 operation, hoặc có thể chứa nhiều operation bên trong:
- Khi ghi vào Database, thường sẽ cần 2 thao tác: ghi data vào mem và ghi log vào file WAL.
- Đối với những Database đang hỗ trợ Secondary Index: transaction bao gồm cả thao tác cập nhật index mỗi khi có data mới được ghi.
- Rất nhiều function được Database xử lý rất phức tạp nhưng có lẽ anh em không hề biết, có thể kể đến như:
UPDATE users SET revenue=revenue+10
append
trong HBaseSELECT COUNT(*) FROM users
Như vậy, mình xin khẳng định rằng là:
Database nào cũng đều có transaction hết
Chỉ có 2 loại:
- Hỗ trợ ACID: anh em vẫn thường gọi là “Có transaction”
- Không hỗ trợ ACID: thường bị hắt hủi gọi là “Không có transaction”
Gọi thế nào thì tùy anh em, cả cộng đồng cùng quy ước rồi mà mình lại không tuân theo thì lại bị gọi là thằng thượng đẳng mất… cho nên, ngoài đời mình cũng gọi như vậy 😀 tuy nhiên, nên hiểu bản chất bên dưới của nó thì sẽ tốt hơn, tránh bị lừa đảo bởi những chiêu trò bánh vẽ marketing nói rằng
Database X có transaction
– đúng là có transaction thật, chỉ là không có ACID mà thôi.
ACID là gì?
Nó là viết tắt của 4 từ: Atomicity, Consistency, Isolation, và Durability, được đề xuất ra bởi Theo Härder và Andreas Reuter vào năm 1983, nhằm mục đích đề ra tiêu chuẩn chịu lỗi của Database. Tiêu chuẩn là như vậy, còn triển khai ra làm sao thì 2 ông ấy lại không đề cập (giống hệt sếp tôi). Cho nên là mỗi thằng Database cũng implement một kiểu khác nhau, trong đó: motip chung thường sẽ gồm nhiều mức thấp thấp và chỉ 1 cái cao nhất là đạt chuẩn 100% Serializable Isolation (còn chạy nhanh hay chậm và có nên đem ứng dụng vào thực tế hay không thì … KHÔNG NHÉ).
Mặc định nhà phát triển sẽ cấu hình sẵn ở mức thấp, và dữ liệu sẽ không đảm bảo được chính xác như những gì mình kỳ vọng. Nên anh em cũng nên rất cẩn thận với loại hình bánh vẽ Marketing thứ hai:
Database Y có hỗ trợ ACID
– nhưng chỉ nên dùng ở mức độ thấp thôi
Một loại bánh vẽ khác mà MongoDB từng dùng ở version cũ:
Database Z có hỗ trợ ACID
– nhưng chỉ ở mức độ single object thôi nhé
Tốt nhất là nên đọc kỹ whitepaper của nó để xem nó implement bên dưới như nào, và thực hiện benchmark để kiểm chứng. Tham khảo benchmark của Martin Kleppmann về mức độ Isolation của các Database mô hình quan hệ đang phổ biến hiện nay nhé: https://github.com/ept/hermitage
A – Atomicity
Từ Atom trong tiếng Anh có nghĩa là nguyên tử, tượng trưng cho 1 thứ mà không thể chia nhỏ hơn được nữa. Đứng từ góc độ người sử dụng Database, ta chỉ có thể quan sát được trạng thái trước khi Transaction diễn ra hoặc sau khi Transaction đã hoàn thành. Nếu bị thất bại hoặc từ chối, các trạng thái tạm thời cần phải được trả lại nguyên vẹn như khi chưa hề diễn ra Transaction.
Atomicity giúp cho người sử dụng có thể dễ dàng retry lại khi gặp lỗi, không phải lo nghĩ về việc bị duplicate hoặc dữ liệu không chính xác. Một số người đề xuất từ Abortability thì hợp lý hơn, vì từ Atomicity dễ gây nhầm lẫn với chữ I (Isolation).
C – Consistency
Consistency ở đây không hẳn chỉ là C ở trong CAP (nhất quán giữa các node), mà nó còn hơn vậy: dữ liệu cần phải nhất quán với những rule đã đặt ra, chẳng hạn như:
- username A đã tồn tại trong unique index nên transaction cần phải abort, nếu thành công (tức chưa tồn tại) thì phải lập tức bổ sung A vào index username.
- họ và tên không dài quá 100 ký tự
Tuy nhiên, đa phần database sẽ không thể thay ta validate được hết tất cả các rule oái ăm được, nên cái việc Consistent hay không còn phụ thuộc vào code của người sử dụng nữa. Nhớ validate cẩn thận, một khi mà có bug thì toang đấy, không có Database nào có thể cứu được mình đâu. Chẳng hạn như A chuyển 300$ cho B:
- Cộng 300$ vào tài khoản của B nhưng quên không trừ của A đi 300$
- Quên không kiểm tra A có hơn 300$ trong tài khoản
I – Isolation
Database có thể được truy cập bởi nhiều kết nối cùng 1 lúc, có thể dẫn tới nguy cơ bị lỗi race condition khi xử lý bất đồng bộ. Ví dụ như hình bên dưới:
Isolation thường bị nhầm với Atomicity (vì cái từ Atom), ở khía cạnh người sử dụng thì ta sẽ không thể xem được trạng thái bên trong của Transaction. Tuy nhiên, giữa các thread bên trong Database thì chúng vẫn nhìn thấy được nhau, và phải tự điều phối làm sao để operation của thread này không ảnh hưởng tới kết quả của thread khác. Trong đó mức độ isolation cao nhất là serializability – trải nghiệm y như xử lý tuần tự vậy, dù chúng nó chạy song song.
Tuy nhiên, thực tế serializability ít được sử dụng trong cấu hình mặc định, thậm chí OracleDB còn không thèm hỗ trợ mức độ này.
D – Durability
Đã commit thành công rồi thì kể cả có sự cố về điện hay lỗi phần cứng gì thì cũng phải đảm bảo dữ liệu không bị mất mát.
Thực tế, đây mới là yếu tố quan trọng nhất của ACID, các nhà phát triển không dám đảm bảo được 100% Durability. Nhưng đây lại là khía cạnh mà ít ai nhắc tới nó nhất và nghĩ rằng nó là điều hiển nhiên. Một số điều ta cần lưu ý:
- Nếu ổ cứng bị lỗi, mình có thể mất dữ liệu vĩnh viễn
- Lệnh fsync mà Database sử dụng để ghi xuống Disk có thể bị bug và mất dữ liệu
- Sử dụng asynchronous replicate tới remote slave database, vẫn có thể bị mất dữ liệu gần đây nếu master bị tèo.
Tại sao nhiều bọn NoSQL đều không hỗ trợ ACID
Thực tế, lập trình viên không phải là người quyết định ra tính năng nào được dùng và cần bỏ đi của sản phẩm, mà chính là người dùng sản phẩm đó. Cái gì được đón nhận nhiều thì giữ lại và cải tiến nó, cái gì không cần thiết thì bỏ đi. Database cũng vậy, và “người dùng” của nó chính là các lập trình viên.
Việc hỗ trợ ACID là hoàn toàn có thể triển khai được, kể cả với môi trường phân tán, tuy nhiên nó sẽ ảnh hưởng nhiều tới hiệu năng của Database. Trong khi đó, tính năng mà hầu hết các Database NoSQL đều đang quảng cáo, chạy marketing tới người dùng đó là “nhanh” và “dễ scale“. Người dùng sử dụng chúng vì nó nhanh, cho nên nhà phát triển sẵn sàng hi sinh tệp rất nhỏ người dùng yêu cầu tính năng ACID, để giữ chân lượng lớn tệp khách hàng trung thành với sản phẩm của mình.
Leave a Reply