Do we take Transactions for granted?

Transaction are often something we take for granted as developers, when we decide what applications we want to build. The mechanism of a transaction is important to understand, as we also need to know when it is appropriate to use them!

In this blog post I will summarise transactions and the different vectors we should consider, I plan to make some further posts on the different areas on this, similar to my series on partitioning and replication.

Okay lets begin…

In some of the literature out there, it is argued that the generalist two phase commit is too expensive to support, because of the performance or the availability problems it incurs.

How do we handle performance?

It is recommended for the application programmers to deal with performance problems, as stated by James C. Corbett in “Spanner: Google’s Globally-Distributed Database” and also his co authors explains:

  • Due to the over use of transactions as bottlenecks arises
  • Rather than always coding around the lack of transactions

What can go wrong with data systems?

The tricky reality of data systems is that many things can go wrong… 😵‍💫

For example:

  • The database software may fail at anytime
  • the database hardware may also fail at anytime
  • Including in the middle of a write operation
  • The application may crash at any time, including half way through a series of operations
  • Interruptions in the network could unexpectedly cut off the application from the database
    • Or one database node to another
    • Several clients may write to the same database at the same time
      • Therefore, overwriting each others changes
    • A client may read data that does not make sense because it has only partially been updated!
    • Or race condition between clients may cause surprising bugs!

In order to be reliable, a system has to deal with these faults, to avoid any catastrophic failures. However, implementing a fault tolerance mechanism is a lot of effort. It requires:

  • Extensive thinking about all the scenarios that could go wrong
  • A lot of testing to ensure the solution actually works

Transactions the solution?

For decades transactions have been the mechanism of choice for simplifying these issues! A transaction is the ability for an application to group several reads and writes together into a logical unit.

  • Conceptually, all the reads and writes in a transaction are executed as one operation
  • Either the entire transaction succeeds – known as a commit
  • Or fails – known as an abort or rollback

If it fails an application can safely retry. ✅

Error handling and transactions?

With transactions error handling becomes much simpler for an application. Because it does not need to worry about partial failures. The case where some operations succeed and some fail for whatever reason.

Let be real transactions are taken for granted

If you have spent years working with transaction they may seem obvious. But really we should not take them for granted, transaction are not a law of nature, they were created with a purpose!

Mainly to simplify the programming model for applications accessing the database. By utilising transactions the application is free to ignore certain potential error scenarios and concurrency issues. Because the database takes care of them instead.

We call these Safety guarantees.

Transaction are not need for all applications

Not every application requires transactions.

And sometimes there are advantages to weakening transactional guarantees or abandoning them entirely. For example:

  • To achieve higher availability
  • Or higher performance

Some safety properties can be achieved without transactions…

How do you know when you need transactions?

In order to answer this question we first need to understand:

  • Exactly what safety guarantees transactions can be provided
  • What costs are associated with them

Final note

Although transactions seem straight forward at first glance, there are actually many subtle and important details that come into play.

In the upcoming blog posts we will be exploring the algorithms the databases use to guard against these issues. This will go especially into areas of concurrency control; discussing various types of race conditions that could occur, and how database implements isolations levels. These include:

  • Read commited
  • Snapshot isolation
  • Serialisability

The context of these transactions will both apply to single node and distributed databases. In the next post we will be discussing the particular challenges that only arise in distributed systems. Thanks for reading.

Leave a comment