欢迎光临
我们一直在努力

ClickHouse高可用架构:基于ReplicatedMergeTree与ZooKeeper/Keeper的容灾方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

ClickHouse高可用架构:基于ReplicatedMergeTree与ZooKeeper/Keeper的容灾方案

本文将详细介绍ClickHouse中实现高可用的核心方案——ReplicatedMergeTree引擎结合ZooKeeper或Keeper的副本同步机制,以及如何在故障场景下实现自动恢复。通过学习本文,您将掌握构建稳定可靠的ClickHouse集群的关键技术。

1. ReplicatedMergeTree引擎原理

ReplicatedMergeTree是ClickHouse内置的表引擎,专门为实现数据副本和故障恢复而设计。它通过协调服务(ZooKeeper或Keeper)管理多个副本之间的数据同步,确保数据一致性和高可用性。

1.1 核心概念

ReplicatedMergeTree引擎涉及几个关键概念:

  • 会话ID:标识一次复制会话,确保事务性操作的一致性
  • 副本ID:集群中每个副本的唯一标识
  • ZooKeeper/Keeper路径:存储元数据和复制命令的路径
  • 数据分片:按照分键将数据分散存储
  • 副本:同一分片的多个实例,保证冗余和可用性

1.2 工作原理

ReplicatedMergeTree的工作流程如下:

  • 当数据写入主节点时,数据首先被写入本地存储
  • 同时,在ZooKeeper/Keeper中创建复制任务日志
  • 从节点监听ZooKeeper/Keeper中的变化
  • 从节点获取复制任务日志,并在本地执行相同的数据操作
  • 所有副本完成同步后,确认写入成功
  • 这种机制保证了即使主节点故障,从节点也拥有完整的数据副本,可以在故障切换后继续提供服务。

    — 创建ReplicatedMergeTree表示例
    CREATE TABLE example_table (
    id UInt32,
    name String,
    created DateTime
    ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/example_table', '{replica}')
    PARTITION BY toYYYYMM(created)
    ORDER BY id;

    在这个示例中,/clickhouse/tables/{shard}/example_table是ZooKeeper/Keeper中的路径,用于协调复制过程;{replica}是当前副本的标识符。

    2. 基于ZooKeeper的副本同步机制

    ZooKeeper作为成熟的分布式协调服务,被广泛用于ClickHouse的副本同步管理。它提供了可靠的数据存储和事件通知机制,确保副本间的数据一致性。

    2.1 ZooKeeper在ClickHouse中的作用

    在ClickHouse集群中,ZooKeeper主要负责以下任务:

    • 元数据管理:存储表结构、分区信息和复制元数据
    • 副本协调:跟踪各副本状态和同步进度
    • 主节点选举:在故障场景下自动选择新的主节点
    • 分布式锁管理:确保写入操作的原子性

    2.2 副本同步流程

    ZooKeeper实现的副本同步过程如下:

  • 数据写入主节点
  • 主节点将写入操作记录到ZooKeeper的日志节点
  • 所有从节点监听ZooKeeper中的变化
  • 从节点检测到新操作后,拉取数据并在本地执行
  • 从节点执行完成后更新ZooKeeper中的状态
  • #publish-mermaid-0-1789523937237{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-0-1789523937237 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-0-1789523937237 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-0-1789523937237 .error-icon{fill:#552222;}#publish-mermaid-0-1789523937237 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-0-1789523937237 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-0-1789523937237 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-0-1789523937237 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-0-1789523937237 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-0-1789523937237 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-0-1789523937237 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-0-1789523937237 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-0-1789523937237 .marker.cross{stroke:#333333;}#publish-mermaid-0-1789523937237 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-0-1789523937237 p{margin:0;}#publish-mermaid-0-1789523937237 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-0-1789523937237 .cluster-label text{fill:#333;}#publish-mermaid-0-1789523937237 .cluster-label span{color:#333;}#publish-mermaid-0-1789523937237 .cluster-label span p{background-color:transparent;}#publish-mermaid-0-1789523937237 .label text,#publish-mermaid-0-1789523937237 span{fill:#333;color:#333;}#publish-mermaid-0-1789523937237 .node rect,#publish-mermaid-0-1789523937237 .node circle,#publish-mermaid-0-1789523937237 .node ellipse,#publish-mermaid-0-1789523937237 .node polygon,#publish-mermaid-0-1789523937237 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-0-1789523937237 .rough-node .label text,#publish-mermaid-0-1789523937237 .node .label text,#publish-mermaid-0-1789523937237 .image-shape .label,#publish-mermaid-0-1789523937237 .icon-shape .label{text-anchor:middle;}#publish-mermaid-0-1789523937237 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-0-1789523937237 .rough-node .label,#publish-mermaid-0-1789523937237 .node .label,#publish-mermaid-0-1789523937237 .image-shape .label,#publish-mermaid-0-1789523937237 .icon-shape .label{text-align:center;}#publish-mermaid-0-1789523937237 .node.clickable{cursor:pointer;}#publish-mermaid-0-1789523937237 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-0-1789523937237 .arrowheadPath{fill:#333333;}#publish-mermaid-0-1789523937237 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-0-1789523937237 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-0-1789523937237 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-0-1789523937237 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-0-1789523937237 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-0-1789523937237 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-0-1789523937237 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-0-1789523937237 .cluster text{fill:#333;}#publish-mermaid-0-1789523937237 .cluster span{color:#333;}#publish-mermaid-0-1789523937237 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-0-1789523937237 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-0-1789523937237 rect.text{fill:none;stroke-width:0;}#publish-mermaid-0-1789523937237 .icon-shape,#publish-mermaid-0-1789523937237 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-0-1789523937237 .icon-shape p,#publish-mermaid-0-1789523937237 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-0-1789523937237 .icon-shape .label rect,#publish-mermaid-0-1789523937237 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-0-1789523937237 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-0-1789523937237 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-0-1789523937237 .node .neo-node{stroke:#9370DB;}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node rect,#publish-mermaid-0-1789523937237 [data-look=\”neo\”].cluster rect,#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-0-1789523937237 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-0-1789523937237 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    客户端写入数据

    主节点接收写入

    数据写入本地磁盘

    在ZooKeeper中创建任务日志

    从节点监听ZooKeeper变化

    从节点获取任务日志

    从节点执行数据复制

    所有副本确认完成

    2.3 配置要点

    启用ZooKeeper副本同步的配置参数:

    <!– clickhouse-server.xml –>
    <zookeeper>
    <node index="1">
    <host>zookeeper1</host>
    <port>2181</port>
    </node>
    <node index="2">
    <host>zookeeper2</host>
    <port>2181</port>
    </node>
    <node index="3">
    <host>zookeeper3</host>
    <port>2181</port>
    </node>
    </zookeeper>
    <replication>
    <zk_session_timeout_ms>30000</zk_session_timeout_ms>
    <zk_lock_timeout_ms>10000</zk_lock_timeout_ms>
    <use_zk_directories>true</use_zk_directories>
    <security_manager_update_period_ms>60</security_manager_update_period_ms>
    </replication>

    关键参数说明:

    • zk_session_timeout_ms:ZooKeeper会话超时时间
    • zk_lock_timeout_ms:分布式锁超时时间
    • use_zk_directories:是否使用ZooKeeper管理目录
    • security_manager_update_period_ms:安全管理器更新周期

    3. 基于Keeper的新一代协调服务

    Keeper是ClickHouse官方推出的新一代协调服务,作为ZooKeeper的分支项目,专为ClickHouse场景优化,提供更好的性能和集成度。

    3.1 Keeper与ZooKeeper的对比

    特性ZooKeeperKeeper
    原生集成 需额外配置 完全集成
    性能 中等 高性能优化
    适用规模 中小规模 大规模集群
    维护复杂度 较高 较低
    功能丰富度 丰富 专注副本同步

    Keeper的优势:

  • 原生集成:作为ClickHouse的一部分,无需额外部署和配置
  • 性能优化:针对ClickHouse场景进行了特别优化,提供更高的吞吐量
  • 轻量级:代码更简洁,维护成本更低
  • 更好的兼容性:与ClickHouse版本紧密配合,提供更好的稳定性
  • 3.2 配置Keeper

    启用Keeper服务相对简单,主要修改配置文件:

    <!– clickhouse-server.xml –>
    <keeper_server>
    <tcp_port>9181</tcp_port>
    <server_id>1</server_id>
    <log_storage_path>/var/lib/clickhouse/keeper/log</log_storage_path>
    <snapshot_storage_path>/var/lib/clickhouse/keeper/snapshots</snapshot_storage_path>
    <coordination_settings>
    <operation_timeout_ms>10000</operation_timeout_ms>
    <session_timeout_ms>30000</session_timeout_ms>
    <raft_logs_level>trace</raft_logs_level>
    </coordination_settings>
    </keeper_server>
    <zookeeper>
    <node>
    <host>keeper1</host>
    <port>9181</port>
    </node>
    <node>
    <host>keeper2</host>
    <port>9181</port>
    </node>
    <node>
    <host>keeper3</host>
    <port>9181</port>
    </node>
    </zookeeper>

    关键配置项说明:

    • keeper_server:Keeper服务配置,端口、存储路径等
    • zookeeper:指定Keeper节点地址
    • operation_timeout_ms:操作超时时间
    • session_timeout_ms:会话超时时间
    • raft_logs_level:Raft日志级别

    3.3 使用场景

    Keeper适用于以下场景:

  • 大规模ClickHouse集群(超过10个节点)
  • 对延迟敏感的应用场景
  • 需要更高吞吐量的业务
  • 希望降低运维复杂度的团队
  • 对于中小规模集群,ZooKeeper仍然是成熟的选择;而对于大规模生产环境,Keeper提供了更好的性能和集成体验。

    4. 故障恢复与自动切换实践

    ClickHouse的高可用不仅仅是数据复制,还包括故障检测、自动切换和恢复机制。本节将详细介绍这些机制的工作原理和实践方法。

    4.1 故障检测机制

    ClickHouse通过以下机制检测节点和副本状态:

  • 心跳检测:节点之间定期发送心跳包,确认彼此存活状态
  • 副本状态监控:监控各副本的数据同步延迟
  • ZooKeeper/Keeper会话监控:跟踪节点的ZooKeeper会话状态
  • 系统资源监控:监控CPU、内存、磁盘等系统资源使用情况
  • 当检测到节点故障时,ClickHouse会:

    • 标记故障节点为"不可用"
    • 通知所有节点更新集群状态
    • 如果故障的是主节点,触发选举机制

    4.2 主节点故障切换

    主节点故障切换过程如下:

  • 故障检测:发现主节点不再响应心跳或ZooKeeper会话超时
  • 候选节点选举:从节点中选举新的主节点
  • 状态确认:新主节点确认获得写入权限
  • 流量切换:将客户端请求重定向到新主节点
  • 数据恢复:确保新主节点数据是最新的
  • — 查看副本状态
    SELECT * FROM system.replicas;
    — 强制手动故障转移(在紧急情况下使用)
    ALTER TABLE example_table UPDATE replica_status = 'active' WHERE replica_host = '故障节点';

    4.3 从节点恢复

    从节点恢复步骤:

  • 检查节点状态:确认节点故障原因
  • 数据补全:确保本地数据是最新的
  • 重新加入集群:更新ZooKeeper/Keeper中的元数据
  • 状态同步:与主节点同步最新数据
  • — 检查从节点是否与主节点数据一致
    SELECT count() FROM example_table WHERE replica_name = '从节点名称';

    4.4 监控与告警

    建立完善的监控与告警机制对高可用至关重要:

  • 集群状态监控:监控节点存活、副本状态
  • 性能监控:查询延迟、吞吐量、资源使用
  • 数据一致性监控:副本间数据一致性检查
  • 自动告警:设置阈值,自动触发告警
  • 5. 最小示例与注意事项

    5.1 最小配置示例

    以下是一个三节点的ClickHouse集群高可用配置示例:

    <!– clickhouse-server.xml –>
    <remote_servers>
    <cluster>
    <shard>
    <replica>
    <host>node1</host>
    <port>9000</port>
    </replica>
    <replica>
    <host>node2</host>
    <port>9000</port>
    </replica>
    </shard>
    </cluster>
    </remote_servers>
    <zookeeper>
    <node>
    <host>zookeeper1</host>
    <port>2181</port>
    </node>
    <node>
    <host>zookeeper2</host>
    <port>2181</port>
    </node>
    <node>
    <host>zookeeper3</host>
    <port>2181</port>
    </node>
    </zookeeper>
    <users>
    <replica_user>
    <password>replica_password</password>
    <networks>
    <ip>::/0</ip>
    </networks>
    <profile>replica</profile>
    </replica_user>
    </users>
    <profiles>
    <replica>
    <readonly>0</readonly>
    </replica>
    </profiles>

    创建副本表的SQL:

    — 在node1上创建主节点表
    CREATE TABLE example_table ON CLUSTER cluster (
    id UInt32,
    name String,
    created DateTime
    ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/example_table', '{replica}')
    PARTITION BY toYYYYMM(created)
    ORDER BY id;
    — 在node2上创建从节点表
    CREATE TABLE example_table ON CLUSTER cluster (
    id UInt32,
    name String,
    created DateTime
    ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/example_table', '{replica}')
    PARTITION BY toYYYYMM(created)
    ORDER BY id;

    5.2 注意事项

  • 网络配置:
    • 确保节点间网络稳定,低延迟
    • 配置合理的超时参数
    • 考虑使用专用网络或VLAN
  • 磁盘空间:
    • 为每个节点预留足够的磁盘空间
    • 监控磁盘使用率,避免空间不足导致同步失败
    • 考虑数据清理策略,定期归档或删除旧数据
  • 参数调优:
    • 根据集群规模调整replication_alter_partitions_sync_timeout
    • 设置合适的zk_session_timeout_ms和zk_lock_timeout_ms
    • 根据数据量调整parts_to_insert_delayed等参数
  • 故障排查:
    • 监控system.replicas表了解副本状态
    • 查看system.query_log排查同步问题
    • 使用EXCEPT语法检查副本间数据一致性
  • 最佳实践:
    • 定期备份重要数据
    • 建立完善的监控和告警机制
    • 进行故障演练,验证自动恢复机制
    • 记录集群配置变更,便于故障排查

    通过以上配置和注意事项,您可以构建一个稳定可靠的ClickHouse高可用集群,确保数据安全和业务连续性。

    赞(0)
    未经允许不得转载:171主机测评 » ClickHouse高可用架构:基于ReplicatedMergeTree与ZooKeeper/Keeper的容灾方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址