15 份文档 + 2 个带测试的包 · 一张图、八个关键决策、六个里程碑
仓库 spencerswagger/JinLiang,commit 3b6cb8b,CI 双绿。
一个用 Go 写的单二进制同步工具:用户只谈自己的数据(哪张表、哪些列、多久一次、哪个方向),底层机制由工具负责探测、代做、补偿、清理。
| 决策 | 为什么 |
|---|---|
位点与数据同事务写目标库 _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 打码REPLICATION + 选中表 SELECT;MySQL:REPLICATION SLAVE/CLIENT + SELECT,建表权限同步后可收verify-full;降级必须在 plan 里标红确认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 链路 |
设计已经能直接开工:接口、状态机、类型字典都能编译并有测试;剩下的是把 M1 的 PG→PG 闭环写出来。
建议组队前先定上面五件M1 只做 PG→PG,别一上来铺三组合