网易首页 > 网易号 > 正文 申请入驻

SOW: 论母猪的产后护理

0
分享至

今天老冯来和大家聊一聊《母猪的产后护理》。俺做的新开源项目 —— SOW,翻译成中文,就是老母猪的意思。

做一个 PostgreSQL 发行版,最折磨人的往往不是把软件编译出来。而是收拾编译出来的东西。

Pigsty 要为多个 Linux 发行版、多个 CPU 架构、多个 PostgreSQL 大版本维护成百上千个组件。不同组合一路展开,最终落到仓库里的制品超过十万个:RPM、DEB、索引、签名、校验和、快照,还有一堆为了兼容包管理器而存在的元数据。

用户看到的只是 apt installdnf install。维护者看到的却是另一幅画面:你只更新了一个包,却必须保证另外九万九千九百九十九个对象没被误删;你只改了一份索引,却必须保证全球用户不会在切换瞬间读到一半新、一半旧的仓库。当仓库小的时候,这些事都像脚本题。仓库大到十万个制品之后,它突然变成了一道数据库题、分布式系统题,还是一道供应链安全题。

所以我写了 SOW[1] —— 一个用 Go 编写的自包含 APT/YUM 软件仓库管理器。


如果你只是想把一目录 RPM / DEB 变成可用仓库,一条命令就够了:

sow create /www/pigsty

如果你要长期维护仓库,SOW 还提供 Managed 模式:一份包体投影成多个发行视图,记录期望状态与已构建状态,生成不可变快照,计算精确变更集,再增量发布到文件系统或对象存储。

一句话概括:SOW 把“生成软件仓库索引”这件小事,和“治理一个长期运行的软件仓库”这件大事,装进了同一个单文件工具里。

这样的工具纯粹是为了解决老冯自己的问题。但如果你也维护着大型跨 Linux 发行版仓库,它应该也能帮到你。虽然有这样需求的用户也不会很多就是了。

为什么叫 SOW?

这个名字值得单独讲讲。在之前,我们做的另一个配套开源项目叫 ,这是 PostgreSQL 生态的一个包管理器。那么既然有小猪来装包,那么制作这些包,负责承载、组织和分发这些软件制品的仓库工具,自然就是“母猪” SOW 了。


它还可以展开成 Software Object Warehouse —— 软件对象仓库。一段工业史里的术语,正好严丝合缝地落到了软件供应链里。而且更妙的是,它还有另外一层双关 —— 在传统铸铁场里,铁水先流入一条主槽,再分流到两侧的小槽里,冷却成一块块铁锭。那些铁锭叫 Pig,承载和分配铁水的主槽叫 Sow。从上方看,一条大槽带着一排小铁锭,正像一头母猪带着一窝小猪。


为什么要再造一个仓库工具?

最直接的诱因,来自 Pigsty 的离线安装。Pigsty 会先把安装所需的 RPM / DEB 下载到本地,再生成一个离线软件仓库。过去,RPM 系统依赖 createrepo_c,Debian / Ubuntu 依赖 dpkg-dev。真正要生成的不过是几份 XML、Packages 与压缩索引,准备工具链却要装进几百 MB 的依赖。

这在 Linux 上已经够啰嗦;到了 macOS 上更难看。你得启动不同的 Linux 容器,挂载同一份目录,分别跑 RPM 与 DEB 工具,再把结果搬回来。为了生成几 MB 元数据,先请来几百 MB 工具链和一支容器车队,怎么看都不优雅。


到了 Pigsty 4.5,我把这套冗余清掉了。SOW 是一个几 MB 级的自包含二进制,在 Linux 和 macOS 上都能直接运行,同时理解 RPM 与 DEB,APT / DNF 仓库的规范。没有守护进程,也不需要额外语言运行时。

但“少装几个工具”只是表面问题。真正让我决定把 SOW 做下去的,是仓库规模扩大后暴露出的四个痛点。

第一,硬链接救不了对象存储

同一个 noarch RPM 可能同时出现在多个架构仓库里,同一份包也可能进入 beta、latest、stable 等多个视图。放在本地磁盘上,可以用硬链接让许多路径共用一份 inode;上传到 Cloudflare R2、OSS 或其他对象存储后,每个 object key 都会变成一份实打实的存储与上传成本。文件内容相同,不代表云端知道它们应该共享所有权。

第二,十万个文件让“比较一下”都变得昂贵

仓库更新通常只变动几十个包,但传统同步工具为了确认这一点,往往要把十几万个文件重新遍历、比较、校验一遍。全量检查一次花十几分钟并不稀奇;真正的数据传输可能只有几秒,时间全耗在“什么都没变”的证明上。


第三,在线仓库不应该露出半成品

一个 RPM 仓库不只是 .rpm 文件;客户端先读 repomd.xml,再沿着它找到 primary、filelists 和包体。APT 同理:ReleaseInReleasePackages 与 by-hash 文件之间有严格引用关系。

如果更新顺序错了,客户端就可能先看到新指针,却找不到新指针引用的对象。对维护者来说只是几秒钟的上传窗口,对全球随机到访的用户来说,就是一次无法复现的 404、校验失败或安装中断。


第四,目录没有版本,发行版需要版本

最核心的问题是,当老冯想要进一步的改进仓库,提供 Channel 的能力,之前的维护模型就会遇到这些问题:如何同时维护 beta、latest、stable 的仓库?如何每月保存一个快照?如何回答“上周三到底加了哪些包”?如何安全回退?哪些旧对象已经没有任何快照引用,可以删除?

这些需求单独看都能用脚本拼出来;组合到一起,脚本就会长成一套没有事务、没有模式、没有审计的影子数据库。市面上当然有 createrepo_cdpkg-scanpackagesrepreproaptly,也有通用同步与对象存储工具。但我没有找到一个足够轻、同时把 RPM 与 DEB、单份包池、不可变快照、原子发布和增量交付放进同一套清晰模型里的开源工具。

幸运的是,自己做工具的成本从来没有像现在这样低过。

两种复杂度,两种模式

SOW 没有假装所有仓库都需要同样的治理强度。它把问题切成 Plain 与 Managed 两层:小问题保持小,大问题才使用完整状态机。

Plain:包目录就是事实

Plain 模式只有一个核心命令:

目录里的 RPM / DEB 是唯一权威事实,repodata/PackagesPackages.gz 都是可以随时丢弃重建的投影。SOW 会并行扫描顶层软件包,每个包在默认路径上只打开一次,在同一遍里完成 SHA-256、解析和渲染所需事实的提取,再生成两种仓库元数据。

生成结果先进入同文件系统的私有 staging 区,经过 SOW 自己的解析器校验后再替换公开文件。最后,它只重新比较文件集合与 stat 快照,确认构建期间没有包被新增、删除或替换;不会为了“再放心一次”把所有大包重新哈希一遍。


Plain 不保存操作日志,也不做沉重的事务恢复。进程中断了,就重新执行同一条 sow create:包目录还在,索引只是派生状态,重建比恢复更便宜。

--pigsty 模式还会最后写入 repo_complete 完成标记。只要 marker 不存在,消费方就知道这份仓库还没准备好。这是一个很小、但非常实用的提交协议。

这套模式解决了 Pigsty 最初的痛点:用一个小二进制替代两套工具链与多个容器,快速得到能被真实 APT、DNF/YUM 客户端消费的仓库。

Managed:仓库不是目录,而是状态机

长期运行的仓库不能只看“目录里现在有什么”。它还必须知道你想要什么、上一次成功发布了什么,以及两者为什么不同。

SOW 的 Managed 模型分成四层:


Workspace 是配置与发现边界;Repository 是所有权边界;Dist 是一个具名的 RPM 或 DEB 成员集合;Architecture View 只是渲染结果,不再拥有一份软件包。这里最重要的不变式是:在一个 Repository 内,每个软件包只有一份正典包体,不留副本。

repo/dists/trixie/main/binary-amd64/...    APT 元数据视图

noarch RPM 或 all DEB 可以被投影进多个架构索引,却不会复制包体。beta 与 stable 也可以引用同一个软件包对象,而不制造第二份云端 object key。而且更妙的是,APT 和 DNF 仓库可以在同一套目录体系下管理。


“只存一份”的边界必须说准确:它是一个 Repository 或一个发布前缀,不是整个 Workspace、bucket 或全世界。不同 Repository 之间不做隐式去重,因为去重不能以破坏所有权为代价。删掉一个仓库,绝不能顺手删掉另一个仓库依赖的共享对象。

Desired、Built 与 Generation

Managed 模式把仓库状态拆成三个概念:

状态

含义

Desired

配置、加包、删包操作想要得到的成员集合

Built

上一次完整渲染、校验并提交成功的公共视图

Generation

对某个 Built 状态的不可变清单

这个区分看似学院派,实际上专门解决失败场景。

假设你一次加入五千个包,Desired 已经改变,但构建在中途被 SIGKILL。没有这层区分,系统只能面对一棵“不知道改到哪儿”的目录;有了它,SOW 可以诚实地说:意图已经更新,上一个 Built Generation 仍完整对外服务,新操作处于待恢复状态。

Generation 不是把整个仓库再复制一遍。它保存的是不可变 manifest、元数据与包体引用集合;多个快照可以引用同一份 Pool 对象。两代 Generation 之间的精确差异就是 Changeset:新增哪些包体、替换哪些元数据、切换哪些指针、哪些旧对象在保留期后可以删除,一目了然。

所以增量同步不再从“重新扫描十万个文件”开始,而是从“比较两个已知 Generation”开始。


原子切换的秘密:最后才动指针

软件仓库没有一个跨文件、跨对象的全局事务。SOW 的做法不是假装它存在,而是把发布顺序设计成可证明的协议:

 包体          元数据          指针          删除旧对象

先放入不可变包体;再写 checksum 命名的元数据与 by-hash 索引;全部就位之后,最后才切换 repomd.xmlRelease / InRelease 这些客户端入口。只有旧指针已经不再引用旧文件,并且保留期与证据门禁都满足,旧对象才允许删除。

因此,客户端沿着一个生效指针往下走时,它引用的内容一定已经存在。对单个协议视图来说,读者看到的要么是完整旧代,要么是完整新代,不会看到一棵被撕裂的树。

在本地 POSIX 文件系统上,这套过程依赖同盘 staging、fsync、原子 rename、稳定路径锁和持久操作日志。每条 Managed 写命令都会先检查并恢复上一次未完成操作,再开始自己的工作。恢复只根据已经落盘的证据判断该回滚还是前滚;证据矛盾时宁可失败关闭,也不提供一个可能猜错的 repair --force

对象存储没有多 key 原子提交,SOW 就先持久化 commit intent,再按确定顺序前滚协议指针,并为每个 target 单独保存 Applied Checkpoint。当前文件系统与 R2 发布各有自己的证据,前者成功绝不会被误认为后者也成功。R2 端如果缺少足够安全的条件删除证据,垃圾回收就只报告候选,不冒险远程删对象。

这也是 SOW 与一条 rclone sync 命令最本质的区别:传输文件不难,困难的是知道哪些能传、何时算提交、失败后往哪边恢复,以及哪些真的可以删

十万个对象,性能不能靠信仰

SOW 0.3 的主要工作,不是继续堆功能,而是把已经成立的模型推到真实仓库规模。

Plain 路径现在每个包只做一遍内容读取、哈希与解析,并通过 --jobs 使用有界并发。输入相同,元数据逐字节确定;无需更新时返回 no-op,也不会为了“更新一下时间戳”替换公开 inode。

Managed 路径则把解析后的“软件包事实”按不可变 SHA-256 缓存在 SQLite 中。新包入库时完整认证并解析一次;后续构建批量载入事实,在内存里完成成员投影。暖构建仍会遍历公开命名空间,但对未变化的 Pool 文件只检查 device、inode、size、mtime、ctime 指纹,不再把所有包体重新读一遍。指纹漂移时才回退到一次权威 SHA-256,并自动修复缓存;需要全量密码学审计时,显式运行 sow check

这类优化的价值,必须落在数字上。

在项目基准中,一个包含 5000 个对象的 Dist,成员展开从约 4.1 秒降到 33 毫秒;50000 个对象原先十分钟仍跑不完,现在约 300 毫秒完成。载荷提升也改成了有界单写入者组提交,每批最多 512 个对象或 1 GiB,既减少 fsync 风暴,也保证文件描述符和恢复状态不会随着仓库规模无限增长。

这些数字不是为了做一张跑分海报。它们只是说明:当仓库真的有十万个制品时,“状态模型正确”只是及格线,“日常小改动仍然足够便宜”才决定工具能不能被长期使用。

推倒第一版,再从最小闭环长回来

SOW 的开发时间不短,中间还经历过一次相当彻底的推倒重来。

最初那一版后来以 v0.1.0 留档。它野心很大:用 Git ref 管理仓库视图,用 SHA-256 CAS 保存制品,同时处理上游同步、多目标云发布、校验、修复、垃圾回收、Cloudflare Worker、CDN purge、边缘验证和生产迁移。

这些功能很多都已经做出来了,部分路径也跑过真实 APT/DNF 与非生产 R2 验收。但它的问题同样明显:仓库模型、云厂商、CDN、边缘运行时与迁移流程耦合得太紧。一项功能的正确性,要靠另外半套系统才能证明;任何小改动都会拖着一长串验收矩阵一起移动。

我最后决定把它封存。

推倒的不是目标,而是抵达目标的方式。一个基础设施工具最怕“什么都有一点,但没有哪一层能单独说清楚”。所以第二版先把最小闭环重新切出来:

P0 / Plain Create: 一个目录进去,一个可用仓库出来;•P1 / Managed Control Plane: Workspace、Repository、Dist、Membership、Build、Generation、Check、Changes 与 Operation Log;•更复杂的同步、远端发布、CDN 与供应商控制面,逐项回到独立验收队列。

v0.2.0 建立了今天的 Plain + Managed 主体:单份包池、元数据视图、确定性构建、锁、日志、崩溃恢复、Generation、文件系统与 R2 发布。

v0.3.0 没有再造一层概念,而是集中清理旧 V1 运行时,收敛云端传输边界,并解决 Plain 与 Managed 在大仓库上的重复读取、逐对象查询、载荷提交和可观察性问题。当前正式二进制只依赖新的 V2 核心,旧实现留在 Git 历史与 v0.1.0 / v0.2.0 标签里,作为经验,而不是第二套事实来源。

这条路看上去比“一次憋个大的”慢,其实更快。每一层都有独立契约、失败语义和真实客户端验收,下一层建立在已经站稳的地基上,而不是建立在一份越来越难读的愿望清单上。


接下来的 Roadmap

SOW 0.3 已经能创建仓库、管理成员与快照、计算变更集,并发布到文件系统和 R2;但它离我脑子里完整的软件制品控制面还有距离。

接下来主要有四条线:

1.上游仓库同步。 直接消费 APT/YUM 上游索引,验证签名与摘要,只拉取缺失制品,并把镜像结果纳入同一套 Package Object、Membership 与 Generation 模型。2.更完整的增量交付。 现在 changes 与 target checkpoint 已经能描述、复用并只发布差异;下一步是扩展对象存储与同步供应商覆盖,把大规模远端 inventory、断点恢复、条件写入和安全删除证据做成稳定闭环。3.CDN 与缓存控制。 CDN purge 不是“调一下 API”这么简单,还要绑定精确 Generation、缓存 TTL、回执与失败恢复。V1 已经证明这条路可行,但它会以独立、可验收的模块重新进入,而不是重新和仓库核心焊死。4.版本与保留策略。 beta、latest、stable、月度快照这些需求,现在已经可以用 Dist、Generation、retain 与 target 组合表达;后续还会补上更高层的策略编排,让常见发布节奏不必由外部脚本手工串联。

这些能力在第一版里大多已经有过实现。我不打算把旧代码整块搬回来,而会像 0.2、0.3 一样,一次只拿回一个边界清楚、能独立验收的能力。

不再憋大招,持续交付小而完整的闭环。

猪猪家族还在继续长大

SOW 是 Pigsty “猪圈宇宙”的一部分,而且这个命名体系已经越来越离谱,也越来越完整:

Pigsty:•SOW:母猪,负责组织、构建和发布软件仓库;•Boar:公猪,开发中的 PIGSTY GUI 管控平台;•Silo:•Oink:•Snort:猪拱,负责收集日志与监控指标

这当然首先是一套命名梗,但它背后也慢慢长出了一条完整链路:SOW 整理制品,Silo 存放制品,Pigsty 把它们安装成系统,Snort 观察系统,Oink 把一切讲清楚。而 SOW 填上的,正是过去最容易被忽视的那一段。

软件仓库看起来只是一个能被 Nginx 托管的目录,但当它承载十万个对象、多个操作系统、多个架构与无数用户之后,它其实是一台没有界面的数据库:有对象、有关系、有版本、有事务、有日志、有垃圾回收,还有绝不能写错的提交指针。

SOW 做的事情,就是把这些隐含规则变成显式模型,把一堆“祖传脚本应该没问题”的侥幸,变成可以检查、恢复和审计的工程契约。如果你只想建一个离线仓库,从一条命令就可以开始。

如果你也在维护一套长期运行的软件发行版,欢迎来看看它更深的一面。SOW 采用 Apache-2.0 许可证。当前 0.3.0 版提供 Linux / macOS 的 amd64、arm64 归档,以及 Linux RPM / DEB 安装包。

•项目主页:sow.pgsty.com/zh[2]•使用文档:sow.pgsty.com/zh/docs[3]•下载:sow.pgsty.com/zh/download[4]•源代码:github.com/pgsty/sow[5]

References

[1] SOW: https://sow.pgsty.com/zh/
[2] sow.pgsty.com/zh: https://sow.pgsty.com/zh/
[3] sow.pgsty.com/zh/docs: https://sow.pgsty.com/zh/docs/
[4] sow.pgsty.com/zh/download: https://sow.pgsty.com/zh/download/
[5] github.com/pgsty/sow: https://github.com/pgsty/sow


数据库老司机

点一个关注 ⭐️,精彩不迷路

跟数据库老司机学习母猪的产后护理

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
美职联疯狂2-2!迈阿密2次送点,梅西助攻+中框,胖虎“独造3球”

美职联疯狂2-2!迈阿密2次送点,梅西助攻+中框,胖虎“独造3球”

球场没跑道
2026-09-06 11:16:26
阿斯:穆帅需要铁腕,而不是给巨星“豁免权”

阿斯:穆帅需要铁腕,而不是给巨星“豁免权”

懂球帝
2026-09-06 11:03:17
剧情崩坏,特效廉价,《坠落2》外网口碑彻底扑街

剧情崩坏,特效廉价,《坠落2》外网口碑彻底扑街

光影新天地
2026-09-05 10:23:59
美网女单16强全出炉:14位种子选手晋级,郑钦文唯一资格赛突围

美网女单16强全出炉:14位种子选手晋级,郑钦文唯一资格赛突围

全景体育V
2026-09-06 11:19:11
中建集团:坚决拥护党中央决定

中建集团:坚决拥护党中央决定

新京报
2026-09-05 12:54:06
巴萨“布斯克茨接班人”场场首发,罗德里佩德里还能争到主力吗?

巴萨“布斯克茨接班人”场场首发,罗德里佩德里还能争到主力吗?

十夏九漓
2026-09-05 21:05:48
知名女星赤裸上身 和两个儿子合照,身材火辣,网友:毫无边界感…

知名女星赤裸上身 和两个儿子合照,身材火辣,网友:毫无边界感…

陈意小可爱
2026-09-03 13:10:31
一场1-2让越南球迷梦碎!两战全败提前出局,下轮不胜将降级!

一场1-2让越南球迷梦碎!两战全败提前出局,下轮不胜将降级!

绿茵舞着
2026-09-05 21:51:53
37岁奥巴梅扬西甲4场4球2助攻,并实现五大联赛250球里程碑

37岁奥巴梅扬西甲4场4球2助攻,并实现五大联赛250球里程碑

懂球帝
2026-09-06 10:42:10
女子985毕业年薪15万男友妈看不上,让他娶公务员,6年后再相逢

女子985毕业年薪15万男友妈看不上,让他娶公务员,6年后再相逢

黑猫故事所
2025-04-26 16:36:31
官方出手了!这一拳不止捶师德,开豪车有4套房产的曾某恐要凉凉

官方出手了!这一拳不止捶师德,开豪车有4套房产的曾某恐要凉凉

爱写的樱桃
2026-09-05 03:18:03
老人因“鱼头对自己”怒斥小辈,被怼到哑口无言:没生在紫禁城,就别那么多穷规矩!

老人因“鱼头对自己”怒斥小辈,被怼到哑口无言:没生在紫禁城,就别那么多穷规矩!

妍妍教育日记
2026-08-16 10:05:09
带队5战全胜!客场掀翻大巴黎,41岁巴西少帅成为足坛现象级教头

带队5战全胜!客场掀翻大巴黎,41岁巴西少帅成为足坛现象级教头

体坛老球迷
2026-09-05 09:16:25
贝克汉姆14岁的女儿小七怎么如此成熟了,好像少妇

贝克汉姆14岁的女儿小七怎么如此成熟了,好像少妇

西楼知趣杂谈
2026-06-13 19:52:21
江苏省委书记信长星、省长刘小涛、省政协主席张义珍,带头捐款

江苏省委书记信长星、省长刘小涛、省政协主席张义珍,带头捐款

政知新媒体
2026-09-05 10:39:45
炸裂封神!巴萨 19 岁天才打破 17 年纪录!碾压一众冠军王牌

炸裂封神!巴萨 19 岁天才打破 17 年纪录!碾压一众冠军王牌

澜归序
2026-09-06 08:38:41
又一电影,宣布撤档

又一电影,宣布撤档

鲁中晨报
2026-09-06 11:51:03
1高+4射搭配!火箭组全新2阵,进攻火力持续升级,三分+防守成主打战术

1高+4射搭配!火箭组全新2阵,进攻火力持续升级,三分+防守成主打战术

熊哥爱篮球
2026-09-06 09:37:38
上世纪50年代,到底杀了多少地主恶霸?公布的数据,让人不敢相信

上世纪50年代,到底杀了多少地主恶霸?公布的数据,让人不敢相信

文史道
2025-11-15 06:45:03
美军事媒体:一艘中等水平中国导弹护卫舰,令美日台同时不安

美军事媒体:一艘中等水平中国导弹护卫舰,令美日台同时不安

普览
2026-09-05 14:04:13
2026-09-06 12:35:00
老冯云数 incentive-icons
老冯云数
数据库老司机,云计算泥石流,PostgreSQL大法师
232文章数 62关注度
往期回顾 全部

科技要闻

DeepSeek被曝将采购16万颗华为昇腾950DT

头条要闻

男子1.38万捡漏二手大众CC 懂车帝称操作失误未发货

头条要闻

男子1.38万捡漏二手大众CC 懂车帝称操作失误未发货

体育要闻

本西蒙斯加盟国王,不管怎样,回来就好

娱乐要闻

低调富养!郭富城两女儿入读香港名校

财经要闻

亏损高达200亿,昔日彩电霸主走下巅峰!

汽车要闻

带升降立标MPV 岚图梦想家9预售价42.99万起

态度原创

房产
健康
教育
时尚
本地

房产要闻

突发重磅!海口出台楼市新政!

脑梗取栓成功≠活下来,还有这三关

教育要闻

大鹏老师《初中数学压轴题杠上系列》完整内容目录!

金秋最流行的鞋子,“红色”更时髦!

本地新闻

扒完小作文,富豪们私藏的度假胜地有多绝

无障碍浏览 进入关怀版