第 13 章 · 副本与分布式 — 可视化演示

五个交互演示:① 集群拓扑 · ② Distributed 写入路径 · ③ Distributed 查询 fan-out/fan-in · ④ Replicated 同步流程 · ⑤ 副本 vs 分片对照

调一调分片数 × 副本数,看拓扑变化

下面的可视化会按你设置的「分片数 × 副本数」实时渲染节点图,并自动计算总机器数、总数据量、容错能力等指标:

机器总数6
总数据量(含副本)1800 GB
每节点存数据300 GB
最多可挂机器(不丢数据)3
分布式表 SQL 路由×3
口诀: 分片决定容量,副本决定可用性。N 分片 × M 副本 = N×M 台机器,但有效数据只装 N 倍(不是 N×M 倍),这就是「副本是镜像」的体现。
注意: 「最多可挂机器(不丢数据)」算的是「单分片只要还活着 ≥1 个副本就不丢数据」。但如果某个分片所有副本都挂,那一片数据就读不到了(其他分片仍能读)。

INSERT INTO events_all 走过的完整路径

下面会演示一条 INSERT 在 3 分片 × 2 副本下的完整路由。重点看 internal_replication 开关对写入流量的影响:

internal_replication = true (开 = Distributed 只写一副本,靠 Replicated 自己同步;关 = Distributed 自己向每副本各写一份)
关键观察:internal_replication=true 时,写入流量 = 1(Distributed 只发一次)+ 1(Replicated 同步)= 2 次网络传输,但客户端只等 1 次。关掉之后,Distributed 自己发 N 次,会和 ReplicatedMergeTree 双重写入,导致数据被写两遍。

SELECT count() FROM events_all 的 fan-out / fan-in

跑一条聚合 SQL,看 Initiator 节点如何把请求扇出(fan-out)到各分片、各分片如何返回中间状态(partial state)、最后在 Initiator 上扇入(fan-in)合并:

聪明的设计: 各分片回传的不是原始数据行,而是uniqState这种「聚合中间状态」(HyperLogLog 草图)。所以即便每个分片有 1 亿行,Initiator 拿到的中间结果也只有几 KB,最后用uniqMerge合并出最终值。这是 ClickHouse 能秒级聚合亿行的核心秘诀。

ReplicatedMergeTree 副本同步:双胞胎照镜子

看一次 INSERT 后,源副本如何在 ZooKeeper / Keeper 登记 log,其他副本又如何主动从「公告板」拉取并下载 Part:

核心要点: 副本之间不直接握手,全靠 Keeper 这块「公告板」。元信息(几百字节 JSON)走 Keeper,真正的列文件(几百 MB)走副本之间的 HTTP 9009 端口。

副本 vs 分片:一图打死

📷 副本(Replica)= 镜像

同一份数据印 3 份。3 台机器各 1TB → 总数据量仍是 1TB。

副本 1 (1TB):
ABCDE
副本 2 (1TB):
ABCDE
副本 3 (1TB):
ABCDE
解决:高可用、读扩展。挂任意 1-2 台不丢数据。

✂ 分片(Shard)= 切割

原数据切成 3 份。3 台机器各 1TB → 总数据量 3TB。

分片 1 (1TB):
AB
分片 2 (1TB):
CD
分片 3 (1TB):
E
风险:挂任意 1 台 → 该分片数据不可读。需要叠加副本才高可用。
维度副本(Replica)分片(Shard)
解决什么问题高可用、读扩展扩容量、写并行
数据关系完全镜像互不相交
3 台 × 1TB 能装多少1 TB3 TB
挂 1 台后果业务无感该分片不可读
实现引擎ReplicatedMergeTreeDistributed + 本地表
协调依赖ZK / Keeperremote_servers 配置
数据如何均衡一定均衡(镜像)看分片键设计
类比同书印多本百科分卷
MySQL 类比主从复制分库分表 / Vitess
生产黄金组合: N 分片 × M 副本(N≥2, M≥2)。例如 3×2 集群(6 台)能装 3 倍数据,丢任意 1 台不丢数据。