分包增量更新工程:9 个子包独立版本号与镜像缓存不失效

简介: 做过客户端分发的同学知道痛点:发一个新版本,用户要下载整个安装包重装。yyzTools 的安装包约 150MB(含 FFmpeg、OCR 模型等),每次更新都让用户重下不可接受。解法是分包 + 增量更新:把产物拆成 9 个独立版本号的子包,只下变更的。本文复盘这套发版工程:分包策略、版本模型、镜像分发、缓存不失效约束。适合做客户端分发、CI/CD、版本工程的读者参考。

做过客户端分发的同学知道痛点:发一个新版本,用户要下载整个安装包重装。yyzTools 的安装包约 150MB(含 FFmpeg、OCR 模型等),每次更新都让用户重下不可接受。解法是分包 + 增量更新:把产物拆成 9 个独立版本号的子包,只下变更的。本文复盘这套发版工程:分包策略、版本模型、镜像分发、缓存不失效约束。适合做客户端分发、CI/CD、版本工程的读者参考。

一、为什么要分包

yyzTools 的产物构成(约 150MB):

  • 主程序(C++ 编译的 exe)
  • 前端页面(Vite 构建的 web 资源)
  • 命令模块库(379 个 .zenmod)
  • 第三方引擎(FFmpeg、ImageMagick、pdfcpu、Aria2、OpenSSL、7-Zip)
  • OCR 模型(RapidOCR 的 ONNX 模型)
  • 文件搜索(Everything)
  • 动态壁纸(独立 exe)

如果打成一个大包,每次发版用户重下 150MB。实际发版经常只改了前端或某个模块,主程序和 FFmpeg 没动--让用户为一次前端 hotfix 重下 150MB 是浪费。

分包的收益很直接:只下有变化的子包,未变的沿用历史版本。一次只改前端的发版,用户只下几 MB 的前端包,其余 8 个子包不动。

二、版本模型:release 与子包版本解耦

yyzTools 的版本模型有两个层次,这是整套工程的关键:

2.1 release:发布身份号

release 字段(当前 1.0.3.1300)是对外发布身份

  • GitHub release tag 用它
  • 安装包文件名用它(yyzTools-setup-1.0.3.1300.exe
  • 更新日志版本号用它

每次发版必递增 release。用户看到的「版本号」就是这个。

2.2 子包版本:各自独立

9 个子包各有独立版本号,没改不升

{
  "release": "1.0.3.1300",
  "main":       "1.0.3.1300",   // 主程序包,本次变更
  "web":        "1.0.3.1300",   // 前端,本次变更
  "modules":    "1.0.3.1300",   // 命令模块,本次变更
  "yyztools":   "1.0.3.1300",
  "ffmpeg":     "1.0.0.1000",   // 未变,沿用
  "rapidocr":   "1.0.0.1000",   // 未变
  "tools":      "1.0.0.1000",   // 未变(第三方引擎集合)
  "everything": "1.0.0.1000",   // 未变
  "wallpaper":  "1.0.0.1000"    // 未变
}

关键设计:main 只是主程序子包的版本,不再当发布号。以前 main 和 release 耦合,导致每次发版都要 bump main(哪怕主程序没改)来对齐 release。解耦后,main 没改就不升,release 独立递增。

这次发版(1.0.3.1300)实际变更的只有 4 个子包(main/web/modules/yyztools),其余 5 个未变。用户只下这 4 个的增量。

三、update.json 的生成:url 派生自各包版本号

update.json 是客户端检查更新的清单。关键约束:每个子包的 url 派生自「该子包自己的版本号」,不是统一绑 release

# 变更包(版本 = release):
https://.../v1.0.3.1300/main.7z
https://.../v1.0.3.1300/web.7z
# 未变包(版本 = 历史版本):
https://.../v1.0.0.1000/ffmpeg.7z
https://.../v1.0.0.1000/rapidocr.7z

这个设计的妙处:未变包的 url 指向历史 release 目录,不动。镜像缓存命中,下载快。如果统一绑 release,未变包也要挪到新目录,缓存全失效。

gen_update_json.ps1 负责生成,每个包的 url 拼成 v<该包版本号>/<文件名>

四、打包与上传:未变包不重传

build_app.bat 的打包逻辑:

  • 遍历 9 个子包,对每个判断版本号是否 = 本次 release
  • 变更包(版本号 = release):打到 v<release>/ 目录,重新打包上传
  • 未变包(版本号 < release):命中历史目录直接 [SKIP],不重打

release_app.bat 的上传逻辑:

  • 只遍历 v<release>/ 里实际存在的 .7z(即变更包)+ installer
  • 未变包沿用历史 release 的 asset,不重传
  • gh release view 预检查,release 已存在直接 [SKIP],绝不覆盖

「绝不覆盖」是硬约束:GitHub release asset 一旦覆盖,CDN/镜像缓存会失效,全球用户重新下载,流量浪费且变慢。所以发版是「只加不改」--新版本新建 release,老版本的 asset 保持不动供历史引用。

五、两条硬约束(违反则 url 404)

这套分包分发有两条硬约束,违反任意一条就会导致客户端下载 404:

约束一:变更包版本号必须 = release

变更包如果不把版本号设为 release,gen_update_json.ps1 会把它打进 v<自己版本>/ 目录,但 release_app.bat 遍历 v<release>/ 上传--找不到这个包,漏传。客户端按 update.json 的 url 去 v<release>/ 找,404。

所以变更包必须显式 bump 版本号 = release。

约束二:未变包的版本号历史上必须作为 release 发过

未变包的 url 指向 v<历史版本>/,这个目录必须在历史上作为某次 release tag 上传过。解耦前每次全量传,所有历史 release(如 v1.0.0.1000)含全部 9 个 asset,天然满足。全新包首次需跟某次 release 对齐完整发一次,之后才能作为「未变包」被引用。

这两条约束的本质是:update.json 的每个 url 都要真实存在。版本号和目录的映射是契约,违约就 404。

六、镜像分发:9 源容灾

yyzTools 在国内分发,GitHub raw 直连慢。解法是多镜像源 + 客户端自动选

update.json 的来源有 9 个镜像(jsdelivr 4 个、raw github 3 个、国内代理 3 个),客户端依次尝试,取第一个可达的。下载 .7z 资产时,也有镜像列表(ghfast.top、ghproxy.com、gh-proxy.com 等代理)做容灾。

工程要点:

  • 镜像只代理 raw / release asset,不改文件--所有镜像指向同一份 GitHub 内容,保证一致性。
  • 客户端有 fallback 逻辑--一个镜像挂了自动切下一个,不卡死。
  • 镜像缓存依赖「绝不覆盖」约束--只要 release asset 不覆盖,各镜像缓存一致有效。

这套是国内分发的常见模式,yyzTools 的实现是 9 源 + 客户端自动容灾。

七、更新流程的进程管理

客户端更新不只是下载,还要替换运行中的文件。yyzTools 的处理:

  • packageKillProcesses:每个子包声明更新时要杀的进程。比如更新 yyztools 包要杀壁纸、录屏、浏览器等辅助进程;更新 tools 包要杀 aria2c/7z/openssl/pdfcpu/magick/gswin64c 等第三方进程;更新 everything 包需要管理员权限杀 Everything.exe。
  • 分包独立更新:只更新变更包,只杀受影响的进程。改前端只杀 web 相关,不影响 FFmpeg 进程。
  • 更新后再拉起:主程序负责协调杀进程 -> 替换文件 -> 重启受影响进程。

这块设计让「更新某个子包」的影响面可控,不会因为改一个模块动整个进程树。

八、和传统安装包分发的对比

维度 传统整包重装 分包增量(yyzTools)
用户下载量 整个安装包(150MB) 只下变更包(几 MB~几十 MB)
版本模型 单一版本号 release + 子包独立版本
缓存友好 否(每次新包) 是(未变包 url 不变)
镜像容灾 难(大文件单点) 易(小包多镜像)
进程影响 全量重启 只杀受影响进程
工程复杂度 高(版本契约 + url 派生 + 杀进程表)

核心权衡:用发版工程的复杂度(版本契约、url 派生、杀进程表、镜像列表),换用户的下载量和镜像缓存命中率。对高频迭代 + 大体积产物的客户端,这个权衡划算。

九、对后端版本工程的启示

yyzTools 是客户端样本,但它的版本模型对后端微服务分发有对应:

  1. 服务版本与发布身份解耦:微服务各有版本号,发布身份(release)独立。不要为了「发版」去 bump 一个没变的服务。
  2. 资源 url 派生自服务版本:镜像 / 构建产物的 url 指向「该服务自己的版本」,不统一绑发布号。这样未变服务的镜像缓存不失效。
  3. 绝不覆盖:已发布的产物不动,新版本新建。CDN 缓存才稳定。
  4. 变更面控制:更新某个服务只动它的依赖进程,不全量重启。

这套「release 身份 + 子包独立版本 + url 派生 + 不覆盖 + 变更面控制」的模式,是版本工程的通用思路,不止用于客户端。

十、小结

分包增量更新的核心:把产物拆成独立版本号的子包,未变不重传,url 派生自各包版本号保证镜像缓存不失效,变更面可控只杀受影响进程

代价是发版工程的复杂度--版本契约、url 派生规则、杀进程表、镜像列表、两条硬约束。收益是用户下载量从 150MB 降到几 MB、镜像缓存命中、发版对运行进程影响最小。

对大体积 + 高频迭代 + 跨地域分发的客户端,这套工程是必要的。核心判断标准:用户为一次更新要下多少、镜像缓存命中率多高、更新影响面多大。整包重装在这三点上都差,分包增量都好,付的是工程复杂度,这是值得的。

项目地址yyztools.com 发版工程:9 子包独立版本 · 未变不重传 · 9 源镜像容灾 · 永久免费

目录
相关文章
|
5天前
|
缓存 JSON 数据格式
多进程架构的 IPC 选型:从命令行参数到窗口消息
做客户端/桌面端架构的同学,多进程是绕不开的话题:主进程 + 辅助进程,怎么通信?后端微服务之间走 RPC,但客户端进程间不能随便上 RPC(重、要起服务、要端口)。本文复盘 yyzTools(一套 Windows 桌面效率工具集)的多进程 IPC 选型,看它如何用 4 种不同量级的通信方式(命令行参数 / 共享配置 / 窗口消息 / stdout)搭起一套多进程编排,以及每种方式的适用边界。适合做客户端架构、多进程编排、Windows 系统编程的读者参考。
41 0
|
7天前
|
JSON JavaScript 开发工具
桌面应用扩展 SDK 的架构模式:声明式宿主、能力全开与信任模型
桌面应用做开放扩展,业界有三条成熟路线:沙箱插件(VS Code、浏览器扩展)、脚本沙箱(uTools/ Alfred)、配置驱动(Rainmeter 风格)。本文以 yyzTools 开放的模块 SDK 为第四种样本——声明式宿主 + JS 桥 + 无沙箱信任模型——对比四种模式的架构要素与适用边界,供做桌面端架构、扩展体系设计的读者参考。
41 0
|
15天前
|
存储 文字识别 安全
数据不出域:本地优先架构怎么做企业级数据合规
本文以桌面工具yyzTools为例,剖析「本地优先」架构如何践行数据合规:剪贴板、OCR、文件索引等敏感数据全程本地处理不出机;翻译等必要联网功能由用户自主选择服务方,去向透明可控;无账号、无遥测,切断身份关联。为后端与隐私合规工程师提供可落地的数据分层实践样本。(239字)
26 0
|
19天前
|
算法 安全 前端开发
国密改造落地实战:用 OpenSSL 子进程透传,零成本支持 sm2/sm3/sm4
本文介绍yyzTools桌面工具如何通过“子进程透传算法名”实现国密(SM2/SM3/SM4)零编译改造:不修改主程序二进制,仅替换内置openssl.exe即可支持国密,一天内快速落地。兼顾升级便捷、审计透明与国密/国际算法统一,代价仅为单次计算性能损耗,适合等保、密评等低频高合规场景。
116 0
|
6月前
|
人工智能 弹性计算 安全
快来养小龙虾!阿里云OpenClaw一键部署,两步解锁专属AI助理!
阿里云推出OpenClaw(小龙虾)——开源本地优先AI智能体,无需写代码、不配环境,两步极速部署!支持浏览器/邮件/文件等操作,数据留本地更安全,兼容通义千问、GPT等多模型,已打通钉钉、飞书等主流IM,真正实现“聊天即行动”。
6406 10
IntelliJ IDEA 控制台如何修改不同级别的日志颜色
IntelliJ IDEA 控制台如何修改不同级别的日志颜色
2467 0
|
5天前
|
人工智能 运维 BI
阿里云千问办公QwenWork深度解析:基于Qwen3.8,六大核心能力重构企业全自动化工作流与计费选型指南
传统AI办公工具大多停留在对话问答、文档摘要、简单文案生成层面,只能完成单点碎片化任务,无法自主拆解复杂业务流程,很难串联多工具、多文档、外部业务系统完成端到端完整工作交付。很多企业在落地AI办公的时候,需要组合多款不同工具,来回切换界面,手动复制粘贴中间结果,智能化改造落地门槛居高不下。千问办公QwenWork是整合多款智能体产品能力打造的一体化企业办公智能体平台,底层基座依托Qwen3.8大模型,打通桌面端Agent、云端Agent、企业协同Agent三种运行形态,不再局限简单问答,接收业务目标之后自主拆解任务步骤,调用各类工具,处理文档、表格、浏览器自动化、数据查询,直接输出可交付的办公
1466 0
|
5天前
|
人工智能 自然语言处理 安全
阿里云AI数智鉴密:AI 生成内容如何拿到一张"防篡改的身份证"
隐形水印 + C2PA签名:让AI生成内容“持证上岗”。
1127 0
|
14天前
|
人工智能 自然语言处理 安全
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
本文聚焦阿里云2026年推出的三款自研AI办公产品,清晰拆解千问办公、Qoder Teams、Qoder CN的差异化定位与能力边界:千问办公主打职场全场景提效,支持自然语言指令一键完成PPT生成、数据分析等高频办公任务;Qoder Teams面向程序员团队,深度整合AI代码生成、团队协同与企业知识库能力;Qoder CN则专为金融、政务等强合规场景打造,实现数据不出境与VPC私有化部署。文章同步给出分场景选型指南与最新活动定价,帮助不同类型的企业按需组合产品,实现业务岗、研发岗与强合规场景的AI能力全覆盖。
3765 4
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考