Chapter 14 · Consistency Levels, Quorums, Availability, and Client Guarantees
Serial Consistency for LWT vs Regular Consistency for Data Operations
Separate Paxos serial consistency for LWT from ordinary data-operation consistency and test conditional contention.
Learning outcomes
AtlasMart must reserve a scarce product once. A normal
INSERT at LOCAL_QUORUM can be highly available, but
two concurrent writers can both decide the item is free. The
business invariant is compare-and-set, so Cassandra must run a
Lightweight Transaction (LWT) using Paxos.
Distinguish ordinary consistency from serial consistency in conditional CQL.
Explain SERIAL versus LOCAL_SERIAL as Paxos/serial-phase scope and regular CL as the learn/data phase.
Run IF NOT EXISTS concurrently and observe one applied result and one rejected condition.
Explain why LWT has higher latency and failure sensitivity than an ordinary mutation.
Choose LWT only when the business invariant requires linearizable compare-and-set semantics.
The mandatory single-DC labs use Apache Cassandra
5.0.9 in the pinned Docker image
cassandra:5.0.9, Java 17 inside the image,
cluster atlasmart-course, network
atlasmart-cassandra, nodes
atlasmart-cass-1..3, datacenter dc1,
racks rack1..rack3, 16 virtual nodes per node,
NetworkTopologyStrategy, replication factor (RF)
3, and explicit per-request consistency levels (CLs). New
tables use UnifiedCompactionStrategy (UCS), no default Time To
Live (TTL), and the Cassandra default
gc_grace_seconds unless a lesson states
otherwise. Authentication, client Transport Layer Security
(TLS), internode TLS, and remote Java Management Extensions
(JMX) are disabled only inside the isolated local learning
network. The optional application example uses Apache
Cassandra Java Driver 4.19.3. Windows learners
should use Docker Desktop/WSL-style Linux containers; commands
run inside containers unless labeled host-side.
docker network inspect atlasmart-cassandra >/dev/null 2>&1 || docker network create atlasmart-cassandradocker volume create atlasmart-cass-1-datadocker volume create atlasmart-cass-2-datadocker volume create atlasmart-cass-3-datadocker inspect atlasmart-cass-1 >/dev/null 2>&1 || docker run -d --name atlasmart-cass-1 --hostname atlasmart-cass-1 --network atlasmart-cassandra -e CASSANDRA_CLUSTER_NAME=atlasmart-course -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack1 -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 -v atlasmart-cass-1-data:/var/lib/cassandra cassandra:5.0.9# Wait until node 1 reports UN before starting peers.docker exec atlasmart-cass-1 nodetool statusdocker inspect atlasmart-cass-2 >/dev/null 2>&1 || docker run -d --name atlasmart-cass-2 --hostname atlasmart-cass-2 --network atlasmart-cassandra -e CASSANDRA_CLUSTER_NAME=atlasmart-course -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack2 -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 -e CASSANDRA_SEEDS=atlasmart-cass-1 -v atlasmart-cass-2-data:/var/lib/cassandra cassandra:5.0.9docker inspect atlasmart-cass-3 >/dev/null 2>&1 || docker run -d --name atlasmart-cass-3 --hostname atlasmart-cass-3 --network atlasmart-cassandra -e CASSANDRA_CLUSTER_NAME=atlasmart-course -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack3 -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 -e CASSANDRA_SEEDS=atlasmart-cass-1 -v atlasmart-cass-3-data:/var/lib/cassandra cassandra:5.0.9# Continue only after all three nodes are UN.docker exec atlasmart-cass-1 nodetool statusdocker exec atlasmart-cass-1 nodetool versiondocker exec atlasmart-cass-1 java -versiondocker exec atlasmart-cass-1 cqlsh -e "SHOW VERSION"
CREATE KEYSPACE IF NOT EXISTS atlasmart_consistencyWITH replication = {'class':'NetworkTopologyStrategy','dc1':3};CREATE TABLE IF NOT EXISTS atlasmart_consistency.order_status_by_id ( order_id text PRIMARY KEY, status text, version int, updated_at timestamp) WITH compaction = {'class':'UnifiedCompactionStrategy'};CREATE TABLE IF NOT EXISTS atlasmart_consistency.inventory_reservation_by_product ( product_id text, reservation_id text, customer_id text, state text, created_at timestamp, PRIMARY KEY (product_id, reservation_id)) WITH compaction = {'class':'UnifiedCompactionStrategy'};CONSISTENCY LOCAL_QUORUM;INSERT INTO atlasmart_consistency.order_status_by_id(order_id,status,version,updated_at)VALUES ('order-42','PAID',1,toTimestamp(now()));DESCRIBE KEYSPACE atlasmart_consistency;
Run commands only against the disposable Apache Cassandra course lab or another explicitly approved non-production environment. Confirm node, keyspace, table, container, volume, path, and datacenter targets before destructive, failure-injection, cleanup, repair, restore, security, or topology operations. Capture current state and expected rollback/recovery evidence first; output and timings can differ by host, operating system, Java runtime, Docker/runtime, driver, and Cassandra configuration.
Core terms used throughout this chapter
Replication factor (RF) is the number of
replicas Cassandra is configured to keep for each partition in a
datacenter. A replica stores a copy of a
partition; the coordinator is the node handling
one client request and is not a permanent leader. A
consistency level (CL) is the per-request rule
that says how many and which replicas must acknowledge a write
or satisfy a read before the coordinator can return success. A
datacenter (DC) is Cassandra's logical
locality/failure-domain grouping; a rack is a
smaller placement grouping within a DC. A
quorum is a majority, calculated as
floor(RF/2)+1 for the relevant replica scope.
CQL means Cassandra Query Language;
cqlsh is its shell. A
Lightweight Transaction (LWT) is a conditional
CQL operation using Paxos consensus; it has a serial phase and a
regular learn/data phase. Availability here
means whether enough replicas are alive/responding for the
requested CL—not whether the cluster has any node alive.
Staleness means a read can return an older
replica version because the requested read CL did not
necessarily intersect the replicas that acknowledged a prior
write.
1. LWT has two consistency dimensions
A conditional statement such as
INSERT ... IF NOT EXISTS is not an ordinary
last-write-wins mutation. Cassandra uses Paxos to establish a
single linearizable order for competing conditional operations.
Serial consistency controls the Paxos/serial
phase: SERIAL spans the relevant replicas globally,
while LOCAL_SERIAL limits the serial quorum to the
local DC. The normal consistency setting still controls the
learn/data phase and what normal reads are guaranteed to observe
immediately after a successful LWT.
| Setting | Used for | Typical choice in local-DC service | What it does not mean |
|---|---|---|---|
SERIAL CONSISTENCY LOCAL_SERIAL |
Paxos phase of IF conditions | serial quorum in local DC | not the same as regular LOCAL_QUORUM |
CONSISTENCY LOCAL_QUORUM |
learn/data phase and ordinary operations | local majority | does not make a non-conditional write an LWT |
SERIAL |
global serial phase | use only if invariant scope requires it | not a general read/write CL shortcut |
LOCAL_SERIAL |
DC-local serial phase | reduces cross-DC dependency | does not isolate tenants or authorize callers |
2. Run a conditional reservation
CONSISTENCY LOCAL_QUORUM;SERIAL CONSISTENCY LOCAL_SERIAL;INSERT INTO atlasmart_consistency.inventory_reservation_by_product(product_id,reservation_id,customer_id,state,created_at)VALUES ('sku-9','slot-1','customer-A','HELD',toTimestamp(now()))IF NOT EXISTS;SELECT * FROM atlasmart_consistency.inventory_reservation_by_productWHERE product_id='sku-9' AND reservation_id='slot-1';
The expected first result contains
[applied] = True. A competing conditional insert
for the same primary key should return
[applied] = False and expose the current values,
rather than silently overwriting them.
CONSISTENCY LOCAL_QUORUM;SERIAL CONSISTENCY LOCAL_SERIAL;INSERT INTO atlasmart_consistency.inventory_reservation_by_product(product_id,reservation_id,customer_id,state,created_at)VALUES ('sku-9','slot-1','customer-B','HELD',toTimestamp(now()))IF NOT EXISTS;
3. Make concurrency visible
Open two terminals and execute the two conditional inserts as close together as possible after deleting the probe row. Exactly one should win the condition. The exact ordering, trace messages, and latency are nondeterministic. Enable tracing for one run to see the extra Paxos work, but do not treat one localhost timing as an LWT performance benchmark.
CONSISTENCY LOCAL_QUORUM;DELETE FROM atlasmart_consistency.inventory_reservation_by_productWHERE product_id='sku-9' AND reservation_id='slot-1';SERIAL CONSISTENCY LOCAL_SERIAL;TRACING ON;INSERT INTO atlasmart_consistency.inventory_reservation_by_product(product_id,reservation_id,customer_id,state,created_at)VALUES ('sku-9','slot-1','customer-A','HELD',toTimestamp(now()))IF NOT EXISTS;TRACING OFF;
LWT adds consensus rounds, coordination state, and tail-latency/failure sensitivity. It is appropriate for invariants such as uniqueness, compare-and-set, or guarded state transitions—not as a blanket replacement for ordinary mutations. Model most Cassandra data for idempotent, partition-local writes and reserve LWT for the small subset that truly needs linearizable conditional semantics.
4. What regular reads see after LWT
The cqlsh documentation distinguishes the serial phase from the
normal learn phase. A successful conditional write with regular
LOCAL_QUORUM means a subsequent read at an
appropriate intersecting regular CL can observe the learned
value. A serial read
(SERIAL/LOCAL_SERIAL) is a separate,
more expensive mechanism intended to read the current Paxos
state consistently. Do not set SERIAL as a general-purpose
default for ordinary SELECTs.
CONSISTENCY LOCAL_QUORUM;SELECT * FROM atlasmart_consistency.inventory_reservation_by_productWHERE product_id='sku-9' AND reservation_id='slot-1';-- Serial reads are specialized; use only when the invariant needs them.CONSISTENCY LOCAL_SERIAL;SELECT * FROM atlasmart_consistency.inventory_reservation_by_productWHERE product_id='sku-9' AND reservation_id='slot-1';CONSISTENCY LOCAL_QUORUM;
Check your understanding
- What phase does LOCAL_SERIAL control for an IF statement?
- What does regular LOCAL_QUORUM control on a successful LWT?
- Why can two ordinary LOCAL_QUORUM writes both violate a uniqueness decision?
- What should two competing IF NOT EXISTS inserts show?
- Should SERIAL be the default SELECT consistency?
Review the answers
1. The Paxos/serial phase of the lightweight transaction.
2. The normal learn/data phase and ordinary request consistency, separate from the serial phase.
3. Quorum acknowledgment alone is not compare-and-set consensus; concurrent writers can both issue valid ordinary mutations.
4. Exactly one condition should apply; the loser receives applied=false with the current state.
5. No. Serial reads are specialized and more expensive; ordinary reads should use a regular CL derived from their invariant.
Production judgment
Choose consistency from a business invariant, topology, RF, and failure budget—not from a cluster-wide slogan. Record which reads must observe which writes, whether the invariant is local to one DC or global, whether conditional uniqueness/compare-and-set is required, and what latency/availability degradation is acceptable when replicas or a whole DC are unavailable. Then test that contract with the real driver, routing policy, request timeout, retry/speculative-execution policy, idempotency classification, and representative network latency.
Consistency level does not replace durable commit-log/storage
design, repair, backup/restore, security isolation,
schema/partition design, compaction/tombstone management, or
application-level idempotency. ALL is not
“permanent durability”; LOCAL_ONE is not tenant
isolation; a timeout is not proof that a write failed; and a
successful weak write does not promise a subsequent weak read
will be fresh. Storage-Attached Indexing (SAI) or vector search
can add read work but do not redefine RF/CL arithmetic. Managed
Cassandra services may restrict topology visibility or CL
choices; verify provider semantics rather than assuming Apache
Cassandra behavior is exposed unchanged. Lesson 5 turns these
mechanisms into an application consistency matrix and shows how
to encode different regular/serial consistency per query in the
Java driver.
Summary and next bridge
Regular CL and serial CL solve different problems. Ordinary mutations use replica acknowledgments; conditional LWT operations add Paxos and a serial consistency scope. Next, map those choices to concrete AtlasMart business invariants rather than one inherited default.
Authoritative references
Re-check these version-sensitive sources when regenerating this course.
- Apache Cassandra 5.0 downloads and Java Driver releases
- Dynamo architecture and tunable consistency semantics
- cqlsh CONSISTENCY and SERIAL CONSISTENCY commands
- Native protocol consistency-level codes
- Cassandra guarantees and LWT linearizable consistency
- Hints and eventual convergence
- Apache Cassandra Java Driver 4.19 consistency API
- Java Driver statement consistency attributes