尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ClickHouse 分布式集群数据重平衡(Rebalance)与无感扩容:从手动分片搬迁到自动化数据迁移实战

ClickHouse 分布式集群数据重平衡(Rebalance)与无感扩容:从手动分片搬迁到自动化数据迁移实战 ClickHouse 分布式集群数据重平衡Rebalance与无感扩容从手动分片搬迁到自动化数据迁移实战在企业级大规模实时 OLAP 架构中随着业务数据量的指数级爆发原有ClickHouse 分布式集群Distributed Cluster的存储容量与算力逐渐逼近物理极限如4 节点集群磁盘水位突破 $90%$ 警戒红线。此时运维团队最常规的操作便是向集群新增节点进行水平横向扩容从 4 分片扩容至 8 分片。然而许多从 Elasticsearch、Kafka 或 TiDB 转型而来的大数据工程师在完成 ClickHouse 新节点上线后遭遇了令人目瞪口呆的**“扩容无效与数据倾斜灾难”**新扩容节点长期“空转围观”老节点依然“磁盘打爆”不同于 ES 或 TiDB 原生具备自动化分片重平衡Auto-Rebalancing机制ClickHouse 底层原生绝不提供自动数据搬迁能力新扩容的 4 个节点上线后只有后续新产生的增量数据才会按新 Hash 规则路由过去而历史数百 TB 的存量数据死死留在老节点上纹丝不动集群查询木桶效应爆发由于分布式表查询需要等待所有 Shard 执行完毕后汇聚老节点因磁盘与 CPU 过载导致查询耗时长达 10 秒新节点虽然 10 毫秒跑完却只能傻傻等待扩容后系统整体 P99 延迟不仅毫无改善反而更慢ClickHouse 为什么不自动做数据重平衡如何安全、快速、平滑地将老分片上的历史存量数据搬迁至新分片实现全集群磁盘水位的绝对均衡本文深入剖析 ClickHouse 分布式分片底层路由机理、三大数据搬迁方案对比矩阵并给出生产级自动化分区分片重平衡迁移实战代码。一、ClickHouse 数据重平衡三大搬迁方案全景对比矩阵数据搬迁方案物理实现机制生产业务中断影响迁移速度与资源消耗工业生产适用场景1. 分区冻结与物理拷贝 (FREEZE ATTACH)手动执行ALTER TABLE FREEZE PARTITION结合rsync拷贝物理 Part需短暂锁表操作极度繁琐易出错⚡ 极快直接复制物理 SST 压缩块相同拓扑结构节点一对一物理置换2. 分布式remote()函数流式查询插入执行INSERT INTO new_table SELECT * FROM remote(...)✅ 完全在线零停服 (Zero-Downtime)较慢消耗源节点与目标节点的 CPU/网络中小规模数据表$ 5\text{TB}$平滑搬迁3.clickhouse-copier分布式协同迁移 (黄金标准)官方专用工具基于 ZooKeeper 状态机实现多节点并行分片流式重哈希搬迁 纯后台异步无感搬迁断点续传且自动校验⚡ 极高全集群多 Worker 并发对拷打满万兆网卡超大规模集群数十 TB 至 PB 级扩缩容首选二、新旧分片 Hash 路由断层 vs 数据重平衡流转时序架构假设原始表使用cityHash64(user_id) % 4分布在 4 个分片上扩容为 8 分片后路由规则变更为cityHash64(user_id) % 8[ 扩容后的数据断层现状]: 老节点 Shard 1 ~ 4 ➔ 堆积了 100% 的历史存量数据 (磁盘占用 95%!) 新节点 Shard 5 ~ 8 ➔ 仅有刚写入的少量增量数据 (磁盘占用 2%!) [ clickhouse-copier 自动化数据重平衡流转时序]: ------------------------------------------------------------------------------- | ZooKeeper 集群协调中枢 (Task State Machine): | | 1. 将待迁移的历史表按 Partition (如按月/天) 拆分为 100 个原子任务槽 (Task) | ------------------------------------------------------------------------------- | | (并发拉取未完成的任务槽) v ------------------------------------------------------------------------------- | clickhouse-copier 分布式数据搬迁工作进程组 (Workers 1 ~ 8 并行执行): | | 1. 从老节点 Shard 1 拉取分区数据流 | | 2. 在内存中根据新的 cityHash64(user_id) % 8 重新计算目标 Shard 编号 | | 3. 批量推送到目标新集群的对应 Shard 节点 (自动去重与原子落盘) | | 4. 向 ZooKeeper 标记当前 Partition 搬迁成功完成! | ------------------------------------------------------------------------------- | v [ 最终状态: 8 个分片节点历史与增量数据实现 100% 完美绝对重平衡单机负载均衡!]三、生产级clickhouse-copier数据迁移配置文件实战在迁移服务器上编写copier_config.xml定义源集群、目标集群与重分片规则clickhouse !-- ZooKeeper 状态协调配置 -- zookeeper node index1 hostzk-node1.internal/host port2181/port /node /zookeeper !-- 数据迁移任务描述 -- tables table_trade_orders !-- 1. 源数据集群拓扑 -- cluster_pullcluster_4_shards/cluster_pull database_pulltrade_db/database_pull table_pullfact_orders_local/table_pull !-- 2. 目标数据集群拓扑 (扩容后的 8 分片集群) -- cluster_pushcluster_8_shards/cluster_push database_pushtrade_db/database_push table_pushfact_orders_local/table_push !-- 3. 目标引擎表结构 DDL (若不存在自动创建) -- engine ENGINE ReplicatedMergeTree(/clickhouse/tables/{shard}/fact_orders_local, {replica}) PARTITION BY toYYYYMM(event_time) ORDER BY (tenant_id, event_time, order_id) /engine !-- 4. 核心重新分片哈希算法 -- sharding_keycityHash64(order_id)/sharding_key !-- 5. 每次搬迁的范围条件过滤 (支持分批次按月迁移) -- where_conditionevent_time 2026-01-01 00:00:00/where_condition max_workers8/max_workers /table_trade_orders /tables /clickhouse启动分布式搬迁工具# 启动 clickhouse-copier 进程进行全量无感搬迁 clickhouse-copier --config copier_config.xml --task-path /clickhouse/copier/task_orders_rebalance四、生产级 Python 自动化流式重平衡迁移与数据对账脚本对于无clickhouse-copier环境的中小集群下面的 Python 脚本展示了如何基于remote()函数按分区自动化迁移并对账。 clickhouse_safe_rebalance_migrator.py 生产级 ClickHouse 分布式集群自动化无感扩容与历史数据重平衡迁移实战 import time import logging import requests logging.basicConfig(levellogging.INFO, format%(asctime)s - [%(levelname)s] - %(message)s) class ClickHousePartitionRebalancer: def __init__(self, node_host: str 127.0.0.1, node_port: int 8123): self.endpoint fhttp://{node_host}:{node_port}/ def execute_sql(self, sql: str) - str: resp requests.post(self.endpoint, datasql.encode(utf-8), timeout1800) if resp.status_code ! 200: raise RuntimeError(fSQL execution failed: {resp.text}) return resp.text.strip() def get_all_partitions(self, database: str, table: str): 获取所有待迁移的分区列表 sql f SELECT DISTINCT partition FROM system.parts WHERE database {database} AND table {table} AND active 1 ORDER BY partition DESC raw self.execute_sql(sql) return [p for p in raw.split(\n) if p] def migrate_single_partition(self, database: str, src_table: str, dest_dist_table: str, partition: str): 优雅迁移单个分区并重新执行分布式哈希打散 logging.info(f 开始重平衡迁移分区: 【{partition}】...) start_t time.time() # 将老分区数据流式查询并通过分布式表重新哈希打散写入新 8 分片集群 migrate_sql f INSERT INTO {database}.{dest_dist_table} SELECT * FROM {database}.{src_table} WHERE toYYYYMM(event_time) {partition} self.execute_sql(migrate_sql) # 数据对账校验 src_cnt self.execute_sql(fSELECT count(1) FROM {database}.{src_table} WHERE toYYYYMM(event_time) {partition}) logging.info(f✅ 分区 {partition} 迁移完毕源分区行数: {src_cnt} | 耗时: {time.time() - start_t:.2f}s) def run_full_rebalance(self, database: str, src_table: str, dest_dist_table: str): print(f\n 开始执行 ClickHouse 集群历史数据全量重平衡 ) partitions self.get_all_partitions(database, src_table) print(f 扫描到共有 {len(partitions)} 个待迁移分区: {partitions}) for p in partitions: self.migrate_single_partition(database, src_table, dest_dist_table, p) time.sleep(2) # 缓冲休眠防止网络 IO 突发打满 print( 全集群所有历史数据重平衡已平稳安全完成\n) if __name__ __main__: rebalancer ClickHousePartitionRebalancer(node_host127.0.0.1, node_port8123) rebalancer.run_full_rebalance(trade_db, fact_orders_local_old, fact_orders_distributed_new)五、生产避坑与 ClickHouse 扩容治理红线在生产中执行 ClickHouse 集群扩容与重平衡时必须坚守以下四项落地原则迁移期间严格控制搬迁带宽与并发线程数在执行大规模数据重平衡时必须限制数据读取与写入带宽如单机限制在 150MB/s坚决防止后台迁移把磁盘 IOPS 占满导致前端线上业务查询超时报错。迁移前后必须做 100% 行数与金额 Checksum 对账在删除老分片物理数据前必须执行SELECT count(1), sum(cityHash64(*)) FROM table进行严格对账确认新旧集群数据完全一致后方可清理旧数据。彻底完成搬迁后再原子切换分布式表视图Atomic Exchange Table利用EXCHANGE TABLES fact_orders_all AND fact_orders_all_new实现毫秒级无感原子切换实现对上游写入端与下游报表查询端的零停机Zero-Downtime平滑割接。通过系统性地掌握 ClickHouse 分布式架构底层的静态路由机理运用clickhouse-copier与自动化分区迁移流水线大数据运维团队能够实现大规模 OLAP 集群的平滑在线水平扩容彻底攻克数据倾斜与老节点爆盘的顽疾让全集群算力得到充分释放。
返回列表