12 KiB
Data Engine 通用数据同步引擎 - 使用文档
一、概述
本系统是一个配置驱动的通用数据同步引擎,核心思想是:平台管理 + 接口管理。
您只需要通过 API 维护好平台和接口的配置信息(认证方式、请求参数、响应解析、目标表结构),系统就会自动:
- 创建目标表(根据
table_definition自动建表) - 拉取数据(分页请求、多步骤请求、并发处理)
- 写入数据库(批量 upsert)
- 增量同步(通过
filtering按最后修改时间过滤) - 自动调度(按配置的时间间隔循环执行)
- 补偿重试(失败的同步任务自动重试,退避递增)
不需要为每个平台写一行业务代码。
二、数据库初始化
2.1 核心表
首次使用需执行 sql/init_core_tables.sql,创建以下 4 张表:
| 表名 | 说明 |
|---|---|
api_datasource_platform |
数据源平台配置(认证信息、限流等) |
api_interface |
接口配置(URL、请求参数、表结构等) |
sync_task_log |
同步任务日志(记录状态,用于补偿) |
sync_tracker |
同步跟踪(记录每个接口的最后同步时间) |
2.2 初始化数据
执行 sql/seed_data.sql 创建腾讯广告平台+接口配置。如需清空重来:
ALTER SEQUENCE api_datasource_platform_id_seq RESTART WITH 1;
ALTER SEQUENCE api_interface_id_seq RESTART WITH 1;
DELETE FROM api_interface;
DELETE FROM api_datasource_platform;
\i sql/seed_data.sql
三、配置说明
3.1 平台管理 (api_datasource_platform)
| 字段 | 说明 | 示例 |
|---|---|---|
platform_code |
平台编码(唯一) | tencent |
platform_name |
平台名称 | 腾讯广告 |
api_base_url |
API 基础地址 | https://api.e.qq.com/v3.0 |
auth_type |
认证类型 | OAUTH2 / TOKEN / API_KEY / BASIC |
token |
access_token | xxxxx |
client_id / client_secret |
OAuth2 凭证 | xxxxx |
auth_config |
自定义认证配置(JSONB) | 详见 3.1.1 |
3.1.1 auth_config 字段详解
{
"token_in_query": true, // token 放在 URL 查询参数
"query_key": "access_token", // 参数名,默认 "access_token"
"header_name": "Authorization", // token 放请求头时的头名
"header_format": "Bearer {token}",
"extra_query_params": { // 额外查询参数
"timestamp": "{timestamp}", // {timestamp} 自动替换为当前时间戳
"nonce": "{nonce}" // {nonce} 自动替换为随机字符串
}
}
3.2 接口管理 (api_interface)
| 字段 | 说明 | 示例 |
|---|---|---|
platform_id |
所属平台 ID | 1 |
name / code |
接口名称 / 唯一编码 | 图片素材 / image |
url |
接口地址(相对路径) | /images/get |
method |
请求方法 | GET / POST |
request_config |
请求配置(JSONB) | 详见 3.2.1 |
response_config |
响应配置(JSONB) | 详见 3.2.2 |
table_definition |
表结构定义(JSONB) | 详见 3.3 |
3.2.1 request_config 字段详解
{
"parameters_location": "query", // 参数位置: "query"(URL) / "body"(默认)
"page": 1,
"page_size": 100,
"page_param": "page", // 分页参数名(自定义)
"page_size_param": "page_size",
"time_field": "last_modified_time", // 增量时间字段
"fields": ["field1", "field2"], // 请求字段(如音频的 fields)
"prefetch": { ... } // 预取配置(见下文)
}
parameters_location 说明:
- 未设置或
"body"→ 参数放在 JSON body 中(POST 请求) "query"→ 参数放在 URL 查询字符串中(GET 请求用)- 当
method=GET时,即使不设置也默认走 query
预取(prefetch):某些接口需要"先拿列表→遍历每个元素查数据"(如先拉账户列表,再遍历拉图片)。
"prefetch": {
"url": "/advertiser/get", // 预取接口地址
"method": "GET",
"response_path": "data.list", // 从响应中取值路径
"target_param": "account_id", // 注入主请求的参数名
"value_field": "account_id" // 从预取结果取哪个字段
}
并发处理:有 prefetch 的接口会并发处理每个实体,并发数由 config.yml 的 sync.concurrency 控制。
增量同步:配置了 time_field 的接口,增量同步时会自动生成 filtering 参数:
{"field": "last_modified_time", "operator": "GREATER_EQUALS", "values": ["<timestamp>"]}
3.2.2 response_config 字段详解
系统默认解析的响应格式:
{ "code": 0, "message": "success", "data": { "list": [...], "page_info": { "total_page": N } } }
可通过 response_config 自定义数据路径:
{ "list_path": "data.list" }
3.3 table_definition 字段详解
{
"table_name": "tencent_image",
"columns": [
{ "name": "image_id", "type": "VARCHAR(100)", "comment": "图片ID" },
{ "name": "account_id", "type": "BIGINT", "comment": "账户ID" }
],
"conflict_keys": ["image_id", "account_id"]
}
自动添加的列(无需声明):
| 列名 | 类型 | 说明 |
|---|---|---|
id |
BIGSERIAL PRIMARY KEY | 自增主键 |
tenant_id |
BIGINT | 租户 ID |
creator |
VARCHAR(64) | 创建人 |
created_at |
TIMESTAMPTZ | 创建时间 |
updater |
VARCHAR(64) | 更新人 |
updated_at |
TIMESTAMPTZ | 更新时间 |
deleted_at |
TIMESTAMPTZ | 软删除 |
raw_data |
JSONB | 原始响应数据 |
四、API 接口
基础地址:http://localhost:3002
4.1 平台管理
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/datasourcePlatform/createDatasourcePlatform |
创建平台 |
| GET | /api/datasourcePlatform/listDatasourcePlatforms |
列表 |
| GET | /api/datasourcePlatform/getDatasourcePlatform |
详情 |
| GET | /api/datasourcePlatform/getPlatformByCode |
按编码查 |
| PUT | /api/datasourcePlatform/updateDatasourcePlatform |
更新 |
| PUT | /api/datasourcePlatform/updateDatasourcePlatformStatus |
更新状态 |
| DELETE | /api/datasourcePlatform/deleteDatasourcePlatform |
删除 |
| GET | /api/datasourcePlatform/getPlatformStatistics |
统计 |
4.2 接口管理
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/apiInterface/createApiInterface |
创建接口 |
| GET | /api/apiInterface/listApiInterfaces |
列表 |
| GET | /api/apiInterface/getApiInterface |
详情 |
| PUT | /api/apiInterface/updateApiInterface |
更新 |
| PUT | /api/apiInterface/updateApiInterfaceStatus |
更新状态 |
| DELETE | /api/apiInterface/deleteApiInterface |
删除 |
4.3 同步控制
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/sync/ctrl/trigger |
触发同步 |
| GET | /api/sync/ctrl/config |
查询配置 |
触发同步示例:
curl -X POST http://localhost:3002/api/sync/ctrl/trigger \
-H 'Content-Type: application/json' \
-d '{"platformCode":"tencent","interfaceCode":"image","fullSync":true}'
响应:
{
"success": true,
"tableName": "tencent_image",
"totalRows": 1500,
"insertedRows": 1450,
"duration": "12.3s"
}
五、配置文件 (config.yml)
sync:
page_size: 100 # 每次分页请求条数
concurrency: 5 # 并发处理数(prefetch 遍历实体时)
retry_count: 3 # 最大重试次数
sync_interval_minutes: 60 # 自动同步间隔(分钟)
compensation_interval_seconds: 300 # 补偿扫描间隔(秒)
auto_sync_enabled: true # 是否启用自动同步
tencent:
oauth:
client_id: "1112038234"
client_secret: "GxyjXFbZAs5dnsNQ"
access_token: "4bacfc7c9b0a31f70ec0eb4771f8b542"
refresh_token: "d15b37363a42449026d337708516e95e"
六、自动同步机制
6.1 启动流程
- 服务启动 →
InitAndStartAutoSync在 goroutine 中启动调度器 - 自动扫描所有 ACTIVE 平台下有
table_definition的接口 - 无
sync_tracker记录 → 全量拉取;有记录 → 增量拉取
6.2 增量同步原理
sync_tracker表记录每个接口的最后同步时间- 配置了
time_field的接口,增量时生成filtering=[{"field":"last_modified_time","operator":"GREATER_EQUALS","values":["<时间戳>"]}] - 不支持时间过滤的接口(如 audio/advertiser)每次全量,
ON CONFLICT去重
6.3 异常中断恢复
- 同步开始前写
sync_tracker.sync_status='running' - 同步完成后写
'success' - 重启检测到
'running'→ 日志告警 → 重新全量
七、补偿机制
7.1 工作原理
- 同步失败 → 自动写入
sync_task_log(status=failed) - 补偿调度器(随主服务自动启动)每 N 秒扫描 failed 记录
- 对未达最大重试次数的任务,调用
SyncByConfig重试 - 重试间隔按退避策略递增:5min → 15min → 30min → 60min → 120min
- 达最大次数 → 标记
manual_review,等待人工介入
7.2 配置
sync:
compensation_interval_seconds: 300 # 扫描间隔
retry_count: 3 # 最大重试次数
补偿调度器随主服务自动启动,无需手动运行。
八、当前已配置接口(腾讯广告)
| 接口编码 | 名称 | 方法+路径 | 类型 | 增量 |
|---|---|---|---|---|
account_relation |
账户列表 | GET /advertiser/get |
单接口分页 | 不支持 |
image |
图片素材 | GET /images/get |
prefetch 遍历账户 | ✅ last_modified_time |
video |
视频素材 | GET /videos/get |
prefetch 遍历账户 | ✅ last_modified_time |
audio |
音频素材 | POST /muse_audios/get |
单接口 POST | 不支持 |
三个素材表自动包含 verify_status DEFAULT 'PENDING'、verified_at、verified_by 校验字段。
图片/视频同步流程
SyncByConfig("tencent", "image")
├── ① 预取: 分页拉取 /advertiser/get → 774 个 account_id
│ 数据同时存入 tencent_account_relation 表
├── ② 并发遍历账户(config.yml concurrency=5)
│ 每个 account_id → GET /images/get?account_id=xxx&page=1&page_size=100
│ 自动补充 filtering(增量时)
│ 结果 upsert 到 tencent_image
└── ③ 更新 sync_tracker 记录同步时间
音频同步流程
单次 POST /muse_audios/get → 分页拉全量 → upsert 到 tencent_audio
九、快速开始
# 1. 建表
psql -h localhost -U postgres -d data-engine -f sql/init_core_tables.sql
# 2. 初始化数据
psql -h localhost -U postgres -d data-engine -f sql/seed_data.sql
# 3. 启动
go run main.go
启动后自动同步和补偿调度器自动运行。也可手动触发:
# 触发图片全量同步
curl -X POST http://localhost:3002/api/sync/ctrl/trigger \
-H 'Content-Type: application/json' \
-d '{"platformCode":"tencent","interfaceCode":"image","fullSync":true}'
十、常见问题
Q: 响应格式不符合 {code: 0, data: {list: [...]}} 怎么办?
修改 dynamic_sync.go 的 parseResp 函数。
Q: 如何添加新平台?
调用平台管理 API 创建平台 → 调用接口管理 API 创建接口(带 table_definition)→ 系统自动建表并同步。
Q: prefetch 的响应格式要求?
必须是 JSON,response_path 指向一个数组。如 response_path: "data.list" 从 data.list 取值。
Q: 如何排查同步失败?
GET /api/sync/ctrl/config?platformCode=xxx查看配置- 查询
sync_task_log表看失败记录 - 补偿调度器会自动重试,日志会打印重试过程