3.9 KiB
3.9 KiB
跨库数据同步中间件
支持 SQLite ↔ MySQL ↔ Postgres,不要求两端同一种数据库。变更经 outbox 队列 近实时投递;冲突进 冲突队列。
权限与隔离
| 项 | 说明 |
|---|---|
| 谁可配 | 仅公司顶级权限(管理员),权限名「数据同步」 |
| 谁不可 | 编辑 / 只读、智能体账号(即使有「发布模块」) |
| 数据隔离 | 通道与冲突带 tenant_id;公司 A 看不到公司 B 的通道/DSN |
| 多服务器 | 同一公司可建多条通道,分别填 B、C 等库的 DSN |
典型场景:A / B / C
| 端 | 角色 |
|---|---|
| A | 线上库(用户增删改) |
| B | 本地库(本机业务 + 接收 C) |
| C | 额外数据源(Excel / API / 导入),只写入 B |
推荐配置:
- 建一条通道:
local= B,remote= A,方向bidirectional,冲突策略queue(或 LWW)。 - C 的数据用 ingest API(或业务直接写 B)写入本地;触发器进 outbox,再推到 A。
- A 上用户改的数据经 outbox 拉回 B。
- 怀疑漏数时点 对账,或等双向通道约每分钟自动对账。
如何保证不漏、不多:
| 手段 | 防什么 |
|---|---|
表触发器 → _ajz_sync_outbox |
漏(本地/线上变更必入队) |
应用远端时 WithApplying(触发器不写 outbox) |
多(A↔B 回声环) |
| 目标 meta 版本相等则跳过 | 多(重复投递) |
| 目标版本更新 → 冲突队列 / LWW | 并发改同一行 |
| 主键对账 reconcile | 漏(存量差、触发器未装前的行) |
| C→B upsert 同主键 | 多(重复灌入) |
C ──ingest/写库──► B (local) ◄──bidirectional outbox──► A (remote)
能力
| 项 | 说明 |
|---|---|
| 方言 | sqlite / mysql / postgres |
| 实时性 | 表触发器写 _ajz_sync_outbox,worker 默认每 500ms 拉取 |
| 方向 | 本地→线上 / 线上→本地 / 双向(A↔B 场景用这个) |
| 冲突 | queue(入队)/ lww_source / lww_target |
| 对账 | POST .../reconcile;双向运行中约每分钟自动一次 |
| 外部源 | POST .../ingest:C → B,再同步到 A |
| 配置 | 控制台「数据同步」页;可改线上 DSN |
配置与冲突持久化:data/dbsync/channels.json、conflicts.json(Docker:.runtime/dbsync)。
控制台用法
- 登录 → 数据同步 → 新建通道
- 本地 B:如
sqlite+file:./data/local.db,表名逗号分隔 - 线上 A:
mysql+user:pass@tcp(host:3306)/db?parseTime=true - 方向选 双向 → 测试连接 → 保存 → 启动
- 需要补漏时点 对账;C 数据走业务写 B 或调用 ingest API
API(需公司顶级权限「数据同步」/ 管理员)
| 方法 | 路径 |
|---|---|
| GET/POST | /api/v1/admin/sync/channels |
| GET/PUT/DELETE | /api/v1/admin/sync/channels/{id} |
| POST | /api/v1/admin/sync/test |
| POST | /api/v1/admin/sync/channels/{id}/prepare|start|stop |
| POST | /api/v1/admin/sync/channels/{id}/reconcile |
| POST | /api/v1/admin/sync/channels/{id}/ingest |
| GET | /api/v1/admin/sync/conflicts |
| POST | /api/v1/admin/sync/conflicts/{id}/resolve |
ingest 示例
POST /api/v1/admin/sync/channels/{id}/ingest
{
"table": "article",
"source": "excel",
"rows": [
{ "id": "c-001", "title": "来自 C" }
]
}
按主键 upsert 写入本地 B,触发器入 outbox,worker 再推到线上 A。
注意
- 两端业务表结构需兼容(同名列);主键默认
id,可用pk_columns覆盖。 - MySQL 需账号有建触发器权限。
- 密钥在 DSN 中;列表页会打码显示。
- 「实时」为亚秒级轮询 + 触发器,非 MySQL binlog CDC;同机延迟通常 <1s。
- 对账按主键集合补缺行,不做逐字段内容 diff;同 PK 内容冲突仍靠版本 / 冲突队列。