Skip to main content

Rob Pankow Rob Pankow

Cassandra on Kubernetes: Persistent Storage Architecture and High Availability

Jul 15, 2026  |  12 min read

Last edited: Jul 20, 2026

Cassandra on Kubernetes: Persistent Storage Architecture and High Availability

Apache Cassandra is a wide-column, peer-to-peer distributed database built for write-heavy workloads that cannot tolerate a single point of failure. Running it on Kubernetes alongside other stateful workloads is now common practice, but Cassandra’s storage engine has requirements that most CSI drivers were not designed around. Every node writes to a commit log for durability and flushes in-memory tables to immutable SSTables on disk, and both paths compete for the same volume unless the platform separates them deliberately.

The bigger operational cost shows up when a node fails. On local storage, a failed Cassandra pod cannot simply reschedule with its data intact: the standard recovery path is nodetool replace, which bootstraps a replacement node by streaming its full share of the data from other replicas across the network. For a multi-terabyte node, that stream can take hours, during which the cluster runs with reduced replication and elevated read/write latency on the nodes serving the stream.

This guide covers the persistent volume architecture for Cassandra on Kubernetes, configuration for the two most common operators, and how disaggregated storage changes the node-failure recovery model from a multi-hour data stream to a volume reattachment.

Why Cassandra Storage Is Different on Kubernetes

Apache Cassandra uses a log-structured merge-tree (LSM-tree) storage engine, and that design drives two distinct, concurrent I/O patterns on every node:

  1. Commit log writes. Every write is appended to the commit log before it is acknowledged, giving Cassandra durability independent of when the corresponding memtable flushes to disk. Commit log writes are small, sequential, and latency-sensitive: a slow commit log volume directly increases write-path latency for every client request.

  2. Memtable flush and compaction. When a memtable fills, Cassandra flushes it to an immutable SSTable file on disk. A background compaction process continuously merges SSTables to remove overwritten and deleted data (tombstones) and keep read amplification under control. Compaction is throughput-heavy and bursty, and it reads and writes the same data directory that client reads query.

Cassandra’s own documentation recommends placing the commit log and the data directories on separate devices specifically to prevent compaction I/O from adding latency to commit log fsyncs. On a single shared Kubernetes persistent volume, a heavy compaction cycle can stall commit log writes and produce write-latency spikes that look like a database problem but are actually a storage contention problem.

The second Kubernetes-specific issue is node replacement. Cassandra’s own replication (via NetworkTopologyStrategy and a configurable replication factor) is what makes the cluster durable, not the underlying block storage. When a node’s local disk is lost, or when a pod on hostPath or local-PV storage cannot reschedule because its data lives on one specific machine, the standard repair path is to bootstrap a brand-new node and stream its full data range from the remaining replicas. That stream is proportional to the amount of data owned by the failed node, not the length of the outage.

Persistent Volume Architecture for Cassandra StatefulSets

Cassandra runs on Kubernetes as a StatefulSet (directly, or through an operator that manages one), with each pod requesting a PersistentVolumeClaim through volumeClaimTemplates. Each node owns its own data and commit log files; nothing is shared between pods at the storage layer, only at the Cassandra replication layer.

Storage AttributeRecommended ValueReason
Volume modeFilesystemCassandra manages SSTables and commit log segments as regular files
Access modeReadWriteOnceOne Cassandra node per volume; no shared-volume access pattern
Volume bindingWaitForFirstConsumerEnsures the volume provisions in the same zone/rack as the scheduled pod
Reclaim policyRetainPrevents data loss if a pod or StatefulSet is deleted accidentally
Allow expansiontrueSupports online growth as keyspace data size increases
IOPS target15,000–40,000 IOPSConcurrent commit log fsyncs, memtable flush, and compaction read/write

Table 1: Persistent volume configuration recommendations for Cassandra on Kubernetes.

A StorageClass for Cassandra using the simplyblock CSI driver:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: cassandra-nvme
provisioner: csi.simplyblock.io
parameters:
replication: "2"
compression: "false"
qos_iops_per_gb: "40"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

compression is left off at the storage-class level because Cassandra already compresses SSTables per-table (typically with LZ4). The qos_iops_per_gb limit exists to keep one node’s compaction burst from consuming bandwidth that a neighboring node’s commit log needs on the same shared NVMe pool.

For clusters that need I/O isolation between the commit log and data paths, provision two volumes per pod, one per volumeClaimTemplates entry, and mount them at /var/lib/cassandra/commitlog and /var/lib/cassandra/data respectively. This mirrors Cassandra’s own bare-metal recommendation and, on a disaggregated NVMe pool, each volume is still an independent namespace with its own QoS ceiling rather than a physically separate disk.

Running Cassandra on Kubernetes and dreading the multi-hour rebuild after a node failure? Simplyblock’s disaggregated NVMe/TCP storage lets a replacement Cassandra pod reattach its predecessor’s volume in seconds, skipping the full-stream bootstrap entirely. Talk to a storage architect

Configuring Cassandra Operators for Persistent Storage

Two operator projects dominate production Cassandra-on-Kubernetes deployments: DataStax’s cass-operator, and K8ssandra, which packages cass-operator together with Reaper (repair scheduling), Medusa (backup/restore), and Stargate (data API access).

cass-operator (CassandraDatacenter CRD)

Storage is configured under spec.storageConfig.cassandraDataVolumeClaimSpec on the CassandraDatacenter custom resource. Racks map to Kubernetes topology, and each rack should span a distinct failure domain:

apiVersion: cassandra.datastax.com/v1beta1
kind: CassandraDatacenter
metadata:
name: dc1
spec:
clusterName: cassandra-cluster
serverType: cassandra
serverVersion: "4.1.5"
size: 3
racks:
- name: rack1
- name: rack2
- name: rack3
storageConfig:
cassandraDataVolumeClaimSpec:
accessModes:
- ReadWriteOnce
storageClassName: cassandra-nvme
resources:
requests:
storage: 500Gi

cass-operator generates the underlying StatefulSet per rack and handles rolling restarts one rack at a time so that at most one replica of any token range is briefly unavailable at once.

K8ssandra Operator

K8ssandra Operator wraps the same CassandraDatacenter storage configuration inside a higher-level K8ssandraCluster resource, and adds Reaper for continuous repair scheduling and Medusa for CSI-snapshot-backed backup and restore:

apiVersion: k8ssandra.io/v1alpha1
kind: K8ssandraCluster
metadata:
name: cassandra-cluster
spec:
cassandra:
serverVersion: "4.1.5"
datacenters:
- metadata:
name: dc1
size: 3
storageConfig:
cassandraDataVolumeClaimSpec:
storageClassName: cassandra-nvme
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 500Gi
racks:
- name: rack1
- name: rack2
- name: rack3

K8ssandra’s built-in Reaper integration matters for the storage discussion because scheduled repair reads generate the same kind of throughput-heavy, bursty I/O as compaction. Per-volume QoS limits on the underlying StorageClass keep repair from starving client-facing read latency on the same node.

OperatorStorage Config FieldRepair SchedulingBackup Integration
cass-operatorspec.storageConfig.cassandraDataVolumeClaimSpecManual (nodetool repair / cron)Manual snapshot commands
K8ssandra Operatorspec.cassandra.datacenters[].storageConfigReaper (automated, incremental)Medusa (CSI-snapshot-backed)
Plain StatefulSetvolumeClaimTemplatesManualManual

Table 2: Cassandra operator storage and operations comparison on Kubernetes.

Diagram showing a Cassandra pod's commit log and data volumes attached from a simplyblock NVMe/TCP pool, with an arrow showing the pod and its existing volumes rescheduling to a new node instead of streaming a full replica rebuild
Figure 1: A Cassandra node's commit log and data volumes attach from a disaggregated NVMe/TCP pool. On node failure, the same volumes reattach to a replacement pod instead of triggering a full-stream rebuild.

High Availability: Replication Factor, Consistency, and Node Recovery

Cassandra’s availability model is independent of the underlying storage layer: it comes from NetworkTopologyStrategy, a per-datacenter replication factor (RF), and the consistency level chosen per query. A common production configuration is RF=3 with LOCAL_QUORUM reads and writes, which tolerates one node being unavailable per datacenter while every request still reaches a quorum of replicas.

What the storage layer does control is how quickly an unavailable node returns to full standing, and that difference is largest at node failure, not during normal operation:

  • Local NVMe (hostPath or local PV): When the node’s disk is lost, or the pod cannot reschedule because it is bound to that specific machine, an operator runs nodetool replace on a new pod. The replacement streams its full token range from the remaining replicas across the network. For a multi-terabyte node this can take hours, during which the cluster serves reads and writes at RF-1 for the affected range and the replicas doing the streaming carry extra I/O load.

  • Cloud block storage (gp3, Premium SSD): The pod can reschedule and reattach its existing volume, avoiding a full stream, but only within the same availability zone. In a multi-AZ node pool, a pod that reschedules to a different zone than its volume fails to attach, forcing the full-stream path anyway. Reattachment that does succeed still adds 20 to 60 seconds of pod-startup latency.

  • Disaggregated NVMe/TCP (simplyblock): The replacement pod reattaches the failed node’s existing data and commit log volumes on any node in the cluster within seconds, with the SSTables and commit log segments intact. Cassandra replays any hints held by other nodes (hinted handoff) and the node participates in the next scheduled repair to reconcile any writes it missed during the outage, but it skips the full-stream bootstrap entirely.

Storage ModelNode Failure RecoveryCluster ImpactPod Scheduling
Local NVMe (hostPath / local PV)Full-stream rebuild via nodetool replace; hours for large nodesCluster serves at RF-1 for the affected range; streaming replicas absorb extra I/OPod pinned to the node holding the disk
Cloud block storage (gp3, Premium SSD)Reattach in 20–60 s if same-zone; full stream if cross-zoneBrief unavailability on successful reattach; full RF-1 window on cross-AZ failureZone-bound; cross-AZ reattach fails
Disaggregated NVMe/TCP (simplyblock)Volume reattaches to new pod in seconds, data intactHinted handoff replay closes the gap; typically minutes, no full streamAny node in the cluster, no zone constraint

Table 3: Cassandra node-failure recovery comparison by storage model.

Rack awareness compounds this. Cassandra distributes replicas across racks so that a single rack failure never takes an entire token range’s replica set offline. On Kubernetes, racks are typically mapped to node pools or availability zones via the operator’s racks field. Pairing that rack topology with storage that is not bound to any single node means a rack-wide maintenance event drains and reschedules pods without triggering a wave of full-stream rebuilds across the cluster.

Snapshot-based backup benefits from the same underlying capability. Simplyblock’s CSI external snapshotter integration, which Medusa can call into for K8ssandra clusters, takes consistent point-in-time snapshots of a node’s data volume without pausing writes, and restoring from a snapshot brings a node back to a known-good state far faster than a full repair-based rebuild for large datasets.

For teams that have followed the CSI driver discussion earlier in this series, Cassandra is the clearest case where a storage-layer capability, volume reattachment independent of node identity, eliminates an entire class of database-level recovery work. See also the earlier entries covering MySQL, MongoDB, Redis, and Kafka on Kubernetes.

Questions and Answers

What persistent storage settings work best for Cassandra on Kubernetes?

Use volumeBindingMode: WaitForFirstConsumer so the volume provisions in the same zone and rack as the scheduled pod, reclaimPolicy: Retain to prevent data loss on accidental PVC deletion, and allowVolumeExpansion: true for online capacity growth. Plan for 15,000 to 40,000 IOPS per node depending on write throughput, replication factor, and compaction strategy. If the commit log and data directories share a volume, size IOPS headroom for both paths; if you split them into two PVCs, configure QoS separately so compaction bursts on the data volume cannot starve commit log fsyncs.

How does Cassandra’s replication factor interact with Kubernetes persistent volumes?

Cassandra replication happens at the cluster layer through NetworkTopologyStrategy and a configured replication factor, entirely independent of how each node’s own data is stored. Each node’s PVC holds only that node’s local share of the data. When a node fails and its pod reschedules, the CSI driver reattaches the existing PVC (with SSTables and commit log intact) to the new pod, and Cassandra’s own hinted handoff and repair mechanisms reconcile any writes made during the outage. The PVC provides durability for one node’s local copy; Cassandra’s replication provides durability across the cluster.

Does NVMe/TCP storage avoid the full-stream node replacement in Cassandra?

Yes, in the common case. nodetool replace full-stream rebuilds are needed when a node’s data is genuinely lost or unreachable. With disaggregated NVMe/TCP storage, a failed pod’s existing data and commit log volumes reattach to a replacement pod on any node in the cluster, so the data is not lost or unreachable, it is just temporarily unavailable while the pod restarts. The node rejoins after replaying hints and participating in scheduled repair, which is materially faster than streaming its full token range from other replicas.

How does simplyblock compare to local NVMe for Cassandra on Kubernetes?

Local NVMe gives the lowest absolute commit log latency, at the cost of binding every pod to a specific machine. Simplyblock’s disaggregated NVMe/TCP storage delivers throughput comparable to local NVMe for the commit log and compaction I/O patterns, typically in the 100 to 400 microsecond latency range on 25 GbE fabric, while allowing pods to reschedule freely, applying per-volume QoS to isolate compaction and repair from commit log writes, and supporting CSI snapshots for fast backup and restore. For teams running cass-operator or K8ssandra in production, the reduced node-replacement time and rack-maintenance flexibility offset the small latency delta for most workloads.

Does this architecture work with K8ssandra’s Reaper and Medusa components?

Yes. Reaper’s scheduled repair reads generate throughput-heavy I/O similar to compaction, and per-volume QoS on the StorageClass keeps that traffic from degrading client-facing read latency on the same node. Medusa’s backup and restore workflow can call into simplyblock’s CSI external snapshotter for consistent, non-blocking point-in-time snapshots of each node’s data volume, which restores faster than a repair-based rebuild for large keyspaces.

You may also like:

NVMe/TCP vs NVMe/RoCE for Kubernetes Storage: Choosing the Right Fabric
NVMe/TCP vs NVMe/RoCE for Kubernetes Storage: Choosing the Right Fabric

NVMe over Fabrics gives Kubernetes clusters low-latency block storage over the network. The transport you pick, TCP or RoCE, determines your latency floor, infrastructure cost, and operational complexity. Here is how to choose.

We Break Our Storage So You Never Have To
We Break Our Storage So You Never Have To

Simplyblock runs 100+ hours of automated chaos engineering before every release: real NVMe hardware, real FIO workloads, four failure types injected under live load. This is what we test, why it is necessary, and what it means for your infrastructure.

NVMe Storage Cost Optimization in 2026: Erasure Coding, Thin Provisioning, and Compute Efficiency
NVMe Storage Cost Optimization in 2026: Erasure Coding, Thin Provisioning, and Compute Efficiency

NVMe drives deliver the performance Kubernetes stateful workloads need, but triple replication and thick provisioning multiply their cost fast. Here is a practical breakdown of erasure coding economics, thin provisioning, and how sub-millisecond latency reduces compute waste.