Skip to main content

Rob Pankow Rob Pankow

ClickHouse on Kubernetes: Storage Architecture for Analytics and Observability Workloads

Jul 29, 2026  |  8 min read

ClickHouse on Kubernetes: Storage Architecture for Analytics and Observability Workloads

The Milvus storage guide covers the retrieval-time storage pattern for vector search, and the etcd storage guide covers the control-plane database underneath Kubernetes itself. ClickHouse sits in a third, increasingly common spot in the same stack: the columnar analytics and observability backend that ingests logs, metrics, and event data at high volume and answers aggregate queries over it in milliseconds. That ingest-and-merge pattern has its own storage requirements, and a generic Kubernetes StorageClass does not meet them by default.

ClickHouse’s MergeTree family of table engines never updates a row in place. Every insert lands as a new, immutable data part on disk. A background merge process continuously combines smaller parts into larger ones, rewriting data that was already written minutes or hours earlier so that read queries touch fewer, larger files. That background merge activity is not an edge case: it is the mechanism that keeps ClickHouse fast, and it runs constantly on any table taking a steady stream of inserts.

Why ClickHouse’s MergeTree Engine Breaks Generic Kubernetes Storage

A MergeTree table’s I/O has two distinct phases, and they compete for the same volume on most Kubernetes deployments:

Part writes happen on every insert batch. ClickHouse’s own documentation recommends batching inserts (thousands of rows per batch, not one row at a time) precisely because each insert creates a new part, and too many small parts overwhelm the merge scheduler. Even batched, a busy ingestion pipeline is writing new parts continuously.

Background merges read multiple existing parts, combine them, and write a new, larger part, then delete the originals. This is large sequential I/O, but it happens on the same disk that is simultaneously serving part writes and read queries. On a generic Kubernetes persistent volume sized for steady-state capacity rather than burst throughput, a merge storm competing with pod-local write traffic on the same node is a common cause of query latency spikes that have nothing to do with query complexity.

This is the same class of problem covered in the log-structured merge tree pattern used by RocksDB and other LSM-based engines: write amplification from compaction is a structural cost of the design, not a misconfiguration, and the storage layer underneath has to absorb it without stealing I/O from the read path.

ClickHouse Storage Tiers: Matching I/O Patterns to Backends

The table below maps ClickHouse’s storage tiers to the backend each one actually needs, using a representative high-ingest observability workload as the reference point.

ClickHouse storage tierI/O patternLatency sensitivityBest-fit backend
Active part writesSmall-to-medium sequential writes, continuousHigh, gates insert acknowledgmentDisaggregated NVMe/TCP or NVMe/RoCE block storage
Background mergesLarge sequential read + write, burstyMedium, but contends with writes and reads if slowSame NVMe/TCP tier, sized for burst throughput
Hot query working setRandom reads across recent partsHigh, gates query response timeSame tier, ideally with a page cache large enough to avoid most disk reads
Cold historical parts (tiered storage)Large sequential reads, infrequentLowS3-compatible object storage, via ClickHouse’s native tiered-storage policies

Table 1: ClickHouse storage tier characteristics and the backend each tier fits best.

ClickHouse’s own tiered-storage feature already assumes this split: it moves cold parts to object storage on a policy while keeping hot parts on local or block storage. The gap most teams hit on Kubernetes is not the cold tier, which ClickHouse handles natively. It is provisioning the hot tier, the one absorbing continuous part writes and merge bursts, on storage that is sized and provisioned like ordinary capacity rather than like a throughput-bound workload.

A slow merge tier turns into slow inserts and slow queries at the same time. Talk to a storage architect about sizing an NVMe/TCP tier for ClickHouse’s active parts and merge bursts, separate from your cold object-storage tier. Talk to a storage architect

How Disaggregated NVMe/TCP Absorbs Merge-Driven I/O Bursts

Running ClickHouse’s data nodes with persistent volumes backed by disaggregated NVMe/TCP (or NVMe/RoCE on RDMA-capable fabrics) addresses the two problems a single generic volume leaves open:

Merge bursts do not steal I/O from the query path. Because the hot-tier volume sits on a shared NVMe fabric rather than a single node’s local disk, the sustained throughput available to background merges is not capped by whatever spare bandwidth exists on one node alongside every other pod scheduled there. A merge storm on one ClickHouse shard does not degrade query latency on a neighboring shard sharing the same physical node.

Node failures become volume reattachments, not full replica rebuilds. ClickHouse typically relies on ReplicatedMergeTree and a coordination layer (ClickHouse Keeper or ZooKeeper) to keep replicas consistent; a lost replica normally means streaming a full copy of that shard’s data from a healthy replica. When the underlying volume lives on the storage fabric instead of node-local disk, a rescheduled pod reattaches the same PVC and resumes from where it left off, without the full-replica data transfer.

How ClickHouse's part-write, merge, and query tiers map onto a disaggregated NVMe/TCP layer ahead of S3-compatible cold storage
Figure 1: ClickHouse's storage tiers (left), the NVMe/TCP layer serving the two latency-sensitive tiers (center), and the query-latency and recovery outcome (right).

ClickHouse deployments also inherit the same snapshot-based backup pattern already covered for CSI snapshot architecture: a VolumeSnapshot of the active-parts volume gives a point-in-time, storage-side capture of a table’s current data parts, restorable in seconds, as a complement to ClickHouse’s own BACKUP command, which typically streams data through an object-storage destination and takes longer as table size grows. For teams running ClickHouse across multiple environments, a VolumeSnapshotClass per cluster tier (frequent snapshots for actively-ingesting production tables, longer-retention snapshots for stable analytical tables) mirrors the pattern already in production for the Milvus and CockroachDB deployments covered elsewhere in this series.

Simplyblock’s own ClickBench benchmark results already show the throughput gain this hot tier delivers under ClickHouse’s own industry-standard benchmark suite. Simplyblock licenses per usable storage TB per year, with no per-core fee, so a cluster that scales data nodes horizontally to absorb higher ingest volume does not pay more for the storage tier unless the actual volume of hot-tier data grows. The architecture works the same way whether ClickHouse runs hyperconverged, with storage and compute on the same nodes, or disaggregated, with a dedicated storage fabric behind the data nodes, on vSphere, bare-metal Kubernetes, or OpenShift.

Questions and Answers

Why does ClickHouse need a dedicated hot storage tier instead of one generic volume for everything? ClickHouse’s MergeTree engine writes new immutable parts on every insert and continuously merges them in the background, generating sustained sequential write and read traffic on top of whatever read traffic query workloads add. A single generic Kubernetes persistent volume sized for capacity rather than throughput lets merge activity compete with query reads for the same disk, which shows up as query latency spikes unrelated to query complexity.

What happens when a ClickHouse replica is lost on generic Kubernetes storage? ClickHouse’s ReplicatedMergeTree engine normally recovers a lost replica by streaming a full copy of that shard’s data from a healthy replica, which can take a long time for large tables. A persistent volume claim backed by simplyblock’s NVMe/TCP storage reattaches to a rescheduled pod in seconds instead, avoiding the full-replica data transfer in most node-failure scenarios.

Can ClickHouse’s built-in tiered storage replace a dedicated NVMe/TCP tier? ClickHouse’s native tiered-storage policies correctly move cold, infrequently-queried parts to S3-compatible object storage, and that part of the architecture does not need to change. The gap is the hot tier: active part writes, merge bursts, and recently-queried parts still need low-latency block storage, which tiered storage assumes exists but does not provide on its own.

How does simplyblock fit into a ClickHouse deployment on Kubernetes? Simplyblock provides NVMe/TCP (or NVMe/RoCE) block storage as persistent volumes for ClickHouse’s data nodes, sized for the continuous part-write and merge-burst I/O that generic Kubernetes storage classes are not built to absorb. Simplyblock’s CSI driver adds fast, storage-side snapshots for table-level backup and rollback, and the same architecture supports both hyperconverged and disaggregated deployment models.

How should I size storage for ClickHouse on Kubernetes? Size the NVMe/TCP hot tier for the working set of actively-written parts plus enough burst throughput headroom for background merges at peak ingest rate, and let ClickHouse’s own tiered-storage policy move cold, historical parts to S3-compatible object storage. Simplyblock’s pricing is per usable TB per year with no per-core fee, so scaling the data-node fleet horizontally for higher ingest volume is a compute decision, not an automatic storage cost increase.

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.