swecrets

Replication: The Replicated* Engines

Judgment — Rung 422 min read

Learning Objectives

  • Evaluate whether a table's durability and availability requirements justify the operational cost of running ReplicatedMergeTree and the Keeper cluster it depends on
  • Choose between single-node ClickHouse with backups, self-hosted ReplicatedMergeTree, and managed/cloud replication, defending the choice against each alternative's real strengths
  • Explain how ClickHouse's replication actually behaves — asynchronous multi-master writes, automatic insert deduplication, independently-performed merges — well enough to reason about replication lag instead of assuming instant consistency
  • Distinguish "replication protects against node failure" from "replication protects against bad data," and explain why a replica faithfully replicates mistakes too

Why This Matters

Every MergeTree table you've built in this course so far has lived on one node. That's fine right up until the node it lives on has a bad night — a failed disk, an OOM-killed process, a bad ALTER that corrupts state — and the answer to "where's our data now" turns out to be "gone, or unreachable until someone restores from backup." The instinctive fix is "add replication." That instinct is right often enough to be dangerous, because ReplicatedMergeTree isn't a checkbox — it's a second distributed system (ClickHouse Keeper) that your ClickHouse cluster now depends on for every write, a new axis of behavior (replication lag) you now have to reason about on every query, and a new category of 3am pages (a degraded Keeper quorum, a "lost" replica) that a single-node setup never had. Teams that reach for it reflexively, for tables that never needed it, spend real engineering time operating infrastructure that was protecting against a risk that a nightly backup already covered. This lesson is about the judgment call underneath the reflex: what replication actually buys you, what it actually costs, and how to tell whether a specific table's risk profile is worth that trade.

The trade-off

A single ClickHouse node is a single point of failure. Its disk fails, or someone runs a destructive ALTER against it, or the box itself dies, and every table on it is unavailable — or, without a separate backup, gone. ReplicatedMergeTree trades that fragility for durability (the data exists in more than one place) and availability (a query can still be served if one replica is down) — in exchange for running more infrastructure: multiple ClickHouse nodes to hold the replicas, and a ClickHouse Keeper cluster to coordinate them. Replication works at the level of an individual table, not the entire server — you opt specific tables in by choosing a Replicated* engine, not by flipping a cluster-wide switch.

That infrastructure cost comes with two things worth being explicit about before going further, because both get glossed over by "just replicate it" advice:

Replication is not backup. A replica faithfully copies whatever happens to the table — including a bad DROP TABLE, an accidental TRUNCATE, or a mutation that corrupts data. If what you're actually worried about is operator or application error rather than hardware failure, more replicas don't help; you need backups, ideally ones with some retention or immutability, kept separately from every replica.

Replication is asynchronous by default, which means "we have replicas" does not mean "every replica is always in sync." There is a real, if usually small, window where a replica is behind. Whether that window is a non-issue or a correctness bug depends entirely on what the workload needs — the same "what staleness can this query tolerate" question from the ReplacingMergeTree lesson, one layer further down the stack.

The alternatives, steelmanned

Single-node ClickHouse with backups (BACKUP/RESTORE, or scheduled snapshots to object storage). The case for it: this is dramatically simpler to operate. No Keeper cluster to run, patch, and monitor; no replication lag to reason about on any query; roughly half (or less) the storage and compute cost of running live standby replicas nobody is querying most of the time. For workloads where the business impact of "unavailable for the time it takes to restore from last night's backup" rounds to zero — an internal reporting table refreshed hourly by batch ETL, a dev or staging environment, anything genuinely tolerant of an occasional multi-hour gap — this is not a lesser choice made under budget pressure. It's the correctly-sized one. Paying continuously for live replica infrastructure to protect against a risk a nightly backup already absorbs is real, ongoing cost for a problem that doesn't exist for that specific table.

Managed or cloud-provided replication. The case for it: you get the durability and availability outcome without personally operating the coordination system underneath it. ClickHouse Cloud is the concrete example — it doesn't run classic ReplicatedMergeTree under the hood at all. It uses SharedMergeTree, described as "a cloud-native replacement of the ReplicatedMergeTree engines that is optimized to work on top of shared storage," where, unlike ReplicatedMergeTree, replicas "[don't] require... to communicate with each other" directly — "all communication happens through shared storage and clickhouse-keeper" — and "for an end-user, nothing needs to be changed to start using the SharedMergeTree engine family." In other words: you still write CREATE TABLE statements that look like the ones in this lesson, but the vendor absorbs the job of running and monitoring the coordination layer. This is the right call for a team that wants the outcome (durable, available data) without the ops capacity — or the appetite — to run a Keeper cluster themselves. The cost is real too: vendor lock-in, less control over exact replica topology, and an ongoing subscription cost that, at large enough scale, can exceed the cost of infrastructure you'd run yourself.

Self-hosted ReplicatedMergeTree — the subject of this lesson. The case for it: full control over topology and infrastructure, works anywhere you can run ClickHouse (your own cloud VMs, on-prem, wherever), and it composes directly with sharding — the Distributed table engine covered in Module 6 — if you also need to scale writes and storage horizontally, not just tolerate a node failure. The cost you pay is in infrastructure and ongoing ops attention rather than vendor margin: running a Keeper cluster, monitoring replica health, and building the team's fluency in a new class of failure mode. It's the right choice when the durability/availability need is real, you're already running (or are willing to run and staff) multi-node infrastructure, and the team has — or is deliberately building — the operational capability a coordination system demands.

How replication actually works

You need enough of the mechanism to reason about the trade-off, not to operate a cluster blind.

A ReplicatedMergeTree table takes two extra parameters beyond a plain MergeTree: zoo_path, "the path to the table in ClickHouse Keeper," and replica_name, "the replica name in ClickHouse Keeper." In practice these are almost always templated with {shard} and {replica} macros defined per-server, so the identical CREATE TABLE statement runs unmodified on every node:

A replicated table, using per-server macros for the Keeper path and replica namesql
CREATE TABLE events
(
    event_time DateTime,
    event_type LowCardinality(String),
    user_id    UInt64
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}')
ORDER BY (event_type, event_time);

Replication is asynchronous and multi-master: any replica can accept an INSERT. Data is written to the replica that received the insert first, then copied to the other replicas, with latency roughly equal to the time it takes to transfer that block of compressed data over the network. By default, an INSERT only waits for confirmation from one replica before returning success to the client; the insert_quorum setting trades insert latency for a stronger guarantee — waiting for confirmation from multiple replicas before acknowledging the write. That default is exactly why "we added replication" doesn't mean "every replica is always caught up" — there's a real window, usually small, where a replica hasn't yet received the latest inserts.

Replication also gives you automatic insert deduplication: identical data blocks written more than once are only stored once. That makes retrying a failed or ambiguous INSERT safe by default — a client that isn't sure whether its write succeeded can just retry it, without a separate idempotency layer. It's a narrower, automatic version of the "upstream deduplication" alternative from the ReplacingMergeTree lesson — it protects against network-level retries, not against your application inserting the same logical row twice for unrelated reasons.

One detail worth being precise about, because it's easy to assume the opposite: by default, merges are not performed once and shipped to other replicas. "Only the source data to insert is transferred over the network. Further data transformation (merging) is coordinated and performed on all the replicas in the same way." Each replica redoes the same merge independently, driven by the same coordinated instructions — so the CPU cost of merging is paid on every replica by default, not once, which is part of the real compute cost you're signing up for, not just the storage cost of extra copies. That default isn't absolute: ClickHouse also has settings — prefer_fetch_merged_part_size_threshold/prefer_fetch_merged_part_time_threshold, and execute_merges_on_single_replica_time_threshold, which lets "only a single replica start[] the merge immediately, and other replicas wait... to download the result instead of doing merges locally" — that let a replica fetch an already-merged part from another replica instead, specifically to speed up very large or slow merges. The default behavior is still the one to plan capacity around; the fetch-instead settings are an escape hatch for expensive merges, not the norm.

ClickHouse Keeper is what makes all of this coordinated rather than chaotic. It stores replica metadata and the shared log of "what should exist" — not a copy of your column data — and it's involved in inserts, ALTERs, and failure recovery, but "ZooKeeper is not used in SELECT queries." A struggling Keeper cluster can stall writes and coordination without necessarily stalling reads already in flight. Keeper itself is a small ClickHouse-native reimplementation of ZooKeeper's coordination protocol, built on RAFT — a consensus algorithm that lets a cluster of nodes agree on shared state even when some of them are unreachable, by requiring any change to be accepted by a majority before it counts. Keeper is compatible with the ZooKeeper client protocol, and like any RAFT-based system it needs its own majority — a quorum — to keep working: a 3-node Keeper cluster tolerates one node crashing. Run Keeper on a single node and you haven't removed your single point of failure — you've relocated it, from "the ClickHouse node" to "the Keeper node," and now a coordination-layer failure can stall every replicated table on the cluster at once, not just the data on one box.

Replica health itself is something you check, not something you assume — system.replicas reports whether a replica is in read-only mode, whether its Keeper session has expired, and how many parts have been permanently lost across the table's history. Reading that table fluently as a diagnostic tool is Module 7 territory; for now, the thing worth knowing is that "is our replication healthy" is a question with a concrete, queryable answer, not a guess.

Decision framework

The reasoning a senior engineer runs through, in order:

  1. What does downtime or data loss on this specific table actually cost? If the honest answer rounds to zero — an internal dashboard refreshed hourly, a table nobody queries outside business hours — single-node plus backups is the correctly-sized answer, not a corner cut.
  2. If durability or availability genuinely matters, can it be bought from a managed vendor for less than the cost of operating it yourself? A team without dedicated infrastructure or on-call capacity for a coordination system very often comes out ahead paying a vendor to run one, even at a real dollar premium.
  3. If self-hosting, are you already running multiple ClickHouse nodes for another reason — sharding for write or storage scale? If so, the marginal cost of also replicating is much lower: you already carry the multi-node operational surface, and adding Keeper coordination on top of infrastructure you're already staffing is a smaller step than standing up a coordination system from a single node.
  4. Do you need protection against a node dying, or protection against bad data? These are different failure classes with different fixes. Replication addresses the first. Only backups — kept separately, ideally with some retention or immutability — address the second, and you need them regardless of what you decide about replication.
  5. If replicating, does this workload need insert_quorum's stronger guarantee, or is the default asynchronous, eventually-caught-up replica tolerable? The same staleness-tolerance question that drove the ReplacingMergeTree decision framework, applied one layer down: a dashboard that can be a few seconds behind on one replica is a very different case from a query that must never read stale data no matter which replica serves it.

Cold Start — No AI

You're the on-call engineer for a single ClickHouse node backing a customer-facing "usage this month" page, checked by a few thousand paying customers, mostly during business hours. At 2am, the node's disk failed. The page was down until someone manually located the previous night's BACKUP in S3 and restored it — a process that took until 9am. No data was permanently lost; the table is loaded fresh every night from a batch job anyway, so the restored backup was, at most, one day stale. Now your VP, having heard "we were down for seven hours," is asking why the team doesn't have replication, and is ready to approve budget for two more nodes plus a Keeper cluster.

Before reading further or asking an AI assistant anything, work through this yourself: would replication actually have prevented the pain in this specific incident? What would it have changed about the 2am failure? What is the real, ongoing cost — infrastructure spend and ops attention — of running it? Is there a cheaper fix that addresses what actually went wrong?

Reflection: What would a generic AI answer to "how do I make ClickHouse highly available" likely say? Would it default to "add ReplicatedMergeTree" without asking what specifically went wrong at 2am? The failure here arguably wasn't "we lack a live standby" — it was "restoring from a known-good backup is a slow, manual process." A generic prompt tends to name the HA feature and stop there; the judgment call this lesson is about is noticing that the seven-hour number measures a process gap, and permanent live infrastructure is one fix for that, but not the only one, and possibly not the cheapest.

Reasoning Prompt

A four-person engineering team, with no dedicated infrastructure or on-call function, runs ClickHouse on their own cloud VMs (chosen for cost reasons over a managed offering). One table backs a fraud-review queue that internal analysts across three time zones query continuously throughout their respective business hours — so the table is effectively under active query load nearly 24 hours a day, five days a week. More than a few minutes of query downtime means analysts can't work the queue and fraud review backs up. The team is deciding among: (a) self-hosted ReplicatedMergeTree with a 3-node Keeper cluster they'd run themselves, (b) migrating this table to a managed ClickHouse offering for its built-in replication, (c) staying single-node but building faster, automated backup-and-restore tooling. Reason through which you'd recommend and under what conditions your recommendation would change. State your assumptions — there isn't a single correct answer here.

Model Answer

A reasonable default for this specific team: (b), migrate to a managed offering — with the reasoning, not the verdict, being the point.

  • Why (c) likely doesn't clear the bar: even a fast, fully automated restore has some nonzero window where the table is unreachable — provisioning, restore time, cutover. Against a workload that's under near-continuous query load across time zones, "a few minutes of automated restore" is a much smaller ask than "zero unplanned downtime," but it's still not zero, and this specific workload's stated tolerance is "more than a few minutes causes real backlog." (c) is the right call for a workload that can absorb an occasional restore window; this one has been described as one that can't.
  • Why (a) is the riskier of the two remaining options for this team specifically: the team has no dedicated ops function and, by their own account, is already running infrastructure themselves "for cost reasons" — meaning they're cost-constrained on engineering time as much as dollars. Standing up and operating a Keeper cluster from scratch is exactly the kind of coordination-system operational burden the anti-pattern gallery below warns about: it's easy to under-provision (a single or degraded Keeper node) in a way that quietly recreates the single point of failure the team is trying to escape, and a small team is more likely to make that mistake precisely because they don't yet have the operational muscle memory for a new distributed system.
  • Why (b) fits: it buys the availability outcome this workload actually needs without asking a four-person team with no ops function to develop Keeper expertise under time pressure. The cost is real — an ongoing subscription premium, and less control over exact infrastructure — but for a team explicitly already making cost-vs-effort trade-offs, trading dollars for the removal of an entire new operational surface is a defensible, not obviously wrong, use of that budget.
  • What would flip the recommendation to (a): if this were a larger, better-resourced infrastructure team already fluent in operating stateful distributed coordination systems — or if the "cost reasons" driving self-hosting were severe enough that a managed premium was genuinely unaffordable rather than just less convenient — self-hosted ReplicatedMergeTree becomes a completely reasonable default instead, and the fixed cost of building Keeper operational competence gets amortized across everything else that team already self-hosts.

The shape of the reasoning matters more than the specific pick: match the scarcest resource — here, dedicated ops capacity on a small team — against what each option actually demands, rather than picking whichever option sounds like "the real production answer."

Case studies

A plausible good fit: business-critical analytics under continuous query load. Companies like Cloudflare, Uber, and Yandex are widely known to run ClickHouse for analytics at real production scale — the general shape of "continuously queried, business-critical, already running enough infrastructure that adding replication is a marginal step, not a first step" is the textbook fit for self-hosted ReplicatedMergeTree: teams at that scale are typically already sharding for data volume, which means the multi-node operational surface Keeper needs already exists.

A composite bad fit, representative of a common mistake rather than a single named incident: a small team runs two shards times three replicas — six ClickHouse nodes — plus a separate three-node Keeper cluster, nine machines in total, for a reporting table refreshed weekly and queried by roughly five internal stakeholders. The actual availability requirement — tolerant of an hour of downtime, refreshed weekly regardless — never justified live standby infrastructure at all, let alone nine machines' worth. The team ends up spending real on-call attention on Keeper session issues for a table whose worst-case failure was always "the weekly refresh runs an hour late."

Running Keeper on a single node. Keeper needs its own quorum to tolerate a failure — a 3-node cluster survives one crash, a 1-node "cluster" survives none. Putting Keeper on one box doesn't remove your single point of failure; it moves it from the ClickHouse layer to the coordination layer, and a coordination-layer failure now threatens every replicated table on the cluster simultaneously rather than just the data on one node.

Treating replication as a backup strategy. A replica applies whatever happens to the source table, mistakes included — a bad DROP TABLE or a destructive mutation propagates to every replica just as faithfully as legitimate data does. If the real risk is operator or application error rather than hardware failure, the fix is backups kept separately, not more live copies of the same mutable state.

Assuming synchronous consistency by default. Reading from one replica immediately after writing to a different one can return a stale result, because replication is asynchronous unless insert_quorum (and a matching read-side setting) says otherwise. A team that assumes replicas are always instantly in sync ships a quiet read-your-own-write bug, not a hardware-fault-tolerance win.

Starving Keeper of resources by co-locating it with an already-loaded ClickHouse node "to save a server." Because writes and coordination on every replicated table depend on Keeper being responsive, a Keeper process competing for CPU or memory with a busy ClickHouse process can degrade replication cluster-wide, not just on the shared box.

Summary

ReplicatedMergeTree trades a single node's fragility for durability and read availability across copies — at the cost of running more infrastructure (multiple ClickHouse nodes plus a ClickHouse Keeper cluster to coordinate them), reasoning about asynchronous replication lag instead of assuming instant consistency, paying merge compute cost on every replica rather than once, and taking on a new category of failure modes centered on Keeper. Single-node ClickHouse with backups is the correctly-sized choice, not a lesser one, whenever a table's actual downtime and data-loss tolerance is genuinely high. Managed or cloud-provided replication — ClickHouse Cloud's SharedMergeTree being the concrete example — buys the same durability and availability outcome without the burden of operating Keeper yourself, at the cost of vendor dependency and ongoing subscription spend. Self-hosted ReplicatedMergeTree is the right choice when the need is real, the team is already running or willing to staff multi-node infrastructure, and it has — or is deliberately building — the operational capability a coordination system demands. Whichever option you land on, remember that replication answers "can a node die without taking my data or my queries with it," not "can bad data or a bad operator action be undone" — that second problem needs backups regardless of how the first one gets solved.

Quiz

  1. 1. A team adds ReplicatedMergeTree to a table specifically so that an accidental DROP TABLE run by an engineer can be recovered from. Why does this not achieve what they intended?

  2. 2. Immediately after an INSERT completes on Replica A of a two-replica ReplicatedMergeTree table (default settings, no insert_quorum), a SELECT against Replica B doesn't return the new rows yet. What's the most likely explanation?

  3. 3. A ClickHouse Keeper cluster is deployed as a single node to 'keep things simple.' What's the real consequence?

  4. 4. A small team with no dedicated infrastructure or on-call function is deciding how to make a business-critical, continuously-queried table more durable and available. Under what condition does the lesson's reasoning favor managed/cloud replication over self-hosting ReplicatedMergeTree?

  5. 5. During a merge on a two-replica ReplicatedMergeTree table with default settings, which of the following accurately describes what happens?