设计基线 v2 · MIT · 不实现

津梁 JinLiang:一期三种组合,覆盖 13 个版本

MySQL 5.7 / 8.0 / 8.4 / 9.x × PostgreSQL 10–18 · 同构含跨版本割接 · 169 条链路推演

定下来的事

9PG 大版本(10–18)
4MySQL 家族
169链路(全笛卡尔)
1352测试单元(×8 场景)

PostgreSQL 10–18:差异比想象中大

每一项差异都会改变同步的实现路径,不能靠"应该差不多"糊过去。

版本EOL对同步有实质影响的差异
102022-11逻辑复制首发(pgoutput);无 TRUNCATE 复制、无 slot 磁盘阀、无 slot advance
112023-11+ TRUNCATE 复制,+ slot advance
122024-11仍无 slot 磁盘阀
132025-11+ max_slot_wal_keep_size(磁盘阀,弃槽才不至于写满盘)、+ 分区根表发布
142026-11+ 流式大事务(protocol v2)、+ 二进制初始拷贝
152027-11+ 行过滤 / 列清单、+ 两阶段提交解码
162028-11+ 订阅端并行 apply、+ pg_stat_io
172029-11+ slot 随主备切换存活、+ pg_createsubscriber
182030-11+ 冲突检测视图、+ idle_replication_slot_timeout;宣称含 DDL 复制(需实测确认)

MySQL 4 个家族:语法和认证都会咬人

版本状态坑
5.7EOL 2023-10无 LOCK INSTANCE FOR BACKUP、无原子 DDL、无 binlog_expire_logs_seconds、默认 native 认证
8.0EOL 2026-04caching_sha2 默认;binlog_transaction_compression(8.0.20+)解析必须解压
8.4 LTS2032 前native 认证默认关闭;SHOW MASTER STATUS 已移除 → 必须用 SHOW BINARY LOG STATUS
9.x 创新版滚动native 认证插件彻底移除;default_authentication_plugin 变量删除
一个具体例子:拿 8.0 时代写死的 SHOW MASTER STATUS 去连 8.4,直接语法报错。所以连接器不能按版本号分支,只能运行时探测。

169 条链路怎么跑得起:四层矩阵

层内容链路何时跑
T1 自洽每版本 → 同版本(PG 10→10 … 18→18;MySQL 5.7→5.7 … 9.x→9.x)13每 PR(改动连接器的子集)× 3 场景
T2 相邻升级n → n+1(10→11 … 17→18;5.7→8.0→8.4→9.x)11每日 nightly
T3 极端跨度最老 ↔ 最新;降级只验「明确拒绝 + 给人话原因」4nightly
T4 异构轮转MySQL 4 × PG 9 × 2 方向 = 72,每周轮转抽样72(每周 12)nightly 抽样 / release 全量
≤15 分钟PR 门禁(T1 子集 × 3 场景)
30–50 分钟nightly(≈40 链路 × 8 场景)
2–3 小时release 全量 169 链路
每周一遍全版本全覆盖
为什么不全量每 PR 跑:1352 个单元跑不起也不必要。但一个版本都不许漏——漏的那条往往就是用户的生产版本。分层让 PR 不堵、每周仍全量扫一遍。

能力探测表(不写版本号分支)

能力探测方式缺失时降级
快照导出slot 创建是否接受 EXPORT_SNAPSHOT短锁取位点,并标注那一瞬
slot 磁盘阀pg_settings 是否有 max_slot_wal_keep_size只能告警不能自动失效,界面明说「你的版本没有磁盘保护阀」
流式大事务pgoutput 协议版本协商全量缓冲 + 上限 512 MB,超限拒绝并给建议
行过滤 / 列清单pg_publication_rel.prattrs/prqual全表传输 + 客户端过滤(标出带宽代价)
TRUNCATE 复制pgoutput 消息支持目标端定期校验 + 告警「源端 TRUNCATE 不同步」
binlog 状态语句SHOW BINARY LOG STATUS 是否可用回退 SHOW MASTER STATUS
备份锁LOCK INSTANCE FOR BACKUP回退 FTWRL;云上被禁 → 快照后取位点 + 重叠去重
认证插件mysql.user.plugin 分布native / caching_sha2 三态适配

产品表现:预检写「你的 PG 12 没有磁盘保护阀,我们用告警代替自动失效」,而不是抛 max_slot_wal_keep_size is not a valid parameter。

支持档:EOL 的也测,但不假装它是主力

全支持PG 14–18、MySQL 8.0 / 8.4 / 9.x — 缺陷必修,CI 全场景
尽力支持PG 10–13、MySQL 5.7 — 仍进矩阵仍跑 nightly,但上游已不再出补丁,预检里明示「建议升级」
不支持PG ≤ 9.6(无原生 pgoutput)、MySQL ≤ 5.6、MariaDB(本期)
降级方向PG 18→17 这类只验「明确拒绝 + 人话原因」,不承诺支持

测试形态(不变的骨架)

五层单元 / 连接器契约 / 端到端 / 故障注入(kill -9、slot 被删、schema 漂移)/ 性能基线(退化 >15% 红)
影子模型对拍内存影子库 vs 目标库逐行比;schema fuzz × 操作序列 fuzz;断言最终一致 / 重放幂等 / 位点不倒退 / 不串位;失败最小化成 seed
准入制度每个连接器带 testmatrix.yaml(镜像/版本/启动参数/能力位),没有清单 PR 直接红
覆盖度报表进 READMEpostgres 10→10 … 18→18 = 9/9 ✔,空格子一眼可见,不许吹「生产级」

语料 TPC-H / northwind / sakila / 各版本官方 regression DDL —— 零本地依赖,不拿任何客户库做基准。

降级:先补偿,后拒绝

每个能力缺口按三步走:① 自动补偿(用户无感)→ ② 有代价的替代(如实标注、可开关)→ ③ 才拒绝 + 解释 + 替代路径。降级不能降正确性——补偿会让结果不一致时,宁可不做。

缺口① 自动补偿② 有代价替代
PG 10–12 无 slot 磁盘阀监控落后量,超 5 GB 暂停并告警;主动推进位点定期全量校验 + 重建
PG 10 无 slot_advance()临时解码连接消费到位点后丢弃(需显式确认)只告警
PG 10 无 TRUNCATE 复制定时校验 + 自动订正;或源端触发器写入 _ds_event只告警
PG ≤13 无流式大事务大事务 spill 到磁盘,不占内存上限调到可用内存内
PG ≤14 无行过滤/列清单快照只 SELECT 需要的列;增量客户端侧过滤建议用视图当源
PG ≤14 无两阶段解码侦测 prepared xact 后暂停告警建议 max_prepared_transactions=0
目标版本更低(18→17)逐特性落地:虚拟生成列→普通列、uuidv7()→客户端生成、新类型→TEXT/JSONB、行过滤→客户端、DDL 复制→我们自己做目标端加影子列 / 落地 JSON
MySQL 5.7 无备份锁毫秒级 FTWRL 取位点快照后取位点 + 5 分钟重叠去重(标注极小重复可能)
MySQL 8.4/9.x native 被禁/移除自动建独立 caching_sha2 账号(不动用户原账号)建议升级客户端驱动
MySQL 8.4+ 无 SHOW MASTER STATUS双语法探测;后备读 performance_schema.log_status—
binlog 事务压缩实现 zstd 解压(源端开了也必须能读)建议源端关闭
MySQL 5.7 无原子 DDL白名单只允许可安全重放;DDL 期间短暂暂停该表轮询 information_schema 感知
落在实现上是「一张表驱动」:探测能力 → 查补偿表 → 有 ① 就用 ① 并在预检记「已补偿」→ 否则问用户是否接受 ② 的代价 → 都不行才拒绝。
跨版本降级只拒绝那一张表,不拒绝整个任务。

性能指标与开销:都要能算出来

≥20k 行/s单核快照(200 B 窄行)
p99 <100 ms端到端(同机房,batch 1 ms)
<80 MB / <256 MB空转 / 增量常驻内存
<200 ms冷启动;二进制 <25 MB

怎么测:TPC-H lineitem 三档(1M / 10M / 100M 行)+ sysbench 写入压测驱动增量;延迟用「源端写 clock_timestamp() → 目标端可见时间」打点;每次 release 存基线 JSON,任一指标退化 >15% 就红。

对谁开销项控制手段
源库1 个复制连接 + 快照期 ≤4 只读连接--snapshot-conns
快照读压力每连接 QPS 上限 200;按 PK 分块,块间可 sleep
WAL / binlog 保留slot 落后阈值 5 GB / 30 min;binlog 保留需覆盖最长断连(预检提示)
目标库写放大批量 500 行/事务;建议同步完再建二级索引
状态 / 死信表每任务 <10 MB;死信表上限 + 轮转
测试自身的开销估算墙钟
PR3 链路 × 3 场景 × 90 s + 单元 30 s12–15 min(并行 6)
nightly40 链路 × 9 min ≈ 6 机器小时20–30 min(并行 20)
release169 链路 × 9 min ≈ 25 机器小时1.5–2.5 h(并行 20)

磁盘约束 runner 只有 14 GB → matrix 让每个 job 只拉自己那个镜像,不要把 9 个 PG + 4 个 MySQL(约 6 GB)全缓存。

其余设计(v1 继承)

名字候选(六个,slug 在 spencerswagger 名下均未被占用)

名字slug出处 / 含义气质
津梁JinLiang渡口与桥("津,水渡也")桥接异构两端;最接近兰台、灵枢的文气
飞挽FeiWan「飞刍挽粟」——古代高速转运军粮最贴"低延迟 + 高吞吐 + 持续运输"
漕运CaoYun古代大规模水路转运强调吞吐与持续,略"重"
通渠TongQu打通水道、引流直白好记;但易与 Alibaba Canal 的"渠"联想
驿传YiChuan驿站接力传递与"雁书"语义偏近,容易撞
转输ZhuanShu《史记》"转输"= 转运输送稳、朴实,但记忆点弱
已定:津梁(JinLiang) —— 渡口与桥,异构两端之间那一段水路。仓库 spencerswagger/JinLiang、二进制 jinliang(短写 jl)。