FtpTool/docs/ftp-sync-tool-design.md
dark 0162117ae4 refactor: 收敛为 Git 直连同步架构并完成收尾
- 将整体方案从 FTP 中转双端代理重构为单 prod-agent 的 Git 直连架构
- 重写主设计文档、详细设计文档和补充方案文档,统一新架构口径
- 新增 GitDirectSyncToolApplication 并调整 Maven 坐标与运行命名
- 清理 application.properties、SyncProperties 和 schema.sql 中的 FTP/ACK 遗留配置与表结构
- 将生产侧主流程收敛为 Git -> PROD 与 PROD -> Git 两条正式链路
- 新增 SyncManagementController,提供最近同步状态与失败任务查询接口
- 补充 ProdSyncCoordinatorIntegrationTest,覆盖两条主链路的最小集成测试与幂等行为
- 为主链路代码补充必要中文注释,提升可读性
- 删除旧架构源码主体并同步修正文档中的过期引用
- 完成编译与测试验证
2026-04-22 13:51:27 +08:00

487 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 基于 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. 结论
在“生产环境可以直接访问开发 GitFTP 不再需要”的前提下,推荐将旧方案调整为:
- **生产环境单点部署**
- **Git 直连**
- **保留生产 `push/pull` 接口**
- **保留 H2 状态库**
这是比原来 FTP 中转更合适的方案,原因是:
- 架构更简单
- 故障点更少
- 链路更短
- 运维成本更低
## 20. 下一步建议
下一步建议按下面顺序推进:
1. 先确认生产环境对开发 Git 是否具备推送权限
2. 确认生产 `push/pull` 接口最终协议
3. 删除退役标记文件 `application-dev-agent.properties`
4. 将工程命名中残留的 `ftp` 语义继续清理
5. 补充新的 `application-prod-agent.properties` 配置说明