ClickHouseNotes

第 16 章:副本

zjc 于 2026-01-16 发布

这是《ClickHouse 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 副本用于提高可用性、读吞吐和故障恢复能力。ClickHouse 的 ReplicatedMergeTree 依赖 Keeper 或 ZooKeeper 维护副本日志、块信息和leader 状态。

16.1 副本架构

              Keeper / ZooKeeper
                    |
      +-------------+-------------+
      |             |             |
  replica-1     replica-2     replica-3
      |             |             |
   local part    local part    local part

副本之间通过复制日志同步元数据,并从源副本拉取数据 part。

16.2 ReplicatedMergeTree

CREATE TABLE analytics.events_replicated
(
    event_date Date,
    event_time DateTime,
    user_id UInt64,
    event_type LowCardinality(String),
    amount Decimal64(2)
)
ENGINE = ReplicatedMergeTree(
    '/clickhouse/tables/{shard}/events',
    '{replica}'
)
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, event_type, user_id);

路径要求:

  1. 同一分片内各副本路径相同;
  2. 不同分片路径不同;
  3. 不同表路径不同;
  4. replica 名称唯一;
  5. 宏配置在每台节点正确。

16.3 写入复制

客户端写 replica-1
        |
        v
replica-1 创建 part
        |
        v
写入复制日志到 Keeper
        |
        v
replica-2 / replica-3 感知并拉取 part

副本写入是异步同步过程。写入成功返回点、part 副本数和一致性语义要结合设置与故障场景确认,不能简单等同于同步多副本持久化。

16.4 副本引擎家族

本地引擎 副本版本
MergeTree ReplicatedMergeTree
ReplacingMergeTree ReplicatedReplacingMergeTree
SummingMergeTree ReplicatedSummingMergeTree
CollapsingMergeTree ReplicatedCollapsingMergeTree
VersionedCollapsingMergeTree ReplicatedVersionedCollapsingMergeTree

先确定合并语义,再选择 Replicated 变体。

16.5 查询副本选择

Distributed 表可以配置负载均衡:

<remote_servers>
    <analytics_cluster>
        <shard>
            <replica>
                <host>ch-01</host>
                <port>9000</port>
            </replica>
            <replica>
                <host>ch-02</host>
                <port>9000</port>
            </replica>
        </shard>
    </remote_servers>
</remote_servers>

常见策略包括随机、轮询、最近主机、错误惩罚等。不同版本和配置支持有差异。生产上要确保:

  1. 不把查询集中到单个副本;
  2. 异常副本能被隔离;
  3. 延迟副本不提供过期结果;
  4. 查询超时可控制。

16.6 副本状态

SELECT
    database,
    table,
    zookeeper_path,
    replica_name,
    is_readonly,
    is_session_expired,
    queue_size,
    inserts_in_queue,
    merges_in_queue,
    absolute_delay
FROM system.replicas;

关键字段:

字段 含义
is_readonly 副本只读
queue_size 待处理复制任务
absolute_delay 副本延迟
is_session_expired Keeper 会话异常
log_pointer 复制日志位置

16.7 副本队列

查看任务:

SELECT
    database,
    table,
    replica_name,
    type,
    source_replica,
    create_time,
    num_tries,
    last_exception
FROM system.replication_queue
ORDER BY create_time;

常见任务类型:

类型 说明
GET_PART 拉取缺失 part
MERGE 执行合并
MUTATE 变更数据
DROP_RANGE 删除范围
ALTER_METADATA 元数据变更

16.8 Keeper 与 ZooKeeper

Keeper 是 ClickHouse 内置的高可用协调服务,兼容常用 ZooKeeper 协议场景。生产建议:

  1. 至少 3 节点;
  2. 独立部署或独立资源;
  3. 使用低延迟 SSD;
  4. 监控会话和延迟;
  5. 避免与其他高 IO 服务争抢磁盘。

确认连接:

SELECT * FROM system.zookeeper
WHERE path = '/clickhouse';

16.9 故障场景

副本只读

可能原因:

  1. Keeper 不可达;
  2. 会话过期;
  3. 元数据冲突;
  4. 副本正在恢复;
  5. 管理操作设置。

排查:

SELECT database, table, is_readonly, last_queue_update, last_queue_exception
FROM system.replicas
WHERE is_readonly = 1;

队列积压

处理顺序:

  1. 检查网络和磁盘;
  2. 检查源副本是否可用;
  3. 查看任务异常;
  4. 暂停高压写入;
  5. 修复后等待同步;
  6. 必要时从健康副本重建。

Part 损坏

优先从健康副本拉取。单副本表需要备份恢复。不要在未确认路径和备份的情况下手工删除数据目录。

16.10 高可用实践

  1. 事实表至少两个副本;
  2. Keeper 三节点以上;
  3. 副本跨故障域部署;
  4. 监控 readonly、queue、delay;
  5. 为写入和查询设置超时;
  6. 定期演练副本重建;
  7. 保留可恢复备份;
  8. 升级时逐节点滚动操作。

本章小结

副本解决可用性和读扩展问题,核心依赖 ReplicatedMergeTree 与协调服务。生产上要同时关注数据同步、队列积压、副本延迟和故障域规划。副本不是分片,也不能替代备份。

思考题

  1. ReplicatedMergeTree 依赖什么组件?
  2. 副本路径和 replica 名称为什么必须正确?
  3. 如何判断副本延迟和队列积压?
  4. 副本和分片的区别是什么?
  5. 哪些故障需要备份而不是副本恢复?