Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Cassandra Adding Nodes

Adding nodes (bootstrapping) expands cluster capacity by introducing new nodes that automatically receive a portion of existing data through streaming.


The following requirements must be met before adding a node:

RequirementVerificationRationale
All nodes should show UN statusnodetool statusBootstrap from degraded cluster increases risk; proceed with caution if necessary
No topology changes in progressnodetool netstatsOnly one topology change may occur at a time
No active repairsnodetool netstatsConcurrent operations cause unpredictable behavior
Schema agreementnodetool describeclusterSchema disagreement causes bootstrap failures
Terminal window
# Pre-flight verification
nodetool status # All nodes UN
nodetool describecluster # Single schema version
nodetool netstats # No active streaming
nodetool compactionstats # No heavy compaction
RequirementRationale
Same or better specs as existing nodesUniform performance
Sufficient disk for expected data shareNode receives 1/N of cluster data
Network connectivity to all existing nodesGossip and streaming
RequirementConsequence if Violated
Same Cassandra versionSchema conflicts, potential data corruption
Same JVM versionUndefined behavior
Same partitionerNode cannot join cluster
Compatible snitchTopology awareness failures
PortProtocolPurpose
7000TCPInternode communication (gossip, streaming)
7001TCPInternode communication (SSL, if enabled)
9042TCPCQL native transport
7199TCPJMX monitoring (optional)

  • New node receives data for its assigned token ranges from existing nodes
  • Existing nodes continue serving client requests during bootstrap
  • Data consistency is maintained (new node receives consistent replicas)
  • Bootstrap is resumable if interrupted (with data directory cleared)
ConfigurationBehavior
num_tokens set (vnodes)Tokens automatically assigned from random distribution
initial_token setExplicit token assignment (advanced)

Token Count

The num_tokens value should match existing nodes. Cassandra 4.0+ defaults to 16 tokens; earlier versions defaulted to 256.

ScenarioOutcomeRecovery
Bootstrap completesNode joins ring with full dataNone required
Bootstrap interruptedPartial data on new nodeClear data, restart
Source node fails during bootstrapStreaming stallsWait for recovery or restart bootstrap
Network partitionStreaming failsResolve network, restart bootstrap
Disk full on new nodeBootstrap failsFree space, clear data, restart

The following settings must be configured on the new node:

# Must match existing cluster exactly
cluster_name: 'ProductionCluster'
# Token configuration - must match existing nodes
num_tokens: 16 # Or 256 for older clusters
# Seed nodes - 2-3 existing stable nodes
# The new node must NOT be listed as a seed
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "10.0.1.1,10.0.1.2"
# This node's address - must be reachable by all other nodes
listen_address: 10.0.1.10
rpc_address: 10.0.1.10
# Must match cluster configuration
endpoint_snitch: GossipingPropertyFileSnitch
partitioner: org.apache.cassandra.dht.Murmur3Partitioner
# Enable bootstrap (default is true)
auto_bootstrap: true

Seed Configuration

The new node must not be listed in its own seed list. Seeds should be 2-3 existing, stable nodes.

For multi-datacenter deployments:

dc=dc1
rack=rack1

The datacenter and rack must match the intended topology placement.


On any existing node:

Terminal window
# All nodes must show UN
nodetool status
# Schema must be in agreement
nodetool describecluster
# No active streaming or repairs
nodetool netstats

Do Not Proceed If

  • Any node shows status other than UN
  • Schema versions disagree
  • Streaming or repair is in progress
Terminal window
# Install Cassandra (same version as cluster)
# Configure cassandra.yaml and cassandra-rackdc.properties
# Ensure data directories are empty
sudo rm -rf /var/lib/cassandra/data/*
sudo rm -rf /var/lib/cassandra/commitlog/*
sudo rm -rf /var/lib/cassandra/saved_caches/*
Terminal window
sudo systemctl start cassandra

The node begins bootstrap automatically:

  1. Contacts seed nodes to learn cluster topology
  2. Gossip propagates new node information to all nodes
  3. Existing nodes stream data to new node
  4. New node transitions from UJ (Joining) to UN (Normal)
Terminal window
# Watch node status (from any node)
watch -n 10 'nodetool status'
# Monitor streaming progress (on new node)
nodetool netstats
# Watch logs for progress and errors
tail -f /var/log/cassandra/system.log | grep -i "stream\|bootstrap"

Expected state transitions:

StateCodeDuration
JoiningUJUntil streaming completes
NormalUNBootstrap complete
Terminal window
# Node should show UN with data
nodetool status
# Verify token ownership
nodetool ring | grep <new_node_ip>
# No active streaming
nodetool netstats

After bootstrap completes, existing nodes retain data that moved to the new node. Cleanup must run on all existing nodes:

Terminal window
# On EACH existing node (not the new node)
# Run one node at a time
nodetool cleanup

See Cleanup Operations for detailed guidance.


Bootstrap duration depends on data volume and network throughput:

Data to Stream200 Mbps (default)400 Mbps
100 GB1-2 hours30-60 min
500 GB4-8 hours2-4 hours
1 TB8-16 hours4-8 hours
2 TB16-32 hours8-16 hours

Factors affecting duration:

  • Network bandwidth between nodes
  • Disk I/O throughput on source and target
  • Number of source nodes (more nodes = more parallel streams)
  • Stream throughput configuration
  • Cluster load during bootstrap

Default streaming throughput is 200 Mbps. To accelerate bootstrap:

Terminal window
# On existing nodes - increase outbound streaming
nodetool setstreamthroughput 400 # MB/s
# On new node - cassandra.yaml
stream_throughput_outbound_megabits_per_sec: 400

Client Impact

Higher streaming throughput increases network and I/O load, potentially impacting client request latency. Use aggressive settings only during maintenance windows.

# cassandra.yaml - stream entire SSTables (faster)
stream_entire_sstables: true

When using NetworkTopologyStrategy with multiple racks, nodes must be added evenly across racks to maintain balanced data distribution.

Cassandra places one replica per rack (when RF ≤ rack count). Uneven node distribution causes uneven load:

RF=3, 3 racks, uneven distribution:
Rack1: 3 nodes → each handles 1/3 of rack's replica load
Rack2: 2 nodes → each handles 1/2 of rack's replica load
Rack3: 1 node → handles 100% of rack's replica load ← OVERLOADED
Current StateCorrect AdditionIncorrect Addition
3 nodes (1 per rack)Add 3 (1 to each rack)Add 1 or 2
6 nodes (2 per rack)Add 3 (1 to each rack)Add 1 or 2
9 nodes (3 per rack)Add 3 (1 to each rack)Add 1 or 2

Formula: When adding nodes to a cluster with R racks, add in multiples of R to maintain balance.

Check current rack distribution:

Terminal window
nodetool status
# Example balanced output (2 per rack):
# Datacenter: dc1
# UN 10.0.1.1 100 GB rack1
# UN 10.0.1.2 100 GB rack1
# UN 10.0.1.3 100 GB rack2
# UN 10.0.1.4 100 GB rack2
# UN 10.0.1.5 100 GB rack3
# UN 10.0.1.6 100 GB rack3

Check load distribution after adding:

Terminal window
# Load should be roughly equal across all nodes
nodetool status | awk '/UN/ {print $3, $8}'

Imbalanced Clusters

If an imbalanced state already exists, adding nodes to underrepresented racks is acceptable to restore balance. The goal is equal nodes per rack.


Nodes must be added one at a time when using vnodes (default):

Terminal window
# 1. Add first node, wait for UN status
# 2. Add second node, wait for UN status
# 3. Continue for all nodes
# 4. Run cleanup on all original nodes

Wait times between additions:

Cluster SizeMinimum Wait
< 10 nodesUntil previous node shows UN
10-50 nodesUN + 1 hour stabilization
50+ nodesUN + 2-4 hours stabilization

Never Bootstrap Multiple Nodes Simultaneously

Concurrent bootstraps with vnodes cause token collisions and unpredictable data distribution. Add nodes strictly sequentially.

Multiple nodes may bootstrap concurrently only with manually assigned, non-overlapping tokens:

# cassandra.yaml - explicit token (disables vnodes)
num_tokens: 1
initial_token: <calculated_token>

This approach is complex and rarely necessary.


Symptoms: Node starts but doesn't appear in nodetool status

CauseDiagnosisSolution
Cluster name mismatchCheck cluster_name in yamlFix name, clear data, restart
Seeds unreachablenc -zv seed 7000Check firewall, network
Wrong listen_addressLog shows binding errorsFix address in yaml
Data directory not emptyCheck /var/lib/cassandra/dataClear data directories
Terminal window
# Check for errors
grep -i "error\|failed" /var/log/cassandra/system.log | tail -50

Symptoms: Node stuck in UJ state, streaming shows no progress

CauseDiagnosisSolution
Source nodes overloadedHigh CPU/IO on sourcesReduce stream throughput
Network issuesPacket loss, timeoutsFix network
Large partitionsTimeout errors in logsIncrease streaming_socket_timeout_in_ms
Disk fulldf -h on new nodeFree space
# cassandra.yaml - for large partition timeouts
streaming_socket_timeout_in_ms: 86400000 # 24 hours

Symptoms: Node crashed or stopped during bootstrap

Recovery:

Terminal window
# Clear partial data
sudo systemctl stop cassandra
sudo rm -rf /var/lib/cassandra/data/*
sudo rm -rf /var/lib/cassandra/commitlog/*
sudo rm -rf /var/lib/cassandra/saved_caches/*
# Restart bootstrap
sudo systemctl start cassandra

See Troubleshooting for additional diagnostics.


Cleanup must run on all existing nodes after bootstrap:

Terminal window
# On each existing node (one at a time)
nodetool cleanup
TaskAction
MonitoringAdd new node to monitoring systems
AlertingUpdate alert configurations
BackupsAdd to backup schedules
DocumentationUpdate cluster inventory

If the new node should be a seed (only if replacing an unreliable seed):

# On ALL nodes, update cassandra.yaml
seeds: "existing-seed1,existing-seed2,new-node"

Rolling restart required for seed list changes to take effect.

After cluster stabilizes:

Terminal window
# Repair the new node's token ranges
nodetool repair -pr