Database Transaction and ACID Revisit
Traditional DBMS processing is build among transactions. Transaction is a crucial and useful abstraction provided by DBMS to model communication procedure. Database users depend on standard sets of properties that guarantee database transactions are processed reliably. These standard properties is a widely used acronym as ACID, which stands for Atomicity, Consistency, Isolation and Durability. Inspired by Martin Kleppmann’s book “Designing Data-Intensive Application”, I want to share some of my thoughts on transaction and ACID properties.
A transaction is a coherent and reliable unit of work performed on a database and should be independent of other transactions. The purpose of transaction abstraction is to deal with two problems
- To provide a reliable way to recover from error and keep system integrity in case of system fault.
- To provide isolation among programmers accessing database concurrently. Without the isolation, concurrency usually cause erroneous, sometimes indeterministic outcome.
A transaction is only a logic abstraction, but it can be made up by multiple operations. For example, in MySQL system, we can use
BEGIN/END to compound multiple statements into a single commit. If there are multiple operations within one transaction, they must be executed or cancelled together. In a database system, a transaction should be executed in an atomic, consistent, isolated and durable manner.
Atomicity is designed for error handling purpose. Atomicity guarantees that one transaction can be fully committed, aborted or roll backed. In other words, the process of a transaction can not be partially accomplished. Additionally, atomicity also make sure that system can roll back a transaction without side-effect, which can be considered as abortability. If the execution of a transaction has some side effect, such as sending external request to downstream application and cannot be reverted, the transaction is not considered as atomic since it does not guarantee abortability.
In the context of ACID, consistency makes sure that a transaction can only bring database from one valid state to another, maintaining database invariant.The legitimacy of data is usually not a database concern, which is usually defined by the application logic. In other words, consistency should be considered as a handy feature offered by some databases rather than a hard requirement for database transaction.
For example, when people create their user profile on a social network, they usually need to choose a user name that is not be used by others. The uniqueness of the user name is not a concern for the database, which is necessary for the social network application.
In fact, there are quite a few common use cases, such as uniquenss, anti-orphan data etc, among database users. Therefore, database provides some tools, such as primary key, foreign keys etc to enforce some constrains on transactions. Consistency feature therefore free users from low level integrity check.
The isolation property guarantees that the processing of a transaction will not be interrupted by other transactions. With strong isolation level, every transaction can consider itself as the only one in the system. In other words, each transaction is independent and even invisible to others. If there are multiple transactions running concurrently, database system should handle it as they are running sequentially. This isolation level is called as serializability, which is usually considered as the strongest isolation level. However, serializability comes with expensive performance penalty, therefore some system also provides weak isolation level to achieve better performance. Some weak isolation levels are read committed, snapshot isolation.
To design a proper isolation level and handle concurrency is one of the most complicated challenge for database design especially for distributed database with multi-leader or leaderless architecture. Most database builds their solution based on two phase locking(2PL). In the design of 2PL, there are 2 kinds of locks, shared locks for read operation and exclusive locks for write operations. A operation must acquire the lock for the object before process the transaction. Depending on the access operation type, acquiring the lock may be blocked and postponed, if another transaction is holding a lock for that object.
The durability means committed transactions will survive permanently. We can consider it as a guarantee against fault tolerance. We can consider it from two perspective. From hardware perspective, it usually means the the transaction has been stored on a persistent storage, such hard disk. On the other hand, people looks at the durability problem from a system perspective and claim the transaction is durable if it is properly replicated.
There are pros and cons for either solution. For examples, the annual failure rate for hard disk drive (HDD) is around 1% while 20% of SSD suffers various reliability issues over a four year period. Therefore, it is possible for a system to lose some transactions data due to hardware failure. On the other hand, during network partition, the replicated data may be inaccessible as well. In reality, system architecture usually combines both solutions to achieve SLA for durability.
Let us review these concepts through a real life example. In a banking application, a common use case is fund transfer. Assuming Bob wants to transfer $100 from his checking account to his saving account. Before the transfer, there are $500 balance in his checking account and $300 in saving account. After he issues the fund transfer in the portal, there is a transaction issue to underlying database. There is a fund subtraction from checking account and a fund addition to the saving account.
Two operations must be either succeed or failed together. Otherwise, there may be some fund missing. This is guaranteed by atomicity. In any time during the transaction, there are $800 total fund belong to Bob. This is guaranteed by consistency. If during the transaction is being executed, Bob is checking his balance of two accounts. He can see either $500/$300 or $400/$400 since the transfer operation is not independent and will not be interrupted by the balance checking operation. This is guaranteed by isolation. After the transaction is committed, there will be $400/$400 balance in Bob’s two account accordingly before other transactions committed. System fault will not roll it back. This is called Durability.
Some banking system sends email or SMS notification after the transaction committed. However, we cannot consider the notification as part of the transactions since
- The execution is not in the context of database and therefore it is not the semantic of database transaction.
- Even we extent the transaction to overall banking system, the SMS and notification can not be retracted easily. Therefore it breaks the abortability.
What is next
This wraps up our initial discussion about ACID. Since 2000s, large scale distributed database gains more popularity among the industry. It is not easy to achieve ACID with performance in consideration. Therefore some relaxed alternatives have been proposed. In the next article, we will discuss some other popular concepts in the distributed data system community.
- Designing Data-Intensive Application Martin Kleppmann’s, O’Relly, 2017