GeneralAndroid MinIO 传输增强完整方案

1. 目标

在当前 MinIO 大文件治理第一阶段已经完成的基础上,进一步增强上传/下载体验,使现有工作流支持:

  • 多文件并发上传
  • 多文件并发下载
  • 中断后重新执行时自动跳过已完成文件
  • 保持当前 manifest / sha256 / history / hook / CI / bootstrap 架构不被破坏

本方案强调:

  • 不重造底层 MinIO / S3 传输协议
  • 继续复用 mc 作为传输引擎
  • 由 Python 脚本负责任务调度、元数据更新与校验

2. 总体原则

2.1 继续复用 mc

不自己实现 S3/MinIO 分块协议。

原因:

  1. mc 已经成熟稳定
  2. mc cp 已具备 multipart 能力
  3. 传输可靠性远高于手写 Python 上传器
  4. 当前项目真正缺的是“调度和状态管理”,而不是传输协议本身

因此:

  • Python 负责任务编排
  • mc 负责真实传输

2.2 并发传输,串行落清单

这是整套方案最关键的设计约束。

可以并发的部分

  • 多个文件同时上传
  • 多个文件同时下载

不能并发的部分

以下文件必须统一串行写入:

  • assets/resource_manifest.json
  • assets/resource_manifest.md
  • assets/assets_sha256.txt
  • assets/asset_history.jsonl

原因:

  • 避免 manifest 写坏
  • 避免 history 顺序混乱
  • 避免“部分成功 / 部分失败”时 Git 元数据和 MinIO 状态不一致

因此整个流程必须遵守:

  1. 并发传输文件
  2. 收集所有成功 / 失败结果
  3. 再由主线程统一写 manifest / sha / history

3. 上传增强方案

3.1 当前状态

当前 scripts/upload_assets.py 是:

  • 单文件上传
  • 上传完成后立即写 manifest / sha / history

这个模式适合单文件维护,但不适合大批量并发导入。

3.2 推荐方案

保留 scripts/upload_assets.py 作为单文件稳定入口,同时新增一个专门的批量脚本:

  • scripts/batch_upload_assets.py

角色划分

  • upload_assets.py
    • 继续负责单文件新增 / 登记
    • 保持逻辑简单稳定
  • batch_upload_assets.py
    • 负责批量并发上传
    • 负责统一收口 manifest / sha / history

3.3 batch_upload_assets.py 的职责

  1. 接收一组待上传文件
  2. 对每个文件做预检查
  3. 并发调用 mc cp
  4. 收集每个文件的结果
  5. 成功项统一写:
    • resource_manifest.json
    • resource_manifest.md
    • assets_sha256.txt
    • asset_history.jsonl

3.4 建议参数

示例:

python3 scripts/batch_upload_assets.py --file-list assets/to_upload.txt --jobs 4

或:

python3 scripts/batch_upload_assets.py --category media --file-list assets/top40_media.txt --jobs 8

建议支持:

  • --jobs N
  • --continue-on-error
  • --dry-run
  • --alias
  • --overwrite
  • --category
  • --file-list

3.5 上传流程

第一步:预检查

对每个文件先做:

  • 文件存在检查
  • 大小读取
  • SHA256 计算
  • object name 生成
  • 远端对象冲突检查

第二步:并发上传

线程池中的每个 worker 只负责:

  • 执行 mc cp local -> remote
  • 上传返回成功后,再执行 mc stat <alias>/<bucket>/<object_key> 做远端存在性确认
  • 推荐默认至少做到:
    • mc stat 成功
    • 远端 size 与本地 size 一致
  • 只有通过远端确认的对象,才允许进入成功结果集合
  • 返回成功 / 失败结果

第三步:统一收口

主线程统一:

  • 只把“上传成功且远端确认成功”的条目写入 manifest
  • 只把“上传成功且远端确认成功”的条目写入 sha 文件
  • 只把“上传成功且远端确认成功”的条目写入 history
  • 输出失败列表

这一点非常关键:

  • 上传命令成功 ≠ 可以立即登记元数据
  • 必须先确认对象在服务器端真实可见,才能把它纳入 Git 中的主清单和历史记录

3.6 上传侧“断点续传”的定义

这里不实现自定义字节级断点续传。

当前定义为:

中断后重新执行同一批上传

脚本会:

  • 重新检查每个对象是否已存在
  • 已成功对象跳过
  • 未成功对象继续上传

对于当前仓库的大文件治理场景,这已经足够实用。


4. 下载增强方案

4.1 当前状态

当前 scripts/download_assets.py 是串行执行:

  • 每次选一个文件
  • 逐个执行 mc cp
  • 对大量文件恢复效率较低

4.2 推荐方案

在现有 scripts/download_assets.py 基础上增强,不额外拆脚本。

4.3 建议新增参数

  • --jobs N
  • --continue-on-error
  • --no-verify
  • --check-size-first

4.4 下载流程

第一步:选取待恢复文件

保留现有模式:

  • --source
  • --category
  • --all

第二步:本地预检查

每个文件先判断:

  • 本地不存在 → 需要下载
  • 本地存在且 sha256 匹配 → 跳过
  • 本地存在但不匹配 → 重新下载

第三步:并发下载

线程池中每个 worker 负责:

  • 创建父目录
  • 执行 mc cp remote -> local_target
  • 下载后校验 sha256

第四步:主线程汇总

输出汇总信息:

  • selected
  • skipped
  • downloaded
  • failed
  • checksum_failed

4.5 下载侧“断点续下”的定义

同样不做自定义 chunk checkpoint 文件管理。

当前定义为:

中断后重跑

  • 已完成且校验通过的文件跳过
  • 未完成或失败的文件继续
  • 本地损坏文件重新拉取

这能够满足:

  • bootstrap 中途失败后重跑
  • 外网不稳定环境反复恢复
  • 大批量下载恢复的断点继续能力

5. bootstrap 方案增强

5.1 当前状态

bootstrap_repo.sh 当前负责:

  • alias 检查
  • download_assets.py --all
  • 规则检查

5.2 增强目标

保留其作为统一入口,但增加:

  • 并发控制
  • 校验策略控制
  • continue-on-error 控制
  • 远程环境变量入口

5.3 建议环境变量

  • GENERALANDROID_MC_ALIAS
  • GENERALANDROID_MC_ENDPOINT
  • GENERALANDROID_MC_ACCESS_KEY
  • GENERALANDROID_MC_SECRET_KEY
  • GENERALANDROID_TRANSFER_JOBS
  • GENERALANDROID_VERIFY_DOWNLOADS
  • GENERALANDROID_CONTINUE_ON_ERROR

5.4 示例

GENERALANDROID_MC_ALIAS=uploadrw \
GENERALANDROID_MC_ENDPOINT=http://tx2.898311.xyz:9010 \
GENERALANDROID_MC_ACCESS_KEY=xxx \
GENERALANDROID_MC_SECRET_KEY=yyy \
GENERALANDROID_TRANSFER_JOBS=4 \
GENERALANDROID_CONTINUE_ON_ERROR=1 \
bash scripts/bootstrap_repo.sh

5.5 bootstrap 应输出的信息

执行时建议显示:

  • 当前 alias
  • endpoint(如适合显示)
  • jobs
  • verify 开关
  • continue-on-error 开关

让同事可以明确当前到底在用哪套恢复参数。


6. 外网 / 远程环境方案

6.1 当前事实

  • minio.898311.xyz 当前不是 MinIO API endpoint
  • 外网恢复主路径已明确为:
    • http://tx2.898311.xyz:9010

6.2 方案

脚本统一只认 alias。bootstrap 负责:

  • alias 已存在 → 直接使用
  • alias 不存在 → 用环境变量自动创建

因此远程同事不需要提前手工执行 mc alias set,只要提供环境变量即可。


7. manifest / sha / history 规则

7.1 主清单

  • assets/resource_manifest.json
  • 唯一主数据源

7.2 阅读视图

  • assets/resource_manifest.md
  • 派生文件
  • 不手工维护

7.3 校验文件

  • assets/assets_sha256.txt
  • 派生文件
  • 不手工维护

7.4 生命周期历史

  • assets/asset_history.jsonl
  • 只追加
  • 不回写旧记录

8. 历史记录策略

upload

记录:

  • action = upload
  • source_path
  • object_key
  • sha256
  • size
  • category
  • operator
  • time

update

记录:

  • action = update
  • source_path
  • previous_object_key
  • previous_sha256
  • previous_size
  • 新对象信息

remove

记录:

  • action = remove
  • source_path
  • object_key
  • sha256
  • size
  • keep_remote
  • remove_local

9. 明确不做的事情

9.1 不自己实现 S3 chunk protocol

不自己写:

  • multipart init
  • part upload
  • part list
  • part resume
  • complete upload

原因:

  • 复杂度高
  • 风险大
  • 当前项目收益不足以支撑这套自研成本

9.2 不把 manifest 并发写入

这是硬性禁止项。

9.3 不把单文件上传强行复杂化

upload_assets.py 继续保持稳定的单文件入口,不承担批量并发导入职责。


10. 需要改动的文件

核心脚本

  • scripts/download_assets.py
  • scripts/bootstrap_repo.sh
  • scripts/upload_assets.py
  • scripts/update_asset.py
  • 新增:scripts/batch_upload_assets.py

复用库

  • scripts/asset_manifest_lib.py

文档

  • README.md
  • main/blog/gitlab/minio_migration_plan.md
  • main/blog/gitlab/minio_migration_progress.md
  • 必要时:.claude/commands/clone-init.md

11. 验收标准

当前口径约束:

  • assets/resource_manifest.json 是主清单
  • assets/resource_manifest.md 是阅读视图
  • assets/assets_sha256.txt 是派生校验文件
  • assets/asset_history.jsonl 是历史记录
  • 多线程 = 多文件并发
  • 断点恢复 = 中断后重跑跳过已完成文件

11.1 单文件上传

  • upload_assets.py 仍可用
  • manifest 写入正确
  • history 写入正确

11.2 批量上传

  • batch_upload_assets.py --jobs 4
  • 多文件并发上传成功
  • 失败项不会污染成功项元数据
  • 成功项统一写入 manifest / sha / history

11.3 单文件下载

  • download_assets.py --source
  • 校验通过

11.4 并发下载

  • download_assets.py --all --jobs 4
  • 比串行快
  • 结果一致

11.5 中断后重跑

  • 中途 kill 掉
  • 再执行同一命令
  • 已完成文件跳过
  • 剩余文件继续

11.6 bootstrap

  • 本机 alias 成功
  • 外网 env 自动建 alias 成功
  • 下载链路成功

12. 详细验收步骤

12.1 单文件上传回归验收

目标:

  • 证明现有单文件上传在传输增强后仍然可用
  • 证明对象只有在远端确认存在后才会进入 manifest / sha / history

建议验证:

python3 scripts/upload_assets.py "assets/test_single_upload.txt" tools --alias local

通过标准:

  • MinIO 中对象存在
  • assets/resource_manifest.json 中有对应条目
  • assets/assets_sha256.txt 中有对应记录
  • assets/asset_history.jsonl 中有 upload 记录
  • 上传后必须经过 mc stat 确认远端对象存在,才允许落清单

12.2 批量上传验收

目标:

  • 证明多文件并发上传可用
  • 证明 manifest / sha / history 只会在远端确认成功后统一收口

建议验证:

python3 scripts/batch_upload_assets.py --file-list assets/test_upload_list.txt --jobs 4 --alias local

通过标准:

  • 成功项都能在 MinIO 中 mc stat 查到
  • manifest 中只出现“远端确认成功”的对象
  • asset_history.jsonl 中有对应 upload 记录
  • 失败项不会污染 manifest / sha / history

12.3 多线程下载验收

目标:

  • 证明 download_assets.py 支持多文件并发恢复

建议验证:

python3 scripts/download_assets.py --all --jobs 4 --alias local
python3 scripts/download_assets.py --all --jobs 8 --alias local

通过标准:

  • 文件都能恢复
  • SHA256 校验通过
  • 并发下载结果与串行模式一致

12.4 断点恢复验收

目标:

  • 证明下载中断后重新执行时会跳过已完成文件并继续剩余文件

建议验证:

  1. 执行批量恢复
  2. 中途手动终止
  3. 重新执行同一命令

通过标准:

  • 已完成文件被跳过
  • 未完成文件继续下载
  • 最终所有文件恢复完成
  • 不会重复全量重下已完成文件

12.5 bootstrap 验收

目标:

  • 证明 clone 后统一入口仍然可用
  • 证明远程 / 外网环境可以通过 env 自动建 alias 并恢复文件

本机验证:

bash scripts/bootstrap_repo.sh

远程 / 外网验证示例:

GENERALANDROID_MC_ALIAS=uploadrw \
GENERALANDROID_MC_ENDPOINT=http://tx2.898311.xyz:9010 \
GENERALANDROID_MC_ACCESS_KEY=xxx \
GENERALANDROID_MC_SECRET_KEY=yyy \
GENERALANDROID_TRANSFER_JOBS=4 \
GENERALANDROID_CONTINUE_ON_ERROR=1 \
bash scripts/bootstrap_repo.sh

通过标准:

  • alias 不存在时能自动创建
  • 下载脚本被正确调用
  • 并发参数能透传
  • 缺失文件能恢复

12.6 文档一致性验收

必须统一以下口径:

  • assets/resource_manifest.json 是主清单
  • assets/resource_manifest.md 是阅读视图
  • assets/assets_sha256.txt 是派生校验文件
  • assets/asset_history.jsonl 是历史记录
  • 多线程 = 多文件并发
  • 断点恢复 = 中断后重跑跳过已完成文件
  • 远程机器通过 env + bootstrap 接入
  • minio.898311.xyz 不是 MinIO API endpoint

通过标准:

  • README 和迁移文档不再出现与当前实现冲突的旧说法

11.7 当前验收进展(截至当前)

目前已经完成的验收:

  1. Python 脚本语法检查通过:
    • scripts/download_assets.py
    • scripts/upload_assets.py
    • scripts/update_asset.py
    • scripts/asset_manifest_lib.py
    • scripts/batch_upload_assets.py
  2. CLI 帮助检查通过:
    • download_assets.py --help
    • upload_assets.py --help
    • batch_upload_assets.py --help
  3. 失败路径检查通过:
    • download_assets.py --all --jobs 2 --continue-on-error --alias definitely-missing-alias
    • 已验证:
      • 已完成文件会 skip verified existing
      • 失败项会进入 summary
      • continue-on-error 行为成立
  4. 真实单文件上传回归验收通过:
    • 临时测试文件上传成功
    • mc stat 确认对象存在
    • manifest / sha / history 正常写入
    • 删除脚本清理成功
  5. 真实批量上传验收通过:
    • scripts/batch_upload_assets.py --batch-file ... --jobs 2 --alias local
    • 2 个测试文件并发上传成功
    • 输出 confirmed 并最终 persisted 2 confirmed uploads
    • manifest 中出现对应测试条目,随后已清理
  6. 多线程下载验收通过:
    • 对已迁移文件分别使用 --jobs 1 / 4 / 8 恢复成功
    • 不同并发参数下结果一致
  7. 断点恢复语义验收通过:
    • 删除部分本地大文件后执行 download_assets.py --all --jobs 2 --continue-on-error --alias local
    • 已完成文件大量 skip verified existing
    • 缺失文件自动恢复
    • 最终 summary: downloaded=3 skipped=59 failed=0

当前尚待补完的验收:

  1. 真实远程 / 外网 bootstrap 验收(如需最终外网闭环确认)
  2. 全文档最终一致性核对(当前正在进行并已修正关键冲突项)

结论:

  • 实现 Agent 已完成首轮落地并已合并到主工作区
  • 上传后远端确认再记账、批量并发上传、多线程下载、重跑跳过已完成文件这四条主线都已在本地验收通过
  • 当前处于“文档终验 + 远程最终验证收尾”阶段

11.8 最终通过条件

只有以下全部满足,才算本轮传输增强通过:

  1. 单文件上传回归通过
  2. 批量上传通过
  3. 多线程下载通过
  4. 断点恢复通过
  5. bootstrap 本机通过
  6. bootstrap 远程参数模式通过
  7. 文档一致性通过

12. 推荐实施顺序

第一步

先改:

  • scripts/download_assets.py
  • scripts/bootstrap_repo.sh

因为下载恢复是当前收益最大的。

第二步

新增:

  • scripts/batch_upload_assets.py

用于后续大批量上传。

第三步

补文档,统一写清:

  • JSON 是主清单
  • 多线程 = 多文件并发
  • 断点恢复 = 中断后重跑跳过已完成文件
  • 外网通过 env + bootstrap 接入

13. 最终结论

多线程上传下载可以做,而且是可靠的。

正确的方案不是自己重写协议,而是:

  • 继续复用 mc 做传输
  • Python 做并发调度
  • manifest / sha / history 串行收口
  • 断点恢复按“重跑跳过已完成文件”实现

这套方案既能满足当前仓库的大文件治理需求,又不会把现有稳定链路推翻。