bigywater.tech
ClickHouse 内部原理 · 62

ReplicatedMergeTree:副本如何同步 Part

真实建一张ReplicatedMergeTree表,只往一个副本插入数据,验证另一个副本如何自动同步,以及背后Keeper协调+HTTP传输的两层真实机制。

只插一边,两边都有
真实node2零操作自动同步node1插入的1万行
同名不同位
真实part文件名相同但物理磁盘路径完全独立

做的事:真实建一张ReplicatedMergeTree表,只往一个副本插入数据

代码CREATE TABLE demo.repl_tbl ON CLUSTER mycluster (k UInt64, v String) ENGINE=ReplicatedMergeTree('/clickhouse/tables/{shard}/repl_tbl', '{replica}') ORDER BY k; -- 只在node1(replica1)插入,node2(replica2)完全不碰 INSERT INTO demo.repl_tbl SELECT number, toString(number) FROM numbers(10000);

验证:node2真实自动同步到了同样的数据

实测 · 本机执行输出
node1: SELECT count() FROM demo.repl_tbl → 10000
node2: SELECT count() FROM demo.repl_tbl → 10000   ← 真实自动同步,没有手动做任何操作

真实的part信息:
node1: all_0_0_0
node2: all_0_0_0   ← 真实同名part

真实的物理路径(完全独立):
node1: .../node1/data/store/be9.../all_0_0_0/
node2: .../node2/data/store/be9.../all_0_0_0/   ← 真实不同磁盘位置,各自一份完整拷贝

node2从头到尾没有被真实插入过一行数据,10000行数据真实是自动出现的——part名字all_0_0_0在两边完全相同,说明node2真实拿到的是跟node1一模一样的part(不是重新生成的),但两边的物理磁盘路径完全独立,证明这是一次真实的网络拷贝,不是共享存储。

真实的同步机制:Keeper记账,副本自己按需拉取

这套同步真实分成两层:第一层是协调层,node1插入完成后,会真实往Keeper里对应这张表的/clickhouse/tables/1/repl_tbl/log路径写一条日志(本文后面《Keeper》一篇会验证这条日志的真实内容——一条"source replica: replica1, get, all_0_0_0"这样的记录,本质是"我(replica1)有一个新part,你们谁需要就来拿");第二层是数据传输层,node2真实持续监听这个日志路径,一旦发现有自己还没有的part,就把这条记录放进自己的replication_queue(本系列后面一篇会专门验证这个队列),然后真实发起一次HTTP请求,通过interserver_http_port这个专门给副本之间传输part数据用的端口,把完整的part文件从node1下载到本地。这个架构真实的设计意图是:Keeper本身只存轻量的协调信息(谁有哪个part、谁需要哪个part),真正体积庞大的数据传输走的是节点之间独立的HTTP连接,不会让Keeper成为数据传输的瓶颈或者单点故障——这也是本文搭建集群时,除了给每个节点配置Keeper地址之外,还必须真实额外配置一个interserver_http_port的原因,本文第一次尝试忘记配置这个端口时,真实撞上了"Table is in readonly mode"的报错,副本完全无法激活,直到补上这个端口才恢复正常。

分步演示:从单边插入到真实自动同步的完整过程

每一步都是本文上面用真实ReplicatedMergeTree跑出来的原始结果。

只插入一边,另一边真实自动同步过去
这一步新验证的节点

    本文用到的工具

    • 本机真实搭建的3节点集群,真实的 ReplicatedMergeTree('/clickhouse/tables/{shard}/repl_tbl','{replica}')
    • 真实的 interserver_http_port(副本间数据传输专用端口)
    京ICP备2026067502号-1京公网安备11010502063487号