18.7 复制拓扑 (链式 / 树形 / 星形)
一句话
拓扑决定 “延迟怎么叠加、带宽压在哪”:星形一跳最快(20ms)但主库要发 N 份,链式最省带宽但延迟随跳数累加(5 跳 100ms),树形折中(3 跳 60ms)——没有最好,只有 “你的瓶颈是主库带宽还是尾副本延迟”。
三种拓扑(本机按每跳 20ms 估算)
| 拓扑 | 最大跳数 | 尾副本滞后 | 主库出流量 | 适合 |
|---|---|---|---|---|
| 星形(主 → 所有从) | 1 | ≈20ms | N 份(带宽压力大) | 从库少、要低延迟 |
| 树形(主 → 中继 → 叶) | 3 | ≈60ms | 扇出(可控) | 跨机房/多地域 |
| 链式(A → B → C…) | 5 | ≈100ms | 1 份(最省) | 带宽紧张、能容忍延迟 |
尾副本滞后 ≈ 跳数 × 每跳延迟
主库出流量 ≈ 副本数 × 日志速率(星形)vs 中继数(树形)vs 1(链式)
选择判据
| 你的瓶颈 | 选择 | 理由 |
|---|---|---|
| 主库出口带宽 | 链式/树形 | 减少主库扇出 |
| 尾副本读延迟 | 星形 | 跳数最少 |
| 跨地域灾备 | 树形(按地域中继) | 避免跨洋多份复制 |
| 多活/写扩散 | 多主(见 18.1 复制模型:单主 / 多主 / 无主) | 拓扑无法解决写冲突 |
代码:树形拓扑的配置要点
# 主库只发给同机房中继,跨地域由中继再分发(减少主库跨洋流量)
# 主 → relay-1(同机房)
log_bin = ON
binlog_do_db = app
# relay-1 → 地域 B 的从库
# (在 relay-1 上开启 log_slave_updates,让从库能继续向下游复制)
log_slave_updates = ON
-- 检查“每一跳”的延迟,而不是只看末级
SHOW REPLICA STATUS; -- 关注 Seconds_Behind_Source / 位点差
反模式
| 反模式 | 后果 |
|---|---|
| 链式拓扑用于 “低延迟读” | 尾副本滞后随跳数累加,越深越慢 |
| 星形拓扑用于几十个从库 | 主库出口带宽打满,影响写入 |
| 中继节点不监控 | 中继挂 = 下游全断,且难定位 |
| 跨地域直接星形复制 | 主库承担全部跨洋流量,成本高 |
| 拓扑变更不做演练 | 切换/扩容时才发现延迟不达标 |
| 只监控末级延迟 | 不知道是哪一跳慢 |
三条铁律
🔑 延迟按跳数累加;要低延迟就减少跳数。
🔑 带宽压力在主库扇出;从库多就用中继。
🔑 每一跳都要监控,否则定位不到瓶颈。
自检
Q1 为什么链式拓扑 “省带宽” 却 “延迟高”?
▸ 答案:因为链式每级只发给下一个节点,主库出流量只有 1 份(省带宽);但日志要逐跳重放,尾副本的滞后 = 跳数 × 每跳延迟。跳数越多,尾副本越慢,且中间任何一跳故障都会阻断下游。
Q2 树形拓扑的 “中继” 有什么风险?
▸ 答案:中继是单点:它挂了,整棵子树都断流;而且中继需要 log_slave_updates 才能继续向下游复制,配置错误会导致 “下游永远追不上”。所以中继要监控、要能快速替换(或做双中继)。
Q3 星形拓扑什么时候会压垮主库?
▸ 答案:当 从库数量 × 日志速率 超过主库出口带宽时:每个从库都要一份完整日志,几十个从库就是几十倍出流量。表现是 “主库写入正常但复制延迟飙升”“网络打满”。此时应改树形,用中继分担扇出。
Q4 跨地域复制为什么常用 “树形 + 地域中继”?
▸ 答案:因为跨洋带宽贵且延迟高:让主库只发同机房中继,再由中继分发到各地域,可以把 “N 份跨洋流量” 降为 “1 份”。代价是多一跳延迟(可接受,因为跨洋本来就有延迟)。
Q5 拓扑和 “一致性” 有关系吗?
▸ 答案:间接有:跳数越多,尾副本越旧,读一致性的窗口越大(见 18.4 复制延迟与读一致性);但一致性级别由 “同步/异步” 决定,不由拓扑决定。拓扑影响的是 “延迟分布”,不是 “是否可能丢数据”。
Q6 多主(multi-master)能解决拓扑问题吗?
▸ 答案:不能,它只是把 “复制延迟” 换成 “写冲突”:多主之间仍要复制,冲突要靠版本/CRDT/人工解决。拓扑解决 “怎么分发”,多主解决 “哪里能写”,两者是不同维度的问题。
Q7 如何验证拓扑是否合适?
▸ 答案:压测 + 观测:测 每跳延迟、尾副本滞后 P99、主库出口带宽。如果尾副本 P99 超标 → 减跳数;如果主库带宽打满 → 加中继。只看 “平均延迟” 会掩盖尾副本的问题。