ZeroBrew:一个比 Homebrew 快 5-20 倍的包管理器

5次阅读
没有评论

共计 6050 个字符,预计需要花费 16 分钟才能阅读完成。

前段时间我在 GitHub 上闲逛的时候,偶然发现了一个叫做 ZeroBrew 的项目,标题写着「比 Homebrew 快 5-20 倍」。作为一个长期被 Homebrew 慢速折磨的 macOS 用户,我的第一反应是「又是一个标题党吧」,但仔细看了看项目说明和基准测试结果之后,我发现这个项目确实有点意思。项目作者不仅给出了详细的性能对比数据,还开源了完整的基准测试代码,这让我产生了想要深入了解和实际试用的冲动。毕竟,如果真的能让日常的包管理操作快上几倍甚至十几倍,那对开发效率的提升是实实在在的。

Homebrew 的性能痛点

说到 Homebrew,相信每个 macOS 开发者都不陌生。它几乎已经成为了 macOS 上事实上的标准包管理器,无论是安装开发工具、命令行工具还是各种依赖库,我们都会习惯性地敲下 brew install 命令。但是,用久了之后你会发现,Homebrew 有一个让人头疼的问题,那就是慢。这种慢不是偶尔慢一次,而是几乎每次操作都能感受到的那种「系统性的慢」。

这种慢体现在很多方面。首先是更新索引的时候,每次执行 brew update 都要等待相当长的时间,终端里会显示一大堆 Git 操作的输出,你只能干等着。其次是安装软件包的时候,即使是很小的工具,也常常需要等待好几分钟。更让人不解的是,有时候你重新安装一个之前装过的包,Homebrew 还是要重新下载、重新解压、重新链接,完全没有利用之前的缓存,整个过程慢得让人怀疑人生。我记得有一次在公司网络环境下安装 tesseract 这个 OCR 工具,前前后后等了快十分钟,而这个包我明明在家里的 MacBook 上已经装过一次了。这种重复劳动带来的时间浪费,积累起来其实是相当可观的。

Homebrew 的这种性能问题其实是有深层次原因的。它最早是用 Ruby 编写的,虽然后来做了很多优化,但整体架构上还是偏向于串行操作。下载完成之后才开始解压,解压完成之后才开始链接,每一步都是顺序执行的。而且,Homebrew 的缓存机制也比较简单粗暴,它只是把下载的压缩包放在 cache 目录里,并没有对包内容进行更细粒度的管理。这就导致即使你之前下载过某个包,如果重新安装的话,还是要重复走一遍完整的解压和链接流程。

ZeroBrew 的设计理念

ZeroBrew 的出现,正是针对 Homebrew 的这些性能痛点而来的。项目作者在 README 中明确提到,ZeroBrew 的设计灵感来自于 Python 生态中的 [[uv]],这是一个用 Rust 编写的超快速 Python 包管理器。如果你关注过 Python 社区最近的动态,就会知道 uv 有多么受欢迎,它把原本需要几分钟的 pip install 操作压缩到了几秒钟,这种量级的性能提升是质的飞跃。ZeroBrew 就是想把这套思路搬到 macOS 的包管理领域。

ZeroBrew 最核心的创新点在于它使用了「内容寻址存储」(Content-Addressable Storage)这个概念。简单来说,就是把每个包按照它的内容计算出一个 SHA256 哈希值,然后用这个哈希值作为存储路径。比如某个版本的 jq 工具,它的哈希值是 abc123...,那么 ZeroBrew 就会把它存储在 /opt/zerobrew/store/abc123.../ 这个目录下。这样做的好处是什么呢?当你需要重新安装这个包的时候,ZeroBrew 只需要检查一下这个哈希值对应的目录是否存在,如果存在就直接用,完全不需要重新下载和解压。这就是为什么 ZeroBrew 在「热安装」场景下能达到 20 倍速度提升的关键原因。

除了内容寻址存储,ZeroBrew 还充分利用了 macOS 的 APFS 文件系统特性。APFS 支持「写时复制」(Copy-on-Write)机制,通过 clonefile 系统调用,可以几乎瞬间完成文件的复制操作,而不需要真正地把数据从一个地方拷贝到另一个地方。ZeroBrew 正是利用这一点,在从内容存储库「具现化」包到 Cellar 目录的时候,使用 clonefile 来创建引用,几乎零成本。这比 Homebrew 传统的解压和复制方式要高效得多。

另外一个值得一提的设计是并行处理。ZeroBrew 在安装多个包的时候,会同时进行下载、解压和链接操作,而不是像 Homebrew 那样串行执行。项目文档中提到,ZeroBrew 还会「竞速多个 CDN 连接」并且「去重飞行中的请求」,这意味着它会同时向多个镜像源发起下载请求,哪个快就用哪个,同时还会智能地避免重复下载相同的内容。这种积极进取的优化策略,配合 Rust 语言本身的高性能特性,让 ZeroBrew 在冷安装场景下也能达到 2-5 倍的速度提升。

实际性能表现

说了这么多理论,那实际表现怎么样呢?项目仓库里提供了一个 benchmark-results.txt 文件,里面记录了 Homebrew Top 100 包的详细测试数据。我仔细看了这些数据,确实非常惊艳。在冷安装(首次安装)场景下,ZeroBrew 平均比 Homebrew 快 2.0 倍,这已经是非常明显的提升了。而在热安装(重新安装之前装过的包)场景下,平均速度提升达到了 7.6 倍。

更夸张的是某些具体的包。比如 tesseract 这个 OCR 引擎,热安装时 ZeroBrew 比 Homebrew 快了 29.5 倍。我前面提到过这个包在 Homebrew 下安装要等十分钟,如果用 ZeroBrew 的话,可能只需要二十秒。还有 sqlite,热安装速度提升了 18.1 倍。这些数据不是凭空捏造的,因为作者把完整的基准测试代码和原始数据都公开了,你可以自己在本地跑一遍验证。这种透明度让我对这个项目的可信度大大增加。

当然,这些性能数据是在特定的测试环境下得出的,实际使用中可能会有一些波动。比如网络环境会影响冷安装的速度,硬盘性能会影响解压和链接的速度。但即使打个折扣,ZeroBrew 带来的性能提升也是实实在在的。想象一下,如果你每天要安装或更新十几个包,每个包节省几十秒到几分钟的时间,一周下来就能省下大半个小时。对于需要频繁配置开发环境的场景,比如 CI/CD 流水线或者容器镜像构建,这种提升更是价值连城。

实际使用体验

看完这些数据之后,我决定在自己的开发机上试用一下 ZeroBrew。安装过程非常简单,官方提供了一个安装脚本,只需要执行一行命令就可以了:

curl -sSL https://raw.githubusercontent.com/lucasgelfond/zerobrew/main/install.sh | bash

脚本会自动下载编译好的二进制文件,放到 ~/.zerobrew/bin/zb 路径下,并且提示你把这个路径加到 PATH 环境变量里。整个安装过程不到一分钟就完成了,非常顺畅。安装完成后,你就可以用 zb 这个命令来代替 brew 了。

ZeroBrew 的命令行接口设计得很友好,基本上就是把 brew 命令换成 zb 就行了。比如安装软件包:

zb install jq
zb install wget git

卸载软件包:

zb uninstall jq

还有一些 ZeroBrew 特有的命令,比如 zb reset 可以完全清空安装状态,zb gc 可以执行垃圾回收,清理不再使用的缓存文件。这些命令的设计都很直观,基本上不需要查文档就能猜到用法。

我先试着装了几个常用的工具,比如 jqwgetgit 这些。第一次安装(冷安装)的时候,能明显感觉到比 Homebrew 快不少,虽然没有达到基准测试里那种极致的倍数,但至少快了一倍左右。然后我又试了一下卸载再重装(热安装),这时候速度提升就非常明显了,几乎是瞬间就完成了。这种流畅的体验确实让人印象深刻,之前用 Homebrew 重装包的时候那种「明明装过为什么还要等这么久」的烦躁感,在 ZeroBrew 上完全没有了。

不过,使用过程中我也发现了一些需要注意的地方。首先,ZeroBrew 目前还是一个实验性项目,作者在 README 里也明确标注了「experimental」字样。虽然对大部分常用的 Homebrew 核心包都支持得不错,但还是有少数包可能会有问题。我在试用的时候,有一个包安装失败了,报了一个链接错误,不过这也在意料之中,毕竟是个年轻的项目。作者建议用户在试用 ZeroBrew 的同时,保留原来的 Homebrew 作为备份方案,遇到问题的时候可以随时切回去。

其次,ZeroBrew 和 Homebrew 使用的是不同的安装前缀。Homebrew 默认装在 /opt/homebrew/ 或者 /usr/local/ 下,而 ZeroBrew 使用的是 /opt/zerobrew/。这意味着如果你在 ZeroBrew 里装了某个包,Homebrew 那边是看不到的,反之亦然。它们的软件包是完全隔离的,互不影响。这其实是个好事,因为你可以放心地在 ZeroBrew 上做实验,不用担心搞坏现有的 Homebrew 环境。不过这也意味着如果你想完全切换到 ZeroBrew,需要把之前用 Homebrew 安装的包在 ZeroBrew 里重新装一遍。

还有一个我觉得特别有意思的细节,就是 ZeroBrew 的内部实现。作者在项目说明中提到,他用 Claude Opus 4.5 这个大语言模型辅助编写了很多代码。他说「语言模型在编程方面确实有效,只要给出精确的规格说明并配合人工输入」。看到这里我会心一笑,因为这也从侧面说明了现在 AI 辅助编程已经发展到什么程度了。一个人加上一个好用的 AI,就能在短时间内写出一个性能这么出色的工具,这在几年前是难以想象的。

技术架构深度解析

如果你对 ZeroBrew 的内部实现感兴趣,我可以稍微展开讲讲它的技术架构。整个 ZeroBrew 的目录结构设计得非常清晰,位于 /opt/zerobrew/ 下的主要有这几个目录:store/ 是内容寻址存储库,每个包按照 SHA256 哈希值存放;prefix/Cellar/ 是具现化后的包目录,类似于 Homebrew 的 Cellar;prefix/bin/prefix/opt/ 是符号链接目录,把可执行文件和库文件链接到这里;cache/ 存放下载的压缩包;db/ 是一个 SQLite 数据库,用来记录包的元数据和安装状态;locks/ 目录则用来做文件锁,避免并发操作冲突。

这种架构设计的巧妙之处在于,它把「存储」和「使用」完全分离开了。store/ 目录里的内容是不可变的、按内容寻址的,而 prefix/ 目录里的内容是可变的、按路径寻址的。当你安装一个包的时候,ZeroBrew 先把包的内容放到 store/ 里,然后用 APFS 的 clonefile 把它「投影」到 Cellar/ 里,最后再创建符号链接到 bin/opt/。这个过程中,真正消耗磁盘空间的只有 store/cache/,而 Cellar/ 里的文件只是指向 store/ 的引用,几乎不占空间。这就是为什么 ZeroBrew 的磁盘占用比 Homebrew 要小的原因。

另外,ZeroBrew 使用 SQLite 作为元数据存储也是一个聪明的选择。SQLite 是一个非常成熟可靠的嵌入式数据库,性能好、占用资源少,用来存储包的版本信息、依赖关系、安装状态等数据再合适不过了。相比之下,Homebrew 使用的是文件系统加上一些 Ruby 脚本来管理元数据,效率要低不少。ZeroBrew 所有的元数据查询都可以通过 SQL 快速完成,而不需要遍历文件系统或者解析大量的文本文件。

在并发控制方面,ZeroBrew 使用了文件锁机制。每个在 store/ 里的包都有一个对应的锁文件,当某个操作正在处理这个包的时候,就会获取这个锁。这样可以避免多个 zb 命令同时操作同一个包导致数据损坏。这种文件锁的方式虽然简单,但非常可靠,即使进程崩溃了,锁也会自动释放,不会留下死锁的隐患。

适用场景与局限性

说完了优点,也要客观地聊聊 ZeroBrew 的适用场景和局限性。首先,ZeroBrew 目前只支持 macOS,而且只支持 Apple Silicon 和 Intel 芯片的 Mac。如果你用的是其他操作系统,那就没法体验了。其次,ZeroBrew 拉取的是 Homebrew 官方的 CDN 资源,这意味着它依赖于 Homebrew 的生态系统。如果某天 Homebrew 改变了 API 或者数据格式,ZeroBrew 可能就会受到影响。虽然作者说会尽量保持兼容,但这始终是一个潜在的风险。

另外,ZeroBrew 目前还不支持 Homebrew 的一些高级特性。比如 Cask(用来安装 GUI 应用的扩展)、Tap(第三方软件源)、Formula 编译选项自定义等等,这些功能在 ZeroBrew 里都还没有实现。如果你依赖这些功能,那暂时还得继续用 Homebrew。不过对于大部分只需要安装命令行工具的开发者来说,ZeroBrew 目前的功能已经足够了。

还有一个需要注意的地方是,ZeroBrew 是一个相对年轻的项目,社区规模和生态还比较小。遇到问题的时候,你可能不太容易找到现成的解决方案,需要自己去提 Issue 或者查看源代码。不过好在项目代码是开源的,而且 Rust 写的代码可读性还不错,如果你有一定的编程能力,排查问题应该不会太难。

从长期发展的角度来看,ZeroBrew 面临的最大挑战可能是如何吸引和维持一个活跃的贡献者社区。Homebrew 之所以能成为 macOS 上的标准包管理器,很大程度上是因为它有一个庞大且活跃的社区,有成千上万的 Formula 维护者在持续更新和维护软件包。ZeroBrew 如果想要走到同样的高度,需要在社区建设上下更多功夫。不过话说回来,性能优势是一个非常有力的吸引点,只要 ZeroBrew 能保持这种性能优势,相信会有越来越多的用户愿意尝试和贡献。

最后

体验完 ZeroBrew 之后,我最大的感受是,包管理器这个领域其实还有很大的优化空间。Homebrew 作为一个已经发展了十几年的成熟项目,它的很多设计决策都是在当年的技术背景下做出的。而现在,无论是编程语言(Rust)、文件系统(APFS)还是存储架构(内容寻址),都有了很多新的可能性。ZeroBrew 的出现,证明了通过吸收新技术和新思路,完全有可能在性能上实现数量级的提升。

对于普通用户来说,我的建议是可以大胆尝试 ZeroBrew,但同时保留 Homebrew 作为备份。把 ZeroBrew 用在那些你经常需要重复安装的包上,比如配置新机器、搭建开发环境的时候,这样能最大化地享受它的性能优势。而对于一些不常用的、或者 ZeroBrew 还不支持的包,继续用 Homebrew 就好。两个工具是可以并存的,没有必要做非此即彼的选择。

我个人觉得,ZeroBrew 的意义不仅仅在于它提供了一个更快的包管理器,更在于它展示了一种可能性——用现代化的技术重新审视和改进那些我们习以为常的开发工具。这种「重新发明轮子」的尝试,只要确实能带来实实在在的价值提升,就是值得鼓励和支持的。期待看到 ZeroBrew 在未来能进一步完善功能、扩大社区,也期待它能倒逼 Homebrew 在性能优化上做出更多改进。毕竟,良性竞争对用户来说永远是好事。

正文完
 0
评论(没有评论)