The road to ACID transactions in Cassandra 6

eatonphil1 pts0 comments

The road to ACID transactions in Cassandra 6 - The Consensus

The Consensus Weekly<br>Get new deep dives, plus jobs and funding in software infrastructure, free in your inbox every week.Join the WeeklyWant a peek? Check out the archives.cassandra<br>The road to ACID transactions in Cassandra 6<br>Atomic batches in 2013, single-partition Paxos compare-and-swap later that year, and now strictly serializable cross-partition transactions with Accord in unreleased Cassandra 6. We explore each on a three-node cluster with an accounting workload.By Phil EatonAugust 16, 2026 Focus

You are getting early access to this article as a subscriber. Your support makes articles like this possible. Thank you.Cassandra is a compelling data system. It is one of extremely few vendor-neutral, open-source databases supporting a SQL-like query language with builtin sharding and builtin replication. A desirable combination. And a reason Cassandra has so many (large) users including Apple, eBay, Bloomberg, and Netflix.Cassandra has evolved significantly since its first release. From an eventually consistent data model without transactions and a schemaless, NoSQL interface over Thrift to where (in the upcoming 6.0 release) it stands as an ACID transactional SQL-like database (granted: severe SQL limitations, transactions are non-interactive, we’ll get to that later).Meanwhile the lack of joins plus automatic sharding (and a limited secondary index story) means a key characteristic has stayed the same: you model tables based on queries. And as a result your application might end up denormalizing, turning a single write into multiple writes in order to position the database to efficiently answer different queries later on.In this article we’ll set up a three-node Cassandra cluster on one machine, running the cassandra-6.0 branch (a pre-release state) to test out some transactional workloads across four of Cassandra’s transactional options: none (the default), BATCH updates, Lightweight transaction (LWT) updates, and Accord (i.e. ACID) updates. Accord transactions will become available only when Cassandra 6 is released (perhaps later this year), which is why we are using the pre-release branch.Setting up a cluster#<br>Install Java 21 and the ant build system, and gcc and Go for our concurrent test runner Monastery.sudo apt-get install -y openjdk-21-jdk ant gcc golang<br>git clone https://github.com/theconsensuslabs/monastery<br>cd monastery<br>CGO_ENABLED=1 go build -buildmode=plugin -o cql.so ./plugins/cql<br>CGO_ENABLED=1 go build -o monastery .

Then grab and build Cassandra.git clone https://github.com/apache/cassandra<br>cd cassandra<br>git checkout cassandra-6.0<br>ant artifacts -Dcheck.skip=true -Dant.gen-doc.skip=true -Dno-javadoc=true

Set up directories and configuration for three nodes, giving them unique IP addresses and JMX ports.for i in 1 2 3; do<br>n=node$i<br># run `killall java` first and then this will clean up the data directories for clean re-runs.<br>rm -rf /etc/cassandra/$n /var/log/cassandra/$n /var/lib/cassandra<br>mkdir -p /etc/cassandra/$n /var/log/cassandra/$n<br>cp -r ~/cassandra/conf/* /etc/cassandra/$n/

echo "<br>cassandra_storagedir=\"/var/lib/cassandra/$n\"<br>JVM_OPTS=\"\$JVM_OPTS -Dcassandra.jmx.local.port=7${i}99\"" >> /etc/cassandra/$n/cassandra-env.sh

echo "<br>cluster_name: 'theconsensus-lab'<br>listen_address: 127.0.0.$i<br>rpc_address: 127.0.0.$i<br>seed_provider:<br>- class_name: org.apache.cassandra.locator.SimpleSeedProvider<br>parameters:<br>- seeds: "127.0.0.1:7000"<br>accord:<br>enabled: true" >> /etc/cassandra/$n/cassandra.yaml

# Set up max memory usage.<br>echo "<br>-Xms4G<br>-Xmx4G" >> /etc/cassandra/$n/jvm-server.options<br>done

Now start up the three nodes one at a time. (-R allows us to run as root.)CASSANDRA_CONF=/etc/cassandra/node1 CASSANDRA_LOG_DIR=/var/log/cassandra/node1 /root/cassandra/bin/cassandra -R >> /var/log/cassandra/node1/console.log 2>&1

Wait for the node to come up (you’ll get connection refused errors for a few seconds until the node comes fully up). Eventually you’ll see this:$ /root/cassandra/bin/nodetool -p 7199 status<br>Datacenter: datacenter1<br>Status=Up/Down<br>|/ State=Normal/Leaving/Joining/Moving<br>-- Address Load Tokens Owns (effective) Host ID Rack<br>UN 127.0.0.1 72.73 KiB 16 100.0% 6d194555-f6eb-41d0-c000-000000000001 rack1

Where “UN” means “Up” and “Normal”.Now let’s add node2.CASSANDRA_CONF=/etc/cassandra/node2 CASSANDRA_LOG_DIR=/var/log/cassandra/node2 /root/cassandra/bin/cassandra -R >> /var/log/cassandra/node2/console.log 2>&1

And once it’s up, nodetool status will eventually look like this.$ /root/cassandra/bin/nodetool -p 7299 status<br>Datacenter: datacenter1<br>Status=Up/Down<br>|/ State=Normal/Leaving/Joining/Moving<br>-- Address Load Tokens Owns (effective) Host ID Rack<br>UN 127.0.0.1 74.46 KiB 16 100.0% 6d194555-f6eb-41d0-c000-000000000001 rack1<br>UN 127.0.0.2 79.89 KiB 16 100.0% 6d194555-f6eb-41d0-c000-000000000002 rack1

Now start the final node.CASSANDRA_CONF=/etc/cassandra/node3 CASSANDRA_LOG_DIR=/var/log/cassandra/node3...

cassandra transactions node acid root status

Related Articles