Chapter 23 · Node Lifecycle: Bootstrap, Replace, Decommission, Remove, Rebuild, and Cleanup

Run cleanup After Topology Changes and Verify Ownership, Disk Use, and Replica Coverage

Finalize topology changes with cleanup, measure disk/compaction effects, verify ownership and replica coverage, and keep cleanup distinct from anti-entropy repair.

Intermediate → Advanced120–165 minutescleanup + lifecycle acceptance labApache Cassandra 5.0.9 · Java 17 · cqlsh/nodetool · isolated RF=3 lifecycle topology · UCSLast reviewed: September 2026

Learning outcomes

AtlasMart has successfully added capacity. The new node is healthy, but old nodes still report more disk usage than expected because Cassandra deliberately keeps data for ranges they used to own. Deleting SSTable files by hand would be unsafe. The supported finalization step is cleanup, performed only after ownership and replica coverage are accepted.

01

Explain why bootstrap/move/replace can leave obsolete range data on former owners by design.

02

Run cleanup only after the new topology is stable and observe its compaction/disk cost.

03

Compare disk use, ownership/endpoints, token metadata and representative reads before/after cleanup.

04

Distinguish cleanup from repair, tombstone garbage collection and generic major compaction.

05

Create an end-to-end topology acceptance checklist that bridges into Chapter 24 repair.

Chapter 23 lifecycle lab baseline

Topology changes are intentionally isolated from the shared course cluster. The mandatory labs use a disposable Docker network atlasmart-cassandra-life, cluster atlasmart-lifecycle, nodes atlasmart-life-1..4 (plus explicitly named replacement/cross-DC nodes where a lesson needs them), pinned Docker Official Image cassandra:5.0.9, Java 17 inside the image, dc1, racks rack1..rack3, and 16 virtual nodes (vnodes) per node. The keyspace atlasmart_lifecycle uses NetworkTopologyStrategy and replication factor (RF) 3 in dc1; normal verification uses LOCAL_QUORUM. New tables explicitly use UnifiedCompactionStrategy (UCS), no default time-to-live (TTL), and Cassandra's normal gc_grace_seconds. Authentication, client/internode Transport Layer Security (TLS), and remote Java Management Extensions (JMX) are disabled only on this isolated single-host learning network. The labs never expose JMX or native transport to an untrusted network. Exact IP addresses, host IDs, tokens, streaming sources, bytes, duration, ownership percentages, failure-detection timing, disk usage and p95/p99 application latency are learner-captured evidence. Docker examples are Bash-compatible; Windows Docker Desktop users can run the same docker commands individually in PowerShell if a shell loop is inconvenient.

Execution and safety note

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.

Terms and lifecycle mental model

A Cassandra node is one member of a peer-to-peer cluster. A datacenter (DC) and rack are logical topology labels used by replication placement to represent failure domains. A partition key is hashed by the partitioner to a token; with virtual nodes (vnodes), one physical node owns many token positions. A replica stores a copy of a token range according to the keyspace replication strategy. A coordinator is whichever node handles one request, not a permanent leader. A consistency level (CL) defines the replica acknowledgments/responses required for an operation.

A topology transition changes cluster membership or token ownership. Bootstrap is the join process in which a new node receives ranges by streaming from current replicas before becoming a normal owner. Pending ranges are ownership changes that are being prepared during a transition: Cassandra must keep writes safe while the future replica set is not yet fully ready. Streaming transfers SSTable data over the internode network. Decommission removes a healthy node and streams its ranges away. Replacement gives the logical ownership of a dead member to a fresh node identified by the dead endpoint. removenode removes an unreachable member from another live node and re-replicates from survivors. rebuild repopulates data on the current node by streaming from selected source nodes/DCs without changing that node's ownership. cleanup is a compaction-style rewrite that discards ranges a node no longer owns after a completed range movement. Repair is anti-entropy reconciliation between replicas; bootstrap/rebuild/cleanup do not make pre-existing replica inconsistencies disappear.

Node identity includes endpoint/broadcast address, host ID and token ownership recorded by cluster metadata. Headroom is spare disk, network, CPU, memory, compaction and replica availability capacity required to perform the transition without violating service objectives. A rollback/abort path is the documented action for a stalled or failed lifecycle sequence; it must be chosen from the current Cassandra version's supported topology state, not improvised by deleting system tables or reusing data directories.

1. Why Cassandra keeps old ranges

During a range movement Cassandra prioritizes availability and recoverability. Once node 4 bootstraps and assumes some replica ranges, the former owners do not immediately delete the SSTable sections for ranges they lost. Current topology guidance explicitly requires operators to run nodetool cleanup on nodes that lost ranges after the new node is known-good. Cleanup is implemented as compaction-style rewriting: SSTables containing mixed owned/unowned ranges may be rewritten so no-longer-owned keys can be discarded. That consumes disk I/O, CPU and temporary space.

Operation What it removes/changes What it does not prove
cleanup keys/ranges the local node no longer owns replica anti-entropy convergence
repair differences between replicas for selected ranges old unowned local files are reclaimed
normal compaction SSTable overlap/versions per compaction strategy topology ownership changed
garbagecollect/tombstone purge eligible deleted data under safety rules range ownership cleanup
rm SSTable files unsupported manual deletion anything safe—can cause data loss

2. Build the before-state: bootstrap node 4 and do not clean yet

Docker · create the isolated three-node RF=3 starting topology
# These names are dedicated to Chapter 23; the reset block never targets the shared course cluster.docker network inspect atlasmart-cassandra-life >/dev/null 2>&1 || docker network create atlasmart-cassandra-lifedocker volume create atlasmart-life-1-datadocker volume create atlasmart-life-2-datadocker volume create atlasmart-life-3-datadocker run -d --name atlasmart-life-1 --hostname atlasmart-life-1 --network atlasmart-cassandra-life \  -e CASSANDRA_CLUSTER_NAME=atlasmart-lifecycle -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack1 \  -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 \  -v atlasmart-life-1-data:/var/lib/cassandra cassandra:5.0.9# Wait until node 1 is UN before starting peers.docker exec atlasmart-life-1 nodetool statusdocker run -d --name atlasmart-life-2 --hostname atlasmart-life-2 --network atlasmart-cassandra-life \  -e CASSANDRA_CLUSTER_NAME=atlasmart-lifecycle -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack2 \  -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 \  -e CASSANDRA_SEEDS=atlasmart-life-1 -v atlasmart-life-2-data:/var/lib/cassandra cassandra:5.0.9docker run -d --name atlasmart-life-3 --hostname atlasmart-life-3 --network atlasmart-cassandra-life \  -e CASSANDRA_CLUSTER_NAME=atlasmart-lifecycle -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack3 \  -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 \  -e CASSANDRA_SEEDS=atlasmart-life-1 -v atlasmart-life-3-data:/var/lib/cassandra cassandra:5.0.9# Continue only after all three appear UN from at least two observers.docker exec atlasmart-life-1 nodetool statusdocker exec atlasmart-life-2 nodetool status
CQL · create a small deterministic AtlasMart ownership fixture
CREATE KEYSPACE IF NOT EXISTS atlasmart_lifecycleWITH replication = {'class':'NetworkTopologyStrategy','dc1':3};CREATE TABLE IF NOT EXISTS atlasmart_lifecycle.order_probe (  order_id text PRIMARY KEY,  customer_id text,  status text,  total decimal,  updated_at timestamp) WITH compaction = {'class':'UnifiedCompactionStrategy'};CONSISTENCY LOCAL_QUORUM;INSERT INTO atlasmart_lifecycle.order_probe (order_id,customer_id,status,total,updated_at)VALUES ('ord-1001','cust-42','PAID',129.90,'2026-09-08T06:00:00Z');INSERT INTO atlasmart_lifecycle.order_probe (order_id,customer_id,status,total,updated_at)VALUES ('ord-1002','cust-77','PACKING',89.50,'2026-09-08T06:01:00Z');INSERT INTO atlasmart_lifecycle.order_probe (order_id,customer_id,status,total,updated_at)VALUES ('ord-1003','cust-42','SHIPPED',42.00,'2026-09-08T06:02:00Z');SELECT * FROM atlasmart_lifecycle.order_probe WHERE order_id='ord-1001';
Docker · capture per-node disk and ownership before node 4
docker exec atlasmart-life-1 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-2 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-3 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-1 nodetool status atlasmart_lifecycledocker exec atlasmart-life-1 nodetool getendpoints atlasmart_lifecycle order_probe ord-1001
Docker · bootstrap node 4 into dc1/rack1
docker volume create atlasmart-life-4-datadocker run -d --name atlasmart-life-4 --hostname atlasmart-life-4 --network atlasmart-cassandra-life \  -e CASSANDRA_CLUSTER_NAME=atlasmart-lifecycle -e CASSANDRA_DC=dc1 -e CASSANDRA_RACK=rack1 \  -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_NUM_TOKENS=16 \  -e CASSANDRA_SEEDS=atlasmart-life-1 -v atlasmart-life-4-data:/var/lib/cassandra cassandra:5.0.9# Poll from separate terminals while the node is joining; a tiny dataset may finish too quickly to catch UJ.docker exec atlasmart-life-1 nodetool status atlasmart_lifecycledocker exec atlasmart-life-4 nodetool netstats -Hdocker exec atlasmart-life-4 nodetool bootstrap# Final acceptance requires node 4 to be UN and schema versions to agree.docker exec atlasmart-life-1 nodetool status atlasmart_lifecycledocker exec atlasmart-life-1 nodetool describecluster

Wait for node 4 to be UN, verify representative reads and let immediate streaming/compaction settle before cleanup. On a tiny fixture disk reduction may be too small to notice. That is expected; the lab teaches evidence and sequencing, not a guaranteed megabyte saving.

3. Capture old-owner disk state, then cleanup deliberately

Docker/nodetool · acceptance gate before reclaiming any range
docker exec atlasmart-life-1 nodetool status atlasmart_lifecycledocker exec atlasmart-life-2 nodetool status atlasmart_lifecycledocker exec atlasmart-life-1 nodetool checktokenmetadatadocker exec atlasmart-life-1 nodetool describeclusterdocker exec atlasmart-life-1 cqlsh -e "CONSISTENCY LOCAL_QUORUM; SELECT * FROM atlasmart_lifecycle.order_probe WHERE order_id='ord-1001';"docker exec atlasmart-life-4 cqlsh -e "CONSISTENCY LOCAL_QUORUM; SELECT * FROM atlasmart_lifecycle.order_probe WHERE order_id='ord-1001';"# Record resource state before cleanup.docker exec atlasmart-life-1 nodetool compactionstatsdocker stats --no-stream atlasmart-life-1 atlasmart-life-2 atlasmart-life-3 atlasmart-life-4
Docker/nodetool · cleanup former owners one at a time
# Run one node at a time so disk/compaction headroom is observable.docker exec atlasmart-life-1 nodetool cleanup -j 1 atlasmart_lifecycle order_probedocker exec atlasmart-life-1 nodetool compactionstatsdocker exec atlasmart-life-2 nodetool cleanup -j 1 atlasmart_lifecycle order_probedocker exec atlasmart-life-2 nodetool compactionstatsdocker exec atlasmart-life-3 nodetool cleanup -j 1 atlasmart_lifecycle order_probedocker exec atlasmart-life-3 nodetool compactionstats

It is safe for cleanup to do little on a node that did not lose relevant ranges. Do not force a large job count simply to make the command “finish faster”; parallel SSTable rewrites can steal disk headroom and latency from foreground requests. Current cleanup supports -j/--jobs; choose concurrency from measured hardware/workload, not a universal value.

4. Verify disk, ownership and replica coverage after cleanup

Docker/nodetool · compare before/after evidence
docker exec atlasmart-life-1 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-2 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-3 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-4 sh -lc 'du -sh /var/lib/cassandra/data/atlasmart_lifecycle* 2>/dev/null || true'docker exec atlasmart-life-1 nodetool status atlasmart_lifecycledocker exec atlasmart-life-1 nodetool describering atlasmart_lifecycledocker exec atlasmart-life-1 nodetool getendpoints atlasmart_lifecycle order_probe ord-1001docker exec atlasmart-life-1 nodetool checktokenmetadatadocker exec atlasmart-life-1 cqlsh -e "CONSISTENCY LOCAL_QUORUM; SELECT * FROM atlasmart_lifecycle.order_probe WHERE order_id='ord-1001';"
Wrong conclusion: “cleanup succeeded, therefore the cluster is consistent.”

Cleanup validates/reclaims local ownership state; it does not compare replicas with Merkle trees or stream anti-entropy differences. Chapter 24 repair remains required according to the repair cadence, outage/hint history and topology event. Likewise, a lower disk number does not prove application SLOs or backup recoverability.

5. End-to-end lifecycle acceptance contract

Gate Evidence Failure response
membership/topology status from multiple observers, DC/rack, checktokenmetadata stop next movement; resolve metadata/failure-domain issue
ownership/replicas describering/getendpoints for representative keys verify RF/NTS and complete range transition
streaming/resource netstats, compactionstats, disk/NIC/CPU/GC throttle/sequence; restore headroom
application SLO representative RF/CL reads/writes + p95/p99 rollback/stop rollout; diagnose coordinator/replica path
cleanup disk before/after, no unowned-range expectation run supported cleanup with safe concurrency
convergence repair plan/status and mismatch evidence Chapter 24 targeted/full/incremental repair as appropriate
recovery backup/restore assumptions still valid do not declare topology change complete

Check your understanding

  1. Why does Cassandra not automatically delete all old range data immediately after bootstrap?
  2. Why can cleanup need temporary disk and I/O even though its goal is to free disk?
  3. Should cleanup run before verifying the new node and replica coverage?
  4. Does cleanup replace repair?
  5. What closes a production topology change?
Review the answers

1. Retaining it is a safety/recoverability choice while ownership moves; cleanup is deliberately separated until the new topology is accepted.

2. SSTables may need compaction-style rewrites to separate owned from unowned ranges before obsolete data can be dropped.

3. No. First prove the new ownership is healthy; cleanup removes a fallback copy from former owners.

4. No. Cleanup removes locally unowned ranges; repair reconciles replicas for ranges that should exist.

5. Membership/ownership, resource and application SLO evidence, appropriate cleanup, repair/convergence plan, security/backup checks and a recorded rollback/incident trail—not merely one successful nodetool command.

Docker · reset only the dedicated Chapter 23 lifecycle lab
docker rm -f atlasmart-life-1 atlasmart-life-2 atlasmart-life-3 atlasmart-life-4 atlasmart-life-4r atlasmart-life-dc2-1 2>/dev/null || truedocker volume rm atlasmart-life-1-data atlasmart-life-2-data atlasmart-life-3-data atlasmart-life-4-data atlasmart-life-4r-data atlasmart-life-dc2-1-data 2>/dev/null || truedocker network rm atlasmart-cassandra-life 2>/dev/null || true

Production judgment

Topology work consumes the same resources that serve customer traffic. Before a bootstrap, decommission, replacement, removal or rebuild, record Cassandra/JDK/driver versions, DC/rack layout, RF and query CLs, vnode count, per-node used/free disk, compaction backlog, streaming throughput, NIC saturation, JVM/GC pressure, repair age, hint window, backup status, SAI/vector indexes, tenant/security constraints, driver timeouts/retries/idempotency and representative p50/p95/p99 latency. Confirm that losing one additional host/rack during the operation still leaves the required replicas and operational headroom. Avoid concurrent range movements in the same failure domain unless the current version and runbook explicitly prove safety.

Streaming moves bytes; it does not cure bad partition keys, oversized partitions, old replica divergence, poor compaction headroom or missing repair. Cleanup reclaims no-longer-owned ranges; it is not anti-entropy. Replacement preserves ownership identity but still requires post-replacement convergence when downtime/write-forwarding exceeds the mechanisms that could cover missed writes. Managed Cassandra services may hide or forbid these commands; use the provider's documented replacement/scale workflow but keep the same evidence and acceptance model. Chapter 24 now focuses on anti-entropy. After learning how membership and ownership move, you can reason precisely about why hints, read repair and topology streaming still leave a scheduled repair obligation.

Summary and next bridge

Cleanup is the final ownership-reclamation step after a range movement, not a substitute for repair. Chapter 23 has separated six lifecycle workflows—bootstrap, decommission, replace, remove, rebuild and cleanup—by membership state, streaming source and ownership effect. Chapter 24 now asks the complementary question: how do replicas that are supposed to own the same ranges prove and restore data convergence over time?

Authoritative references

Lifecycle commands are version-sensitive and state-sensitive. Re-check these sources, the release notes and your deployment's orchestration/managed-service rules before applying a topology procedure.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.