设计完成 · 2026-11-05

津梁:设计收口了

15 份文档 + 2 个带测试的包 · 一张图、八个关键决策、六个里程碑

完成状态

15 份设计文档(含未决清单)
2 个包已带真测试进 CI(类型字典、状态机)
17 + 15断言数(状态机 / 类型映射)
0 行功能代码(刻意:先设计)

仓库 spencerswagger/JinLiang,commit 3b6cb8b,CI 双绿。

一句话定义

一个用 Go 写的单二进制同步工具:用户只谈自己的数据(哪张表、哪些列、多久一次、哪个方向),底层机制由工具负责探测、代做、补偿、清理。

一期:MySQL↔MySQL、PG↔PG、MySQL↔PG,单向;PG 10–18、MySQL 5.7/8.0/8.4/9.x。
不做:同表双向、Web UI、其他数据库。MIT。

八个关键决策

决策为什么
位点与数据同事务写目标库 _ds_meta崩溃重放天然幂等,不需要 Kafka 事务、不需要分布式协调;目标库位点是唯一权威,源端书签只是护栏
背压暂停读而不是暂停 ack不 ack 会让 WAL 堆积(有告警与阈值);ack 了却没落库就是丢数据。宁可堆盘,绝不丢
写入单线程有序,并行只在源端按表拆跨事务必须按提交顺序落地,否则因果错乱;要快就多开流,不是乱序
降级先补偿后拒绝PG 12 没磁盘阀就"落后 5 GB 暂停+主动推进";只有补偿会破坏一致性时才拒绝,且只拒那一张表
能力运行时探测,不按版本号分支MySQL 8.4 移除了 SHOW MASTER STATUS、9.x 移除 native 认证;版本号判断永远追不上分支与云上魔改
类型映射四档,绝不静默降级tinyint(1) 溢出 2..127、utf8mb4 单行 65535 字节、timestamptz 丢时区 —— 都要摆到桌面上让人确认
校验三级,L1 只做可加统计PG 与 MySQL 没有共同可比的行哈希(md5 vs crc32 不同源),所以初筛用 count/sum/min/max,行级校验放到应用侧抽样
自动动作全可回滚,blocked 无忽略开关开源工具碰的是生产库;没有 undo 的动作不许做,改配置类的必须人来

数据怎么流

[源] 读取/解码 → 事务组装 → 转换(并行) → 有界队列 → 批写入(单线程) → 提交(数据+位点)
        │             │                                        │
        │             └ 大事务 spill 到磁盘                      └ 提交成功才 ack 源端
        └ 心跳 / DDL / TRUNCATE → 控制面

内存预算:快照 并发 × 块行数 × 行宽、增量队列 8192 行、单事务 128 MB 后落盘。

生命周期

10 个阶段、迁移表写进代码并带断言——非法迁移直接测试失败,而不是运行时随缘。

idle → preflight → prepare → snapshot → catchup → streaming → draining → done
                      │                    │          │
                      └──→ failed ←────────┴──────────┴→ paused → streaming/snapshot

SIGTERM 三步:停读 → flush 并提交(含位点)→ advance 源端 + 释放租约。绝不半批落库。

安全边界

凭证只收 env: / file:(文件须 0600);yaml 与命令行不许写明文;日志 DSN 打码
最小权限PG:REPLICATION + 选中表 SELECT;MySQL:REPLICATION SLAVE/CLIENT + SELECT,建表权限同步后可收
传输默认 verify-full;降级必须在 plan 里标红确认
审计每个代做动作记「谁/何时/SQL/undo」,可 undo 撤销,撤销也记一笔

六个里程碑,验收都是可执行的

里程碑验收判据
M1 PG→PG 闭环1M/10M 行快照跑通;kill -9 重启不重不丢;对拍 200 seeds 绿
M2 MySQL 源5.7/8.0/8.4/9.x × 3 场景矩阵绿;8.4 语法与 9.x 认证两个坑有回归用例
M3 MySQL 目标双向映射表全用例;宽表行宽超限被预检拦住
M4 运维面故意破坏目标库 verify 必须报;孤儿书签 gc --dry-run 列出、--force 才删
M5 五档频次只有 SELECT 权限也能跑定时增量;同值/时钟漂移不漏数
M6 性能与门禁单核 ≥20k 行/s、p99 <100ms、空转 <80MB;release 覆盖 169 链路

还没定的五件(其余五条在文档里)

  1. MySQL 无主键表:允许但 insert-only(超 50 万行建议加主键),还是直接拒绝?
  2. _ds_* 落哪个 schema:默认跟目标表同 schema,要不要可配?
  3. 视图作为源:只支持快照、明确不支持增量 —— 这样够不够?
  4. 死信 raw_row:默认存真实行还是只存哈希?
  5. 是否做独立文档站:现在 README + docs/ 够用吗?

下一步

设计已经能直接开工:接口、状态机、类型字典都能编译并有测试;剩下的是把 M1 的 PG→PG 闭环写出来。

建议组队前先定上面五件M1 只做 PG→PG,别一上来铺三组合