ClickHouse cluster full-refresh publication¶
This guide is for data engineers making a first bounded full_refresh into a
one-shard ClickHouse cluster. It explains how to select the safe publication
mode, validate a manifest, and recognize a successful run. Operators recovering
an interrupted run should use the
cluster publication runbook.
Choose the mode from the physical topology¶
The two modes are not interchangeable.
| Manifest mode | ClickHouse inventory | Target engine | Staging behavior |
|---|---|---|---|
omitted or internal |
every member reports internal_replication=true |
direct Replicated*MergeTree |
dpone stages once and ClickHouse replicates one shared generation |
external |
every member reports internal_replication=false |
direct non-replicated *MergeTree |
dpone stages the same sealed artifact directly to every required member |
Do not select external for a replicated table. Fan-out plus table replication
can duplicate delivery. Do not select internal for independent tables. One
staged insert would not establish a complete generation on every member.
Mixed flags, a mode/engine mismatch, an incomplete inventory, multiple shards, or an unreachable required member block before source extraction. A requested cluster publication never falls back to local publication.
Prerequisites¶
Before the first run, confirm all of the following:
- the cluster contains exactly one shard and at least two required members;
- every member reports the same
internal_replicationvalue; - every target database uses the Atomic engine;
- external mode uses direct non-replicated MergeTree-family tables;
- the target and candidate are in the same database;
- no
Distributedaccess table is the publication target; - the runtime principal can inspect cluster, database, table, column, replica, and distributed-DDL queue metadata;
- the runtime principal can use the platform-owned KeeperMap authority and can create, insert, exchange or rename, and drop managed tables;
- the runtime can connect directly to every admitted member without exposing endpoints or credentials in output;
- direct member connections use the native transport and the per-member ports
advertised by
system.clusters; an injected endpoint resolver is required when Docker, a proxy, NAT, or another network boundary changes those addresses; - every resolved direct connection is opened during admission and the resolved endpoint set is bound into the inventory digest before extraction;
- distributed-DDL queue retention exceeds the maximum recovery window; and
- extraction produces one immutable replayable artifact with a SHA-256 digest, schema identity, byte size, and row count.
Local synthetic tests do not prove these properties for an external deployment. Live certification remains UNVERIFIED until it is run in an explicitly approved environment.
First success with external replication¶
Install the source and sink extras:
Start from the checked example:
dpone check \
examples/batch/clickhouse-external-replication-full-refresh.batch.yaml \
--format json
dpone plan \
examples/batch/clickhouse-external-replication-full-refresh.batch.yaml \
--format json
The important manifest fragment is:
sink:
type: clickhouse
table:
schema: analytics
name: target_table
staging:
schema: analytics
strategy:
mode: full_refresh
max_source_bytes: 104857600
options:
lineage: false
physical_design:
storage:
clickhouse:
engine: MergeTree
cluster:
name: analytics_cluster
ddl_scope: cluster
replication_mode: external
external_content_row_budget: 100000
The static plan includes this additive publication decision:
{
"requested": true,
"selected": true,
"mode": "cluster_external",
"replication_mode": "external",
"runtime_admission_required": true,
"no_fallback": true
}
runtime_admission_required is intentional: a static plan cannot prove the
current member inventory, grants, Keeper state, or direct-member connectivity.
Fix every blocker before proceeding. Do not reinterpret a static pass as live
certification. dpone plan returns exit code 1 when the external publication
decision contains blockers, even though it still renders the complete decision
document for automation and diagnosis.
lineage: false is required for this bounded V2 route because it publishes the
sealed source artifact unchanged. Lineage projection and decoder-dependent
transformations fail during pre-source admission; dpone does not extract first
and silently alter the artifact later.
Run through the normal runtime entrypoint after the plan is reviewed. The
manifest contains logical connection_ref aliases, never credentials. Run it
only inside a deployment-provided, verified
DPONE_RUNTIME_CONNECTION_CONTEXT; see the
credentials quickstart and
runtime startup diagnostics. Retain
the artifact spool on durable worker storage by setting
DPONE_EXTERNAL_ARTIFACT_STORE (or the schema-declared
options.external_artifact_store_path). The configured value must be an
absolute path. External admission fails before the
Keeper lock when neither is configured; there is no local /tmp fallback.
For multi-worker deployments the path must resolve to the same durable storage
on every eligible worker.
dpone run \
examples/batch/clickhouse-external-replication-full-refresh.batch.yaml \
--run-id external-cluster-full-refresh-001 \
--format json
The public Python API uses the same admission, authority, receipt, and recovery path:
import dpone
report = dpone.run(
"examples/batch/clickhouse-external-replication-full-refresh.batch.yaml",
run_id="external-cluster-full-refresh-001",
)
if not report.passed:
raise RuntimeError(report.result.errors)
What dpone does¶
flowchart LR
A[Complete member inventory] --> B[Keeper target fence]
B --> C[Seal one immutable artifact]
C --> D1[Stage member 1]
C --> D2[Stage member 2..N]
D1 --> E[All-member READY barrier]
D2 --> E
E --> F[Fenced one-shot cluster DDL]
F --> G[Queue and generation reconciliation]
G --> H[Durable COMMITTED receipt]
H --> I[Exact predecessor cleanup]
The operation and logical generation identities are deterministic for the same scheduler invocation and plan. Physical table UUIDs may differ between external members; the logical generation binds the artifact and schema digests to the ordered opaque member map.
An ambiguous member load is never appended again. Before publication, dpone may drop and rebuild only the exact owned unpublished candidate, then replay the same immutable artifact. Publication DDL is sent once and reconciled from its bound queue entry and every required member.
Recognize success¶
A successful external run has all of these properties:
- every required member reached
READYfor the same logical generation; - the authority advanced through the fenced publication phase;
- every target exposes its desired member generation;
- the durable receipt uses
dpone.clickhouse.cluster-external-full-refresh-receipt.v1; - source state advances only after the committed receipt is durable; and
- cleanup either completed everywhere or remains explicitly recoverable.
Structured output uses opaque member IDs and digests. It excludes endpoints, credentials, raw SQL values, source rows, and local artifact paths. Structured runtime success documents are written to stdout. Typed external-publication failure documents are written to stderr and exit non-zero, leaving stdout empty so a partial success document cannot be mistaken for a committed receipt.
The receipt embedded in an ordinary runtime result has
evidence_scope: runtime and evidence_status: UNVERIFIED. It proves the
runtime protocol outcome; it is not a certification receipt. Only the separate
exact-commit live-certification workflow may emit PASS certification
evidence.
Retry and recovery boundary¶
Retry only the same scheduler operation, including the identical explicit
--run-id external-cluster-full-refresh-001. Dpone observes the Keeper authority,
owned candidates, queue entry, and target generations, then resumes the exact
incomplete phase. A different operation remains fenced while the earlier record
is unresolved.
Never:
- switch the manifest to local or internal mode to bypass a failure;
- blindly repeat an insert, exchange, rename, or cleanup statement;
- delete an authority row to release a fence;
- delete a candidate or predecessor without exact UUID evidence; or
- treat a partial inventory or row-count match as proof of convergence.
Continue with the exact contract reference or the operator recovery runbook.