- 将整体方案从 FTP 中转双端代理重构为单 prod-agent 的 Git 直连架构 - 重写主设计文档、详细设计文档和补充方案文档,统一新架构口径 - 新增 GitDirectSyncToolApplication 并调整 Maven 坐标与运行命名 - 清理 application.properties、SyncProperties 和 schema.sql 中的 FTP/ACK 遗留配置与表结构 - 将生产侧主流程收敛为 Git -> PROD 与 PROD -> Git 两条正式链路 - 新增 SyncManagementController,提供最近同步状态与失败任务查询接口 - 补充 ProdSyncCoordinatorIntegrationTest,覆盖两条主链路的最小集成测试与幂等行为 - 为主链路代码补充必要中文注释,提升可读性 - 删除旧架构源码主体并同步修正文档中的过期引用 - 完成编译与测试验证
487 lines
11 KiB
Markdown
487 lines
11 KiB
Markdown
# 基于 Git 直连的配置双向同步工具设计方案
|
||
|
||
## 1. 文档目的
|
||
|
||
本文档用于说明一套基于 Git 直连的配置同步工具设计方案,满足以下目标:
|
||
|
||
- 生产环境定时从开发 Git 拉取新配置,并调用生产 `push` 接口导入生产
|
||
- 生产环境定时从生产 `pull` 接口拉取当前配置,并回写到开发 Git
|
||
- 在 FTP 不再使用的前提下,简化整体架构、降低维护成本
|
||
|
||
## 2. 已知约束
|
||
|
||
### 2.1 技术约束
|
||
|
||
- JDK:`1.8`
|
||
- Spring Boot:`2.7.18`
|
||
- 轻量数据库:`H2` 或同类开源可商用数据库
|
||
- 其他依赖必须为开源可商用组件
|
||
|
||
### 2.2 网络与部署约束
|
||
|
||
- 生产环境可以访问开发 Git 仓库
|
||
- 生产环境需要能够调用生产系统 `push/pull` 接口
|
||
- FTP 不再使用
|
||
|
||
建议先确认一个关键前提:
|
||
|
||
- 生产环境是否对开发 Git 具备“读 + 写”权限
|
||
|
||
说明:
|
||
|
||
- 如果生产环境只能读取 Git,无法推送分支,那么“生产 -> 开发 Git”这条链路不能闭环
|
||
- 如果生产环境可以读取和推送 Git,则整套同步可以收敛为单点部署
|
||
|
||
## 3. 新架构结论
|
||
|
||
在新条件下,不再推荐“双端代理 + FTP 中转”。
|
||
|
||
推荐改为:
|
||
|
||
- **单端代理 + Git 直连 + 本地状态库**
|
||
|
||
即只在生产环境部署一套同步服务:
|
||
|
||
- `Sync-Agent-Prod`
|
||
|
||
它同时承担两类任务:
|
||
|
||
1. 从开发 Git 拉取配置,推送到生产
|
||
2. 从生产 `pull` 接口拉取配置,回写到开发 Git
|
||
|
||
整体结构如下:
|
||
|
||
```text
|
||
开发 Git 仓库 <----> 生产环境 Sync-Agent-Prod <----> 生产系统 push/pull 接口
|
||
```
|
||
|
||
## 4. 为什么要改成单端部署
|
||
|
||
新架构相比旧方案有明显优势:
|
||
|
||
- 去掉 FTP,中转链路减少一跳
|
||
- 去掉打包上传、轮询下载、ACK 回执等中间环节
|
||
- 部署节点减少为 1 个,运维更简单
|
||
- 故障点减少,排查路径更短
|
||
- 数据流更直接,状态一致性更容易控制
|
||
|
||
## 5. 总体方案
|
||
|
||
推荐在生产环境部署唯一同步实例:
|
||
|
||
- `Sync-Agent-Prod`
|
||
|
||
其职责如下:
|
||
|
||
- 拉取开发 Git 主配置分支
|
||
- 检查是否存在待下发的新版本
|
||
- 调用生产 `push` 接口导入配置
|
||
- 定时调用生产 `pull` 接口获取当前生产配置
|
||
- 将生产配置写回 Git 快照分支
|
||
- 使用 H2 记录同步状态、检查点、失败记录
|
||
|
||
## 6. 技术选型
|
||
|
||
| 分类 | 选型 | 说明 |
|
||
| --- | --- | --- |
|
||
| 运行时 | JDK 1.8 | 满足约束 |
|
||
| 框架 | Spring Boot 2.7.18 | 主体框架 |
|
||
| 调度 | Spring Scheduling | 实现定时任务 |
|
||
| 重试 | Spring Retry | 失败重试 |
|
||
| 数据库 | H2 File Mode | 持久化检查点与任务状态 |
|
||
| Git 操作 | JGit | 生产环境直接读写 Git |
|
||
| HTTP 调用 | RestTemplate | 调用生产 `push/pull` 接口 |
|
||
| JSON | Jackson | 标准序列化 |
|
||
| 日志 | SLF4J + Logback | 默认日志能力 |
|
||
|
||
说明:
|
||
|
||
- FTP 客户端依赖在新方案里已经不是核心能力
|
||
- 标准同步包、FTP 目录、ACK 文件等设计可以整体下线
|
||
|
||
## 7. 部署模式
|
||
|
||
### 7.1 推荐模式
|
||
|
||
推荐只部署:
|
||
|
||
- `prod-agent`
|
||
|
||
不再需要:
|
||
|
||
- `dev-agent`
|
||
- FTP 中转服务
|
||
|
||
### 7.2 运行位置
|
||
|
||
同步工具建议运行在生产环境可控节点上,要求:
|
||
|
||
- 能访问开发 Git
|
||
- 能访问生产 `push/pull` 接口
|
||
- 能持久化本地 H2 文件数据库
|
||
|
||
## 8. 两条核心链路
|
||
|
||
### 8.1 链路一:开发 Git -> 生产 push 接口
|
||
|
||
用途:
|
||
|
||
- 将开发配置分支中的新配置同步到生产环境
|
||
|
||
流程如下:
|
||
|
||
1. `Sync-Agent-Prod` 定时拉取开发 Git 指定分支
|
||
2. 获取最新提交版本号,例如 Git Commit ID
|
||
3. 判断该版本是否已成功同步
|
||
4. 如果未同步,则导出配置目录
|
||
5. 调用生产 `push` 接口导入配置
|
||
6. 成功后更新本地检查点和任务状态
|
||
|
||
建议时序图如下:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant G as Git(开发)
|
||
participant P as Sync-Agent-Prod
|
||
participant API as 生产Push接口
|
||
|
||
P->>G: 定时 pull config-dev-main
|
||
P->>P: 判断是否有新 commit
|
||
P->>P: 导出配置目录
|
||
P->>API: 调用 push 接口
|
||
API-->>P: 返回处理结果
|
||
P->>P: 更新 sync_task / checkpoint
|
||
```
|
||
|
||
### 8.2 链路二:生产 pull 接口 -> 开发 Git
|
||
|
||
用途:
|
||
|
||
- 将当前生产配置快照回写到开发 Git,用于镜像、审计、回溯
|
||
|
||
流程如下:
|
||
|
||
1. `Sync-Agent-Prod` 定时调用生产 `pull` 接口
|
||
2. 将返回结果标准化并计算内容哈希
|
||
3. 判断该版本或哈希是否已同步
|
||
4. 如果未同步,则切换到生产快照分支
|
||
5. 写入配置文件
|
||
6. 提交 commit 并 push 到开发 Git
|
||
7. 成功后更新本地检查点和任务状态
|
||
|
||
建议时序图如下:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant API as 生产Pull接口
|
||
participant P as Sync-Agent-Prod
|
||
participant G as Git(开发)
|
||
|
||
P->>API: 定时调用 pull 接口
|
||
API-->>P: 返回当前生产配置
|
||
P->>P: 标准化并计算 hash/version
|
||
P->>G: checkout config-prod-snapshot
|
||
P->>G: commit + push
|
||
P->>P: 更新 sync_task / checkpoint
|
||
```
|
||
|
||
## 9. Git 分支策略
|
||
|
||
这个设计点仍然必须保留。
|
||
|
||
不建议将“开发配置推生产”和“生产配置回写 Git”使用同一个 Git 分支,否则非常容易形成同步闭环。
|
||
|
||
推荐分支如下:
|
||
|
||
- `config-dev-main`:开发主配置分支
|
||
- `config-prod-snapshot`:生产配置镜像分支
|
||
|
||
同步规则:
|
||
|
||
- `Git -> PROD` 只消费 `config-dev-main`
|
||
- `PROD -> Git` 只写入 `config-prod-snapshot`
|
||
|
||
### 9.1 这样设计的价值
|
||
|
||
- 避免生产回写内容再次触发下发
|
||
- 生产快照不会污染开发主线
|
||
- 便于审计“生产当前实际配置”
|
||
|
||
### 9.2 机器人提交标记
|
||
|
||
建议同步工具统一使用固定 commit message 前缀,例如:
|
||
|
||
```text
|
||
sync(prod->git): traceId=xxx version=xxx
|
||
```
|
||
|
||
同时:
|
||
|
||
- `Git -> PROD` 扫描时只关注 `config-dev-main`
|
||
- 不读取 `config-prod-snapshot`
|
||
|
||
## 10. 状态库设计
|
||
|
||
新方案建议保留以下核心表:
|
||
|
||
### 10.1 `sync_checkpoint`
|
||
|
||
用于记录各方向最后一次成功同步的检查点。
|
||
|
||
关键字段:
|
||
|
||
- `direction`
|
||
- `last_success_version`
|
||
- `last_success_hash`
|
||
- `updated_at`
|
||
|
||
### 10.2 `sync_task`
|
||
|
||
用于记录每次同步任务生命周期。
|
||
|
||
关键字段:
|
||
|
||
- `trace_id`
|
||
- `direction`
|
||
- `source_version`
|
||
- `content_hash`
|
||
- `status`
|
||
- `retry_count`
|
||
- `error_msg`
|
||
|
||
### 10.3 `sync_ack`
|
||
|
||
在新架构下:
|
||
|
||
- 不再作为跨节点 ACK 使用
|
||
- 已退出当前主 schema
|
||
|
||
如果后续需要审计扩展,可以单独恢复为接口调用日志表。
|
||
|
||
## 11. 幂等设计
|
||
|
||
建议继续使用以下组合作为幂等键:
|
||
|
||
```text
|
||
direction + sourceVersion + contentHash
|
||
```
|
||
|
||
作用:
|
||
|
||
- 同一开发版本不会重复推生产
|
||
- 同一生产快照不会重复写 Git
|
||
|
||
## 12. 失败处理与补偿
|
||
|
||
### 12.1 自动重试
|
||
|
||
以下场景建议自动重试:
|
||
|
||
- Git pull 失败
|
||
- Git push 失败
|
||
- 生产 `push` 接口调用失败
|
||
- 生产 `pull` 接口调用失败
|
||
|
||
建议策略:
|
||
|
||
- 最大重试次数:`3 ~ 5`
|
||
- 指数退避:`30s / 60s / 120s`
|
||
|
||
### 12.2 失败落库
|
||
|
||
失败后建议:
|
||
|
||
- 更新 `sync_task.status=FAILED`
|
||
- 记录异常堆栈摘要
|
||
- 增加重试次数
|
||
- 保留最近一次成功检查点不变
|
||
|
||
### 12.3 人工补偿
|
||
|
||
后续可增加管理接口,支持:
|
||
|
||
- 按 `traceId` 重试
|
||
- 按方向重跑最近一次失败任务
|
||
- 查询最近同步记录
|
||
|
||
## 13. 安全设计
|
||
|
||
### 13.1 Git 访问建议
|
||
|
||
推荐使用:
|
||
|
||
- HTTPS + Token
|
||
|
||
或:
|
||
|
||
- SSH Deploy Key
|
||
|
||
### 13.2 权限建议
|
||
|
||
生产环境访问 Git 的账号建议采用最小权限原则:
|
||
|
||
- 对 `config-dev-main` 至少有读取权限
|
||
- 对 `config-prod-snapshot` 需要推送权限
|
||
|
||
更理想的做法:
|
||
|
||
- 使用专用机器人账号
|
||
- 对开发主分支启用保护
|
||
- 限制机器人只写快照分支
|
||
|
||
### 13.3 生产接口认证
|
||
|
||
生产 `push/pull` 接口建议使用:
|
||
|
||
- `Bearer Token`
|
||
- HTTPS
|
||
|
||
## 14. 项目结构建议
|
||
|
||
新架构下建议进一步简化模块职责:
|
||
|
||
```text
|
||
sync-tool
|
||
|- src/main/java
|
||
| |- config
|
||
| |- git
|
||
| |- job
|
||
| |- repository
|
||
| |- service
|
||
| |- web
|
||
|- src/main/resources
|
||
| |- application.properties
|
||
| |- application-prod-agent.properties
|
||
```
|
||
|
||
说明:
|
||
|
||
- `prod-agent` 是唯一正式运行角色
|
||
- `dev-agent` 与 FTP 相关模块已退出主运行面
|
||
|
||
## 15. 核心模块划分
|
||
|
||
建议保留并聚焦以下模块:
|
||
|
||
- `GitClientService`
|
||
- clone / pull / checkout / commit / push
|
||
- `ProdConfigApiService`
|
||
- 调用生产 `push/pull` 接口
|
||
- `SyncTaskService`
|
||
- 任务创建、状态变更、重试次数维护
|
||
- `CheckpointService`
|
||
- 成功检查点维护
|
||
- `ProdSyncCoordinator`
|
||
- 串联双向同步流程
|
||
- `JobScheduler`
|
||
- 定时调度
|
||
|
||
已退出主运行面:
|
||
|
||
- FTP 包上传下载逻辑
|
||
- FTP ACK 逻辑
|
||
- 双端代理运行路径
|
||
|
||
## 16. 定时任务建议
|
||
|
||
新架构下推荐保留两类核心任务:
|
||
|
||
### 16.1 `GitToProdSyncJob`
|
||
|
||
职责:
|
||
|
||
- 拉取 `config-dev-main`
|
||
- 判断是否有新 commit
|
||
- 调用生产 `push` 接口
|
||
|
||
### 16.2 `ProdToGitSnapshotJob`
|
||
|
||
职责:
|
||
|
||
- 调用生产 `pull` 接口
|
||
- 判断是否有新快照
|
||
- 提交到 `config-prod-snapshot`
|
||
|
||
可选任务:
|
||
|
||
- `RetryFailedTaskJob`
|
||
- `HealthCheckJob`
|
||
|
||
## 17. 一期 MVP 建议
|
||
|
||
建议重新按最小可交付版本收敛:
|
||
|
||
### 阶段 1:打通 Git -> 生产
|
||
|
||
- 生产环境直连开发 Git
|
||
- 实现 `config-dev-main` 拉取
|
||
- 实现生产 `push` 接口调用
|
||
- 落库记录同步状态
|
||
|
||
### 阶段 2:打通 生产 -> Git
|
||
|
||
- 接入生产 `pull` 接口
|
||
- 回写 `config-prod-snapshot`
|
||
- 实现 commit + push
|
||
|
||
### 阶段 3:增强稳定性
|
||
|
||
- 补充重试
|
||
- 补充管理接口
|
||
- 补充告警与审计日志
|
||
|
||
## 18. 风险与注意事项
|
||
|
||
### 18.1 最大风险:Git 写权限不足
|
||
|
||
如果生产环境对开发 Git 没有推送权限,则“生产 -> Git”链路无法完成。
|
||
|
||
解决方案:
|
||
|
||
- 申请机器人账号
|
||
- 或将“生产回写 Git”改成调用开发侧服务接口
|
||
|
||
### 18.2 最大风险:双向同步闭环
|
||
|
||
如果生产回写到了开发主分支,会再次触发下发。
|
||
|
||
规避措施:
|
||
|
||
- 使用独立快照分支
|
||
- 不扫描快照分支
|
||
- 使用幂等键和机器人提交标记
|
||
|
||
### 18.3 最大风险:生产直连开发 Git 的安全边界
|
||
|
||
需要明确:
|
||
|
||
- 网络访问是否合规
|
||
- Git 账号权限是否受控
|
||
- Token 或 SSH Key 是否可轮换
|
||
|
||
## 19. 结论
|
||
|
||
在“生产环境可以直接访问开发 Git,FTP 不再需要”的前提下,推荐将旧方案调整为:
|
||
|
||
- **生产环境单点部署**
|
||
- **Git 直连**
|
||
- **保留生产 `push/pull` 接口**
|
||
- **保留 H2 状态库**
|
||
|
||
这是比原来 FTP 中转更合适的方案,原因是:
|
||
|
||
- 架构更简单
|
||
- 故障点更少
|
||
- 链路更短
|
||
- 运维成本更低
|
||
|
||
## 20. 下一步建议
|
||
|
||
下一步建议按下面顺序推进:
|
||
|
||
1. 先确认生产环境对开发 Git 是否具备推送权限
|
||
2. 确认生产 `push/pull` 接口最终协议
|
||
3. 删除退役标记文件 `application-dev-agent.properties`
|
||
4. 将工程命名中残留的 `ftp` 语义继续清理
|
||
5. 补充新的 `application-prod-agent.properties` 配置说明
|