ClickHouse 集群扩容实战:数据重分布过程中的查询可用性保障
ClickHouse 集群扩容实战数据重分布过程中的查询可用性保障ClickHouse 集群扩容是件让人头疼的事——加节点容易但新节点上来之后数据要重分布resharding这个过程可能持续数小时甚至数天。期间如果查询打到还没迁移完的分片上要么返回不完整数据要么直接报错。业务方打开看板一看数据突然少了 30%电话就打过来了。今天我们来实战 ClickHouse 集群扩容重点讨论数据重分布过程中怎么保障查询可用性。一、ClickHouse 集群扩容的基本原理ClickHouse 用 ReplicatedMergeTree 引擎族做数据复制用分布式表Distributed 表做跨分片查询。扩容的本质是改变分片数量——比如从 2 分片扩到 4 分片数据需要从旧的 2 分片重分布到新的 4 分片。具体到节点层面扩容前集群由 ch-node-1 至 ch-node-4 组成 2 分片 2 副本结构扩容后新增 ch-node-5 至 ch-node-8形成 4 分片 2 副本结构。原有节点维持原有分片角色新节点加入后承担新增分片的副本职责数据随后在旧分片与新分片之间进行重分布。扩容流程关键步骤在配置文件中定义新的集群拓扑新增分片节点在新节点上创建本地表结构ReplicatedMergeTree创建新的分布式表指向新集群拓扑从旧分布式表迁移数据到新分布式表验证数据完整性后切换读写流量二、数据重分布的两种策略2.1 策略一INSERT SELECT 重分布最直接的方式——从旧分布式表读数据INSERT 到新分布式表ClickHouse 自动按新分片规则分配数据-- 第1步在新节点上创建本地表结构与旧表完全一致 CREATE TABLE IF NOT EXISTS user_events_local ON CLUSTER new_cluster_4shards ( event_date Date COMMENT 事件日期, event_type String COMMENT 事件类型, user_id UInt64 COMMENT 用户ID, event_time DateTime COMMENT 事件时间, duration UInt32 COMMENT 事件持续时间, channel LowCardinality(String) COMMENT 渠道 ) ENGINE ReplicatedMergeTree(/clickhouse/tables/{shard}/user_events_local, {replica}) PARTITION BY toYYYYMM(event_date) -- 按月分区 ORDER BY (event_date, event_type, user_id); -- 第2步创建新的分布式表 CREATE TABLE IF NOT EXISTS user_events_all ON CLUSTER new_cluster_4shards AS user_events_local ENGINE Distributed( new_cluster_4shards, -- 新集群名4分片 default, -- 数据库 user_events_local, -- 本地表名 rand() -- 分片键随机分配 ); -- 第3步数据重分布——从旧表读取INSERT到新分布式表 -- 按分区迁移避免一次性迁移全量数据导致内存爆炸 INSERT INTO user_events_all SELECT * FROM user_events_old_all WHERE event_date 2026-01-01 AND event_date 2026-02-01; -- 每次迁移一个月的数据循环执行直到全部迁移完优点逻辑简单ClickHouse 自动处理分片路由。缺点INSERT SELECT 期间新分布式表的数据不完整直接查询会丢失数据。2.2 策略二分区级无缝迁移更安全的策略——利用 ClickHouse 的分区 Attach 功能在迁移每个分区时做原子切换。具体流程如下选择待迁移分区确定当前需要迁移的分区例如 202601。旧表分离分区在旧节点上执行 DETACH 操作使分区变为离线状态不影响查询。数据文件复制将分区数据文件从旧节点复制到新节点。新表挂载分区在新节点上执行 ATTACH 操作恢复分区可用性。数据一致性验证检查新旧数据是否一致。若一致更新分布式表配置指向新集群。若不一致执行回滚将分区重新 ATTACH 回旧节点。循环执行完成当前分区后继续迁移下一个分区。-- 分区级迁移操作示例 -- 在旧节点上 DETACH 分区不影响查询分区变为离线状态 ALTER TABLE user_events_local ON CLUSTER old_cluster_2shards DETACH PARTITION 202601; -- 把分区数据文件从旧节点复制到新节点 -- ClickHouse 分区文件路径: /clickhouse/data/default/user_events_local/202601/ -- 使用 rsync 高效传输-- rsync -avz ch-node-1:/clickhouse/data/default/user_events_local/202601/-- ch-node-5:/clickhouse/data/default/user_events_local/-- 在新节点上 ATTACH 分区数据立即可查询ALTER TABLE user_events_local ON CLUSTER new_cluster_4shardsATTACH PARTITION 202601;## 三、查询可用性保障的三层防线 数据重分布过程中最大的挑战是查询怎么才能不中断、不丢数据 ### 3.1 第一层双分布式表并行查询 在迁移期间同时维护旧分布式表和新分布式表。查询走一个联合视图同时从两个表读数据然后取并集 sql -- 创建联合视图同时从新旧分布式表查询去重合并 CREATE VIEW user_events_union AS SELECT * FROM user_events_old_all -- 旧集群数据在逐步减少 UNION ALL SELECT * FROM user_events_new_all -- 新集群数据在逐步增加 -- 注意UNION ALL 可能产生重复数据正在迁移的分区同时出现在新旧两个表 -- 解决方案用 event_date user_id event_time 作为去重键更精确的去重方式-- 使用 ClickHouse 的 argMax 去重取最新版本的数据 CREATE VIEW user_events_safe AS SELECT event_date, event_type, user_id, event_time, duration, channel, argMax(event_type, _version) AS event_type_final, argMax(duration, _version) AS duration_final FROM ( SELECT *, 1 AS _version FROM user_events_old_all UNION ALL SELECT *, 2 AS _version FROM user_events_new_all ) GROUP BY event_date, user_id, event_time;3.2 第二层查询路由中间层在应用层实现查询路由——根据查询涉及的时间范围决定走旧表还是新表class ClickHouseQueryRouter: 查询路由器根据迁移进度决定查询走旧表还是新表 def __init__(self): # 记录已迁移完成的分区列表 self.migrated_partitions set() # 如 {202601, 202602, 202603} self.old_cluster_client ClickHouseClient(hostch-node-1, port9000) self.new_cluster_client ClickHouseClient(hostch-node-5, port9000) def route_query(self, sql, date_range): 根据查询的时间范围决定路由到旧集群还是新集群 date_range: {start: 2026-01-01, end: 2026-07-19} # 检查查询涉及的月份分区是否已迁移完 involved_months self._extract_months(date_range) if all(m in self.migrated_partitions for m in involved_months): # 所有涉及分区都已迁移 → 查询走新集群 return self.new_cluster_client.execute(sql) elif not any(m in self.migrated_partitions for m in involved_months): # 所有涉及分区都未迁移 → 查询走旧集群 return self.old_cluster_client.execute(sql) else: # 混合状态 → 需要走联合视图 union_sql sql.replace(user_events_all, user_events_safe) return self.new_cluster_client.execute(union_sql) def _extract_months(self, date_range): 从日期范围提取涉及的月份分区键 start date_range[start] end date_range[end] months set() current start while current end: months.add(current[:7].replace(-, )) # 2026-01 → 202601 # 下一个月 month int(current[5:7]) 1 year int(current[:4]) if month 12: year 1 month 1 current f{year}-{month:02d}-01 return months ### 3.3 第三层读写分离与流量切换 在迁移过程中写入流量会经过判断后同时写入新旧两个分布式表以确保新数据在两边都有读取流量则经由查询路由器根据迁移进度路由到旧、新或联合视图最终实现业务方无感知切换。 写入流量在迁移期间需要双写 sql -- 双写INSERT 同时写入新旧分布式表 -- 可以在应用层做也可以用 ClickHouse 的 materialized view CREATE MATERIALIZED VIEW user_events_dual_write ON CLUSTER old_cluster_2shards TO user_events_new_all -- 目标表新集群分布式表 AS SELECT * FROM user_events_old_all; -- 来源旧集群的数据写入自动同步到新集群-- 注意materialized view 只对新写入的数据生效-- 旧数据需要用 INSERT SELECT 迁移## 四、扩容后的验证与优化 ### 4.1 数据完整性验证 sql -- 对比新旧集群的数据量是否一致 SELECT old_cluster AS source, count() AS total_rows FROM user_events_old_all UNION ALL SELECT new_cluster AS source, count() AS total_rows FROM user_events_new_all; -- 对比关键指标的聚合结果是否一致 SELECT old AS source, sum(duration) AS total_duration, count(DISTINCT user_id) AS unique_users FROM user_events_old_all WHERE event_date BETWEEN 2026-01-01 AND 2026-06-30 UNION ALL SELECT new AS source, sum(duration) AS total_duration, count(DISTINCT user_id) AS unique_users FROM user_events_new_all WHERE event_date BETWEEN 2026-01-01 AND 2026-06-30;4.2 性能优化扩容后新节点可能有冷数据缓存问题-- 手动预热新节点的缓存 -- 先跑一遍全表扫描让数据进入 page cache SELECT count() FROM user_events_local WHERE event_date 2026-07-01; -- 调整分布式表的负载均衡策略 -- 从默认的随机分片改为按分片键分配减少跨分片查询 ALTER TABLE user_events_all ON CLUSTER new_cluster_4shards MODIFY ENGINE Distributed( new_cluster_4shards, default, user_events_local, userId -- 用 user_id 作为分片键同用户数据落在同一分片 );4.3 常见故障排查新节点 join 失败检查 ZooKeeper 连接是否正常/clickhouse/tables/{shard}/路径是否已创建分区 ATTACH 后查询报错检查分区文件格式是否兼容新旧节点的 ClickHouse 版本必须一致联合视图查询超时双分布式表查询开销翻倍调整max_execution_time和max_memory_usage建议在扩容期间将联合视图查询的超时时间设为正常值的 2-3 倍并提前和业务方沟通可能会有短暂的查询延迟。五、总结ClickHouse 集群扩容的核心挑战不是加节点本身而是数据重分布过程中的查询可用性保障。两种重分布策略各有适用场景INSERT SELECT 适合小规模或非生产集群分区级 ATTACH/DETACH 适合大规模生产集群的逐月迁移。查询可用性保障的三层防线是双分布式表联合视图保证数据不丢失、查询路由器根据迁移进度智能路由、双写保证新数据在两边都有。落地路径是先做小规模验证一个分区确认流程没问题后按分区循环迁移每迁移一个分区就更新路由器的已迁移列表直到全部完成再做最终流量切换。扩容后务必做数据完整性对比验证确保行数和聚合结果一致。最后提醒一点这个方案在上生产之前建议先用灰度流量验证一周确认资源消耗在预期范围内再全量推送。我们在实际项目中因为跳过了这步有一次把缓存集群打挂了教训深刻。

相关新闻

英雄联盟玩家的终极效率工具:3大核心技术革新你的游戏体验 [特殊字符]

英雄联盟玩家的终极效率工具:3大核心技术革新你的游戏体验 [特殊字符]

英雄联盟玩家的终极效率工具:3大核心技术革新你的游戏体验 🚀 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit LeagueAk…

2026/7/19 16:47:28阅读更多 →
金融场景下的数据归档与合规留存:大表 15 年全生命周期管理的实现路径

金融场景下的数据归档与合规留存:大表 15 年全生命周期管理的实现路径

金融场景下的数据归档与合规留存:大表 15 年全生命周期管理的实现路径 一、监管说交易记录保留 15 年,但热数据只需要 3 个月 金融监管对数据留存的要求极其严苛——《金融机构客户身份识别和交易记录保存管理办法》要求交易记录至少保存 5 年&#xff0…

2026/7/19 16:47:28阅读更多 →
网盘直链下载助手:浏览器直接下载的终极解决方案

网盘直链下载助手:浏览器直接下载的终极解决方案

网盘直链下载助手:浏览器直接下载的终极解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 …

2026/7/19 16:47:28阅读更多 →
ngx_output_chain_get_buf

ngx_output_chain_get_buf

1 定义 ngx_output_chain_get_buf 函数 定义在 src/core/ngx_output_chain.cstatic ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) {size_t size;ngx_buf_t *b, *in;ngx_uint_t recycled;in ctx->in->buf;size ctx->buf…

2026/7/20 0:15:05阅读更多 →
互联网大厂常见Java面试题及答案汇总(2026持续更新)

互联网大厂常见Java面试题及答案汇总(2026持续更新)

金九银十即将来袭,又是一个跳槽的好季节,准备跳槽的同学都摩拳擦掌准备大面好几场,今天为大家准备了互联网面试必备的 1 到 5 年 Java 面试者都需要掌握的面试题,分别 JVM,并发编程,MySQL,Tomca…

2026/7/20 0:15:05阅读更多 →
python数据可视化技巧的100个练习 -- 31. 类别数据的点图

python数据可视化技巧的100个练习 -- 31. 类别数据的点图

重要性★★★☆☆ 难度★★☆☆☆ 你是一家零售公司的数据分析师。你的经理要求你可视化最近产品发布的客户满意度评级分布。评级是分类的,范围从“非常不满意”到“非常满意”。创建一个点图以显示每个评级类别的频率。使用 Python 进行数据处理和可视化。在代码中生成输入…

2026/7/20 0:13:05阅读更多 →
智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

在2026世界人工智能大会(WAIC 2026)举办期间,千里科技董事长、阶跃星辰董事长印奇作为特邀嘉宾出席大会开幕式并在大会主论坛(上午场)发表主题演讲《当智能体进入物理世界》。在印奇看来,"智能体"…

2026/7/20 0:13:05阅读更多 →
商汤大装置发布“技术-生态-商业”闭环布局,共启“国产AI基础设施规模化商用元年”

商汤大装置发布“技术-生态-商业”闭环布局,共启“国产AI基础设施规模化商用元年”

7月18日,在WAIC 2026商汤科技 “基座大模型架构创新与生态合作论坛”上,商汤科技联合创始人、大装置事业群总裁杨帆发表《智变共生——加速AI基础设施持续升级》主题演讲,系统呈现了商汤大装置国产AI基础设施“技术-生态-商业”闭环布局&…

2026/7/20 0:13:05阅读更多 →
2026郑州美发学校避坑指南:拆解5种教学方式,谁在“流水线”谁在“真传技”?

2026郑州美发学校避坑指南:拆解5种教学方式,谁在“流水线”谁在“真传技”?

2026年想在郑州学美发,很多零基础学员最先搜索的问题就是:郑州美发学校哪家好?这个问题没有一个只看学校名字就能得出的答案。因为不同学校的课程方向、学习周期、教学方式和适合人群并不一样。有的更适合零基础,有的偏向发型师进修,还有的只做某一项短期技术培训。对于完全没…

2026/7/20 0:11:05阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/20 0:50:54阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/20 0:50:54阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/20 0:50:54阅读更多 →
2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

7月18日智东西消息,在2026 WAIC期间,努比亚联合字节豆包打造的二代“豆包手机”努比亚NaviX Ultra首次亮相,相比一代有诸多升级。智能体手机理念中兴通讯终端事业部总裁、努比亚总裁倪飞表示,智能体手机要从人操作手机变为手机帮人…

2026/7/20 0:01:04阅读更多 →
努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra:外观与功能双升级在2026 WAIC期间,首次亮相的努比亚NaviX Ultra吸引了众多目光。它是努比亚联合字节豆包打造的二代“豆包手机”,与一代努比亚M153相比,外观设计变化较大。其机身背部搭载横向排布的大尺寸影像模…

2026/7/20 0:01:04阅读更多 →
C# 将逗号分割的字符串转换为long,并添加到List<long>

C# 将逗号分割的字符串转换为long,并添加到List<long>

目录 方法1:使用Split和Convert.ToInt64 方法2:使用LINQ的Select和ToList 方法3:使用TryParse进行异常安全转换(推荐) 如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天…

2026/7/20 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/19 22:50:49阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/19 14:50:26阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/19 18:50:36阅读更多 →