Cassandra lightweight transactions

We all know that Cassandra is a distributed database. However there’re situations where one needs to perform an atomic operation and for such cases a consensus must be reached between all the replicas.

For instance when dealing with payments we might require that we only insert the row once.

CQL provides an easy to use IF syntax to deal with such cases.

INSERT INTO payments (payment_time, customer_id, amount) 
VALUES (2016-11-02 12:23:34Z, 123, 12.00) 

Note: You can also use IF EXISTS or any other IF <CONDITION>.

UPDATE payments SET amount = 10.00 
WHERE payment_date = 2016-11-02 12:23:34Z 
AND customer_id = 123 
IF amount = 12.00

This simple IF NOT EXISTS isn’t free. Under the hood it triggers  a lightweight transaction (also known as CAS for Compare And Set).

It’s called lightweight because it doesn’t imply locking as it’s the case in traditional (SQL) databases.

Lightweight doesn’t mean free either. In fact such queries require a read and a write and they also need to reach consensus  among all the replicas.

Underlying principle

In Cassandra the consensus is reached by implementing the Paxos algorithm (that we’ve already discussed previously).

The messages exchanged during a Cassandra lightweight transactions.
The messages exchanged during a Cassandra lightweight transactions.

The leader role is not a master role (any node can act as a leader or more accurately as a proposer).

Briefly the proposer picks a proposal number and sends it to the participating replicas. (Remember the number of replicas is determined by the keyset’s replication factor). If the proposal number is the highest the replica has seen, the replica promises to not accept any earlier proposal (i.e. a proposal with a smaller number).

If the majority promises to accept the proposal, the leader may proceed with its proposal. However if a replica replies with another value for that proposal it’s the value the leader must propose.

This gives the linearisable or serial property because if a leader interrupts an on-going proposal it must complete it before proposing its own value.

Cassandra uses Paxos to implement a Compare-And-Set operation so it needs to intertwin read and writes into the Paxos protocol.

Consistency levels

Now that we have a clear picture in mind of what’s happening during a lightweight transaction (LWT) let’s discuss the consistency levels.

As there is a read and a write phase involved in the transaction we need 2 consistency levels.

Serial consistency levels

The read consistency is called the serial consistency and is set using the SERIAL CONSISTENCY command. It can take only 2 values:


The only difference is when Cassandra uses several datacenters. LOCAL_SERIAL runs Paxos only in the local datacenter whereas SERIAL runs it accross all datacenters.

The SERIAL CONSISTENCY command is only available for conditional updates (UPDATE or INSERT with the IF statement).

Write consistency

Then the write phase uses the regular CONSISTENCY command. It default to ONE but can be set to any of the write consistency levels.

Read consistency

The last thing is if we want to consider any on-going lightweight transactions when reading a value. In this case we want to read the value of any on-going transaction.

This can be done by setting the read consistency level to SERIAL. This is the regular consistency level, the one set with the CONSISTENCY command (not the serial consistency) and it applies to read queries only (i.e. SELECT statements).