Implementing Linearizable Writes with Lightweight Transactions in Apache Cassandra
Guide to using Cassandra Lightweight Transactions for linearizable, compare‑and‑set writes, with steps, checks, and limits.
26 Sept 2025, 02:41 UTC

Desired Outcome
Perform a compare‑and‑set (CAS) write that guarantees linearizable consistency for a single row, using Apache Cassandra’s Lightweight Transactions (LWT) feature. The operation should either apply the change when a condition is met or leave the data unchanged, returning a clear indicator of success.
Prerequisites
- Apache Cassandra 3.0 or later (LWT was introduced in 2.0 and stabilized in 3.x).
- Access to a CQL shell (cqlsh) or a driver that can execute CQL statements.
- A keyspace and table defined with a primary key that identifies the row you intend to update.
- Sufficient permissions to INSERT/UPDATE and to read the system schema for monitoring.
- Understanding that LWT incurs higher latency due to the Paxos prepare/propose/commit phases.
Procedure
- Choose the consistency level for the transaction. LWT uses a separate
serial_consistencysetting that defaults toSERIAL(orLOCAL_SERIALfor multi‑datacenter clusters). You can override it per statement if needed. - Construct the CQL statement with the appropriate IF clause. Use
IF NOT EXISTSfor an insert‑only check orIF column = valuefor a compare‑and‑set update. - Execute the statement. Example using cqlsh:
cqlsh> INSERT INTO users (user_id, email, created_at)
VALUES (uuid(), '[contact removed]', toTimestamp(now()))
IF NOT EXISTS;
Replace users, column names, and values with your own schema. The uuid() function generates a new UUID for the primary key if you need a fresh row; for an update on an existing row, supply the existing key and use IF on a column.
- Inspect the result. The statement returns a result set that includes an
[applied]boolean column. A value oftruemeans the condition was satisfied and the write was committed;falsemeans the condition failed and no change was made. - Verify durability. After a successful LWT, you can read the row with a regular SELECT at any consistency level (e.g.,
QUORUM) to confirm the data is visible. - Monitor for contention. Under high concurrent CAS attempts on the same partition, watch for
WriteTimeoutExceptionin the logs or vianodetool tpstats:
nodetool tpstats
Look at the MutationStage and ReadStage metrics; an increase in pending tasks or a drop in completed Paxos operations signals contention.
Expected Checks
- First execution: The returned
[applied]column should betrue. A subsequent identical statement (same condition) should returnfalsebecause the condition is no longer satisfied. - Log inspection: No
WriteTimeoutExceptionentries for the LWT under low‑to‑moderate load. - Thread pool stats: Paxos-related stages (
PrepareStage,ProposeStage,CommitStage) show steady completion rates without growing queues. - Data verification: A
SELECT * FROM users WHERE user_id = ?;returns the inserted row with the expected values.
Recovery Options
Because an LWT that returns Note that compensatory actions also incur LWT overhead and should be used sparingly. To check whether your workload stays within safe limits, run a controlled test:false
DELETE or UPDATE using another LWT (e.g., IF email = '[contact removed]') to revert or correct the row.DELETE if you need to remove the row and accept the extra overhead.Limitations and Practical Verification
INSERT … IF NOT EXISTS on a fixed partition key at a configurable rate.[applied] = false (indicating contention).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.