摘要

  • Kamp(广为称为 PHK)在 Verdens Gang 委托开发生产级 Web 加速器后,设计并编写了最初的 Varnish Cache,利用操作系统虚拟内存取代了第二层应用级缓存管理器。
  • 他在 FreeBSD 各版本、jails、GEOM、timecounter 及基础系统原语上的工作体现出一贯的纪律:将状态置于可复用且所有权和故障边界明确的层次中。
  • VCL、进程分离和共享内存日志使 Varnish 的请求路径保持窄小,同时将更多责任转移给 HTTP 策略、内核行为、扩展及周边的分发系统。
  • Beer-Ware、Moral License 及赞助试验揭示了技术极简主义在经济上的对应问题:机器工作可以削减,但安全、发布和专业人工维护仍需资金。

Verdens Gang 让“减法性能”经受生产检验

Varnish Cache 始于 2005 年前后,源于挪威报纸《Verdens Gang》的一个生产问题。该出版商需要一个能吸收流量突发并减少后端工作的 Web 加速器,同时又不复制现有缓存软件的复杂性和瓶颈。Poul-Henning Kamp 在 VG 的支持下设计并编写了初始系统,该项目于 2006 年公开可用。

决定性选择是移除应用层面的缓存管理器。Varnish 将缓存对象映射到地址空间,并让操作系统虚拟内存系统决定哪些页面保持驻留。应用专注于 HTTP 策略、请求处理和对象元数据。VCL 表达缓存决策;管理进程控制配置和工作进程生命周期;共享内存日志使大流量观测远离同步请求写入。

这些选择为它赢得了速度声誉,但更深层的影响是责任的重新安置。内核内存行为变得更加重要。编译型策略既强大又危险。聚焦的代理需要相邻系统来处理其范围之外的功能。靠减法实现的性能并没有让整体系统变得简单;它让状态的所有者更加明确。

Kamp 通过 FreeBSD 发布工程、jails、GEOM、timecounter 以及其他内核或基础系统原语培养了这种直觉。他后来在精密计时、开源资金和项目治理方面的工作,将同样的检验应用于代码和机构:哪个层次已经在负责这项工作,而移除另一层又会制造什么依赖?

核心问题是:少做是否能让系统更易于运维和交接,还是仅仅把复杂性移到运维人员看不见的地方。当减法留下清晰接口、可观察的故障路径以及愿意承担剩余责任的维护者时,Kamp 的记录最为有力。

发布工程让接口承诺变得可见

Kamp 在项目治理和架构尚未完全定型时就开始接触 386BSD 和 FreeBSD 这一代码谱系。他自己的历史叙述称,他从 1994 年初起在 FreeBSD 核心团队工作约六年,并负责 FreeBSD 2.x 的发布工程,同时参与内核和基础系统的工作。

发布工程是一个重要的起点,因为它迫使开发者将操作系统视为一件交付物,而不是一堆补丁。代码必须能够一起构建,升级必须可行,而故障必须能被未参与开发讨论的用户理解。发布工程师站在技术雄心与人们实际可安装的系统之间的边界上。

Kamp 的贡献清单包括 VFS 名称缓存、sysctl、内存分配、设备系统、安全字符串缓冲、jails、GEOM、磁盘加密和 timecounter。这份清单部分来自他的第一人称档案,不应取代提交级署名。其中许多系统是与他共同开发的,并且在他最初的工作之后经过了大量维护。作为对 Varnish 诞生之设计环境的描述,这一广度仍有充分依据。

操作系统项目会奖赏那些能被无关应用复用的机制。名称缓存改善整个系统的路径查找。timecounter 为硬件时钟创建共同抽象。GEOM 使存储变换可以组合。jails 暴露隔离模型,而不是封装某个托管服务。这种取向鼓励了 Kamp 后来在 Varnish 中提出的问题:应用能否依赖通用内核机制,而不是重新实现它?

FreeBSD 还提供了治理经验。Kamp 曾在早期核心团队任职,并在项目约于 2000 年转向选举模式时离开这一正式职务。他的技术参与仍在继续,但当前 FreeBSD 的权限属于现有提交者和现任 Core Team。历史上的领导并非持续的公司头衔。

这一区别很重要,因为开源影响力可以在正式职务结束后持续存在。一个子系统可以在数十年中承载架构师的选择,而后来的维护者会改变实现和策略。持久的贡献是一个他人可以拥有的可用抽象,而非无限期的控制权。

如果把发布工程置于中心,Kamp 的 FreeBSD 记录就不会看起来像一堆互不相关的内核工作。发布是局部修改合成一个操作系统的地方。每个子系统都必须按相同接口构建,安装介质必须送达用户,默认值必须站得住脚,变更必须能在从旧状态升级后继续存在。

因此,Kamp 对 FreeBSD 2.x 的历史责任并不仅仅在于版本号。发布工作暴露了那些只盯着自己代码的开发者可能会忽略的依赖。设备变更可能破坏安装程序。库接口可能让第三方软件陷入困境。一个新内核机制即使技术上正确,如果缺少文档、工具和回滚方案,也可能在运维上不可用。

这一背景有助于解释 Varnish 后来的形态。该缓存并非设计成等待实现团队的纸上算法,而是作为出版商需要运行、观察和修改的软件而诞生。管理进程、VCL 加载、共享日志和运行参数都是系统的一部分,因为一个没有运维路径的快速循环无法解决 Verdens Gang 的问题。

发布工程还鼓励抵制永久性的兼容负担。一旦接口发布且用户围绕它构建,移除就会变得代价高昂。拒绝一个薄弱抽象最安全的位置,是在它成为发布的一部分之前。Kamp 的文章常常偏袒窄契约和明确所有权,因为每多一个表面最终都会成为某人的维护义务。

证据并不支持把 FreeBSD 2.x 的每一项发布决策都归于某一个人。它支持的是 Kamp 曾在集成边界工作过一段时期。这一角色提供了一条实际经验:架构在一定程度上是用户期望下一版本兑现的承诺的累积。

对基础设施购买者而言,这是原型与受维护系统之间的有用区别。原型演示机制。发布过程则证明维护者能够封装该机制、说明其局限、修复回归并带领用户前进。Varnish 的长久生命力既取决于原始存储设计,也同样取决于第二种纪律。

小型原语承载着长期价值与过时假设

Kamp 在 FreeBSD 中的若干贡献并非运维人员会购买甚至注意到的产品,而是基础系统原语:名称缓存、内存分配、sysctl、动态字符串构造和设备基础设施。其价值在于改变其他代码执行工作的成本或安全性。

VFS 名称缓存避免了在重复使用相同文件系统名称时重复昂贵的路径解析工作。具体实现已经演进,功劳是集体的,但设计问题长期存在。文件路径是覆盖在存储对象之上的人类可读命名空间。缓存这种关系可以改善系统整体性能,而过期或错误失效的条目会破坏文件系统视图。这正是后来 HTTP 缓存中同一取舍的紧凑示例:只有当失效规则正确时,复用才有价值。

phkmalloc(Kamp 历史上的分配器工作)解决了另一种常见成本。通用分配位于几乎所有服务之下,分配器行为会影响碎片、锁和局部性。这一历史实现不应被当作适用于当今所有系统的答案。其意义在于,性能工作往往从被测功能的下方开始。即使 HTTP 逻辑高效,Web 缓存也可能受限于分配和对象生命周期。

sbuf工作为内核和基础系统代码提供了更安全的动态字符串构造。由部分数据构建的字符串是截断和内存错误的常见来源。共享原语并不能让所有调用者都正确,但它减少了每个子系统临时拼凑缓冲区管理的需要。这是更安静的系统工程形式:从许多未来调用点移除一个重复的错误来源。

设备和 DEVFS 工作处理的是硬件如何呈现给软件。设备是有生命周期、命名和权限问题的物理或虚拟资源。一致的命名空间和附加模型使后来的驱动程序和运维工具能够对它们进行推理,而不必各自发明私有约定。

不应把这些贡献夸大为 Kamp 独自设计了 FreeBSD 的现代基础系统。他自己的档案是第一人称证据,后来的开发者进行了大量工作。可辩护的结论在于方法。他反复在那些好处会随上层调用者数量而成倍增大的接口上工作。

在常规人物档案中,这种倍增很容易被忽视,因为没有客户标志能标明谁从一个更安全的字符串原语或更可预测的时钟抽象中受益。基础设施的价值往往表现为重复代码、可避免的崩溃或重复 I/O 的消失。只有在原语失效或必须被替换时,这项工作才会显现。

Kamp 的记录包括 GBDE 磁盘加密和通常称为 MD5crypt 的密码哈希格式。两者都属于对他系统工作的完整叙述,也都需要明确的历史边界。

GBDE 在 FreeBSD 存储中应用了密码变换。它符合 GEOM 时代关注围绕块设备组合功能的问题,尽管当前 FreeBSD 用户还有其他选择,而当前安全建议取决于威胁模型、实现和支持。早期加密设计证明有人在保密性和依赖密钥的存储上做过工作,但不证明应在新部署中选用这一历史机制。

MD5crypt 是为密码存储而设计的,当时单纯的快速 MD5 哈希需要通过带盐和重复工作的格式来加强。该格式传播到许多类 Unix 系统和网络设备。现代密码安全已转向刻意昂贵且感知内存的密码哈希,因为廉价通用哈希容易遭受大规模猜测攻击。正确的编辑处理是“有期限的影响”:一个设计可以在一个时期改善实践状态,之后变得不再合适。

这种按时期区分的纪律在基础设施报道中尤其重要。在指导方针改变很久之后,旧软件仍存在于设备和嵌入式产品中。把一个机制称为“广泛部署”听起来可能像推荐,而实际上它可能描述的只是技术债。归功于作者并不等于要为后来每个供应商继续使用它的决定负责。

这一原则同样适用于 Varnish 配置、FreeBSD 子系统和时间协议。功能名称可以保持不变,而实现和威胁假设已经改变。人物档案应当区分最初的问题、历史贡献、当前维护和现今的部署建议。

Kamp 愿意在文章和计算机史工作中重新审视旧系统,使这种区分成为主题的一部分,而不是编辑上的麻烦。系统工程师会继承自己过去的决策。成熟的实践会记录某个选择为何合理、什么发生了变化,以及用户如何在不假装早期工作毫无意义的情况下迁移。

Jails 让隔离成为内核原语,而非应用约定

FreeBSD jails 通过结合文件系统、进程、网络和管理限制,将进程隔离扩展到传统chroot模型之外。这一想法允许多个服务环境共享一个内核,同时各自看到受约束的系统视图。

Kamp 的早期贡献是有据可查的历史的一部分,后来的 jail 开发则属于更广泛的 FreeBSD 社区。这一区分尤其重要,因为 jails 已演化为一整套大型运维特性。开创者可以建立模型,而不必为后来的每一条安全边界、管理工具或部署负责。

其架构意义很明确。与每个应用程序自行同意守规矩相比,由内核强制执行隔离更可靠。被监禁的进程可以被限制为看不到其他进程组或网络资源,具体取决于配置和共享内核的威胁模型。运维人员可以运行服务,使爆炸半径缩小,开销也低于独立物理机。

jail 并不能保证防范每一次逃逸或内核漏洞。环境共享同一个内核。特权配置和设备暴露都很重要。网络设计可能削弱隔离。该机制降低了权限并创建了更清晰的边界;它并没有消除安全工程的需要。

同样的思路再次出现在 Varnish 的管理进程与工作进程分离中。处理流量的子进程不需要所有管理权限。父进程可以重启它并控制配置。进程边界分配故障后果,而不是假设一个大进程会保持正确。

jails 还展示了原语的经济价值。托管提供商和系统管理员可以围绕隔离构建服务,而不必各自发明私有机制。内核项目承担维护边界的成本,用户则同时继承其好处和缺陷。当所有权和更新路径清晰时,这种转移是可以接受的。

GEOM 将存储视为可组合变换的图

存储系统常常叠加功能:一块磁盘可能被分区、镜像、加密、打标签,并通过另一层抽象暴露。如果没有一致的框架,每个特性都可能包含自己的设备发现和 I/O 管线,造成重复和难以处理的交互。

GEOM 为 FreeBSD 提供了用于组合存储变换的模块化框架。提供者和消费者在图中连接,使各个类可以实现分区、镜像或加密等操作。该框架为内核提供了一种共同语言,用于描述存储层如何附着和传递 I/O。

Kamp 被记载为主要架构师和贡献者。后来的 GEOM 类及维护属于项目。其意义同样在于机制而非完整产品:定义契约,使多个功能可以共存,而不必每一个都成为私有栈。

组合也有成本。每一层都可能增加元数据、故障行为和恢复要求。加密层需要密钥;镜像需要状态协调;分区层有自己的几何。当底层设备故障而运维人员不理解变换顺序时,代码中优雅的图可能难以修复。

因此,GEOM 反映了 Kamp 系统哲学的两个方面。清晰的接口减少重复实现,但并不能免除运维人员理解由这些接口组装而成的系统。通用原语可能使组合数量超出任何单个团队的测试能力。

与 Varnish 的比较并不是说 Web 缓存和块 I/O 相同,而是两者都提出了同一个问题:哪个层次应该拥有状态,以及如何在不过度复制或隐藏的情况下组合变换。Kamp 在内核中的工作使他对应用开发者常常回避的操作系统抽象充满实际信心。

Timecounter 让时钟成为系统责任

操作系统内部的可靠时间听起来简单,直到硬件时钟相互不一致、漂移、停止或提供不同的分辨率和稳定性。应用想要一个单调、准确的时间尺度;内核必须组合硬件源和校正机制,而不能要求每个子系统都理解振荡器行为。

FreeBSD 的 timecounter 工作创建了硬件时间源之上的抽象。Kamp 的贡献属于更广泛的内核计时史和后续维护。该模型使系统能够按质量选择和使用计数器,同时通过共同接口向操作系统其余部分暴露时间。

这项工作引出了 Kamp 对 NTP、PTP、硬件基准和传统时间协议弱点的长期兴趣。时间基础设施组合了振荡器、网络延迟、内核校正和运维监测。协议消息可以正确,而本地时钟却不稳定。高分辨率计数器可以既精确又不准确。网络路径可能引入简单的往返估计无法消除的非对称延迟。

计时看起来与 HTTP 缓存相距甚远,但架构问题相似。哪个层次应该负责校正?什么状态具有权威性?系统如何暴露不确定性,而不是给出一个误导性的数字?在每个应用中重复时间逻辑,会比维护一个强内核和协议边界更糟。

运维风险很高。日志、分布式事务、证书和度量都依赖时间。一个错误可能使事件看起来顺序错乱,或使安全决策失效。时间基础设施值得独立监测和回退,而不是盲目信任某一台服务器。

Kamp 近期的文章和实验工作继续把时间作为系统问题对待。公开记录表明他长期关注,而不是声称某个实现取代了 NTP 或 PTP。其价值在于坚持认为时间应当从硬件、协议到内核进行工程化,而不是被当作一种没有所有者的公用事业。

Kamp 在 timecounter、NTP、PTP 实验和计时硬件方面的工作,构成了 Varnish 之外的第二根技术支柱。时间看起来可能像操作系统可以获取一次然后分发的服务。实际上,一台机器组合了不完美的振荡器、硬件计数器、中断和调度延迟、内核换算、同步协议以及对误差容忍度各不相同的应用。

FreeBSD 的 timecounter 抽象使内核可以通过共同接口从可用硬件源获取时间。计数器可能具有高频、有限宽度、漂移、回绕行为或平台特定的访问成本。内核必须把这些 tick 转换成有用的时基,并在多个源之间做出选择,同时不让设备怪癖泄漏到每个应用中。

这是把状态放在正确层次的又一案例。应用不应各自读取硬件计数器并发明校正。内核所处的位置适合维护一致的系统时钟并通过共同接口暴露它。网络协议可以根据外部基准估算偏移和频率。监测随后可以检测本地时钟或参考路径何时变得不可靠。

NTP 和 PTP 解决相关但不同的运维问题。NTP 在通用网络间分发时间,必须容忍可变延迟和不完美的服务器。PTP 可以在受控环境中借助硬件时间戳和网络支持实现更紧密的同步。两种协议都无法废除振荡器物理特性、路径非对称或糟糕的运维设计。

Kamp 对传统协议和实现选择的批评应被视为技术论证,而非自动共识。其意义在于把隐藏的链条显式化。日志或数据包捕获中的时间戳是硬件、内核和协议决策的输出。当这些层次不一致时,分布式系统可能打乱事件顺序、使证书失效、破坏度量或让事故重建不可靠。

与 Varnish 的联系并不在于 Web 缓存需要实验室级时钟,而在于反复强调必须由某一层拥有度量,并暴露足够证据让系统其余部分信任它。缓存生命周期、日志时间戳和超时都是关于时间的决策。如果时钟不稳定或其不确定性被隐藏,更高层的正确性就难以证明。

精密计时工作还说明了独立工程的局限。构建参考或实验守护进程可以揭示协议问题,但生产时间服务取决于硬件供应、网络拓扑、内核集成、长期观测以及能够对漂移作出响应的运维人员。没有任何单一实现能控制整条链条。

客户资助的项目把架构变成了开放产品

委托关系至关重要。Varnish 并非为了赢得某项合成竞赛而发明。它有客户、工作负载和运维反馈。新闻出版商有流量突发、频繁变化的内容,以及在高需求下延迟至关重要的后端系统。缓存必须快速提供对象,并避免提供错误对象。

初期资金还说明了开放基础设施可以如何开始。客户付钱解决具体问题,产生的代码被发布供更广泛使用。社区可以测试其他工作负载并改进系统。资助方获得解决方案,而不必拥有封闭产品。

公开证据并未披露完整合同金额或条款。它支持起源和生产关系的说法,而不是财务估算。不应把 VG 的角色转换成对 Varnish 的当前所有权,正如不应把 Kamp 的作者身份转换成对每一次部署的所有权。

决定新建缓存而不是扩展现有缓存,反映了架构判断。Kamp 认为传统方法带有旧操作系统的假设,并重复了内核缓存。干净的设计可以利用现代虚拟内存和狭义的 HTTP 加速范围。

从头开始也会带来风险。成熟项目包含多年的协议边界情况。新实现必须通过测试和事故来学习这些情况。生产资助方提供了能尽早面对这些假设的环境。

虚拟内存成为缓存管理器

Varnish 的决定性存储选择是使用内存映射,并让操作系统管理页面驻留。缓存对象可以表示在地址空间中,由内核决定哪些页面保留在 RAM 中、哪些被回收或由存储后备。

该设计避免了应用内部的第二套缓存替换系统。传统缓存可能在内存中跟踪对象,将其写入文件,之后通过内核页面缓存读回,从而产生副本和重复状态。Varnish 可以引用映射数据,并让缺页或驱逐反映操作系统的全局内存决策。

这有时被概括为 Varnish 是内存缓存。这种说法不完整。该架构可以使用文件或内存作为后备存储,操作系统会根据压力移动页面。磁盘并非缺席,而是通过虚拟内存行为管理,而不是通过传统形式的用户态对象 I/O 引擎。

这种方法依赖内核。页面替换、回写、文件系统行为和地址空间限制都会影响性能。无关进程的内存压力可能改变驻留情况。容器或虚拟机可能有与主机交互的限制。运维人员需要系统级可观测性,而不仅仅是缓存命中率。

收益是请求路径上的工作减少。对象不必在每次复用时经过多个缓冲区复制或由应用逻辑同步读取。CPU 可以把更多时间用于 HTTP 决策和网络 I/O。

该设计也是对信任的一种声明。Kamp 信任成熟的虚拟内存系统来完成应用开发者经常重新实现的任务。这种信任来自内核经验。并非所有应用都应把存储委托出去的普遍规则。对持久性、访问或控制要求不同的工作负载可能需要另一种设计。

因此,Varnish 的性能声誉应当在具体工作负载中表述。可缓存性、对象大小、后端延迟、请求组合、内存、内核和配置都很重要。基准测试只证明其在测试范围内的行为,并不证明对每个代理或 CDN 的永久优越性。

当虚拟地址空间被当作对物理 RAM 的陈述时,Varnish 的内存映射设计最容易遭到误解。映射对象只是给进程一个地址,内核可以通过该地址提供页面,并不要求每个映射页面都同时驻留。

这一区别使大地址空间变得有用。应用可以引用大于即时驻留内存的缓存,由操作系统决定哪些页面处于活跃状态。在地址空间受限的系统上,映射的数量和大小可能在物理存储耗尽之前就成为限制。

因此,常驻集大小只是容量分析的一部分。运维人员需要理解映射存储、缺页、回收、文件系统后备以及其他进程的压力。即使主机有空闲内存,容器限制也可能改变实际行为。交换或大量缺页活动可以保持正确性,同时毁掉延迟。

该架构避免了应用层驱逐引擎,但并没有移除驱逐。它把决策移入内核策略,Varnish 在此处直接控制较少,却能受益于系统全局知识。当操作系统值得信任,且主机按单一系统而非带有隐藏交互的隔离应用配额进行配置时,这种取舍效果最好。

这是 Kamp 方法的一个精确例子。重复的缓存管理器被移除。剩下的层次变得更加重要,必须用正确的指标进行观测。“Varnish 使用内存”是不完整的运维陈述;有用的问题是虚拟内存在压力下如何提供工作集。

VCL 让缓存策略既可执行,也可审查

缓存不能仅凭状态码判断正确性。它需要针对 Cookie、认证、请求方法、标头、后端选择、新鲜度、失效和例外的规则。Varnish Configuration Language 将这些决策暴露给运维人员。

VCL 被翻译成 C 并编译为可加载对象。运行中的系统可以在管理控制下加载配置并在配置之间切换。编译型策略避免了对每个请求解释高级语言,并让运维人员无需修改守护进程源码即可结构化地更改行为。

其能力相当可观。VCL 程序可以选择后端、修改标头、决定请求是否可缓存、设置 TTL 值、实现清除,并按条件引导流量。即使由基础设施团队维护,它也成为应用架构的一部分。

这种能力也带来风险。语法上有效的策略可能缓存个性化内容、忽略认证或把流量发送到错误后端。一条规则可以提高命中率,同时违反正确性。变更需要版本控制、测试、分阶段发布,以及既懂 HTTP 又懂应用的人员审查。

编译增加了一条信任边界。调用编译器的进程、模块路径以及任何内联或扩展代码都必须受到控制。VMOD 可以增加能力,也会扩大攻击面。快速的策略语言并不会自动变得安全。

VCL 还改变了组织责任。应用团队控制缓存标头;平台团队控制 VCL;安全团队关注 Cookie 和认证。事故可能源于这些团队之间的某个假设。该语言让策略足够明确以供审查,但不能自行协调所有权。

这是 Kamp 最具影响力的设计选择之一。性能没有被硬编码到某个产品配置中。运维人员可以在接近请求路径处表达策略。由于机制与本地决策分离,该系统在不同应用之间仍然有用。

反向代理缓存只有在向正确的请求者提供正确表示时,才能降低后端负载和延迟。HTTP 包含旨在支持这一决策的元数据,而实际应用经常产生模棱两可或不一致的信号。

新鲜度可以通过缓存指令和过期时间控制。Vary表示不同的请求标头产生不同的表示。Cookie 和授权通常意味着个性化。某个响应在后端故障期间可能可以安全地提供过期内容,但在用户变更后又不宜复用。

Varnish 暴露这些决策,而不是声称每个成功响应都可缓存。运维人员可以调整策略,并为结果承担责任。通过忽略Vary或认证取得的高命中率是数据完整性失败,而不是性能成功。

失效是另一条困难边界。按 URL 清除对象可能不会移除所有变体。Ban 规则可以匹配分组并消耗资源。应用事件可能被延迟或丢失。较短的新鲜期能降低过期风险,但会减少后端节省。不存在通用的失效策略。

后端行为同样塑造缓存。缓慢或故障的源站会造成队列和重试。提供过期内容可以在符合策略的情况下保持服务。健康检查可以移除后端,但如果配置不当也可能放大故障。Varnish 是分发系统中的一层,其正确性取决于应用和源站基础设施。

架构纪律在于把这些取舍显式化到策略和可观测性中。Varnish 可以很快,因为它避免工作,但它绝不能回避判断复用是否有效所需的工作。

快速路径与控制、观测和容量限制保持分离

Varnish 使用一个管理进程和一个工作进程(缓存进程)。管理侧控制配置、参数和子进程生命周期。工作进程处理流量。如果子进程失败,父进程可以收集信息并重启它。

这种分离降低了流量处理进程的权限和持续性。崩溃并不要求管理层随之消失。新 VCL 可以在受控条件下编译和加载。启动后可以根据平台和配置降低权限。

重启并不能从每次故障中恢复。内存状态可能丢失。客户端可能看到错误。反复崩溃会形成循环。后端或操作系统可能才是真正原因。运维人员需要崩溃诊断和限制,而不是把自动重启当作韧性的证明。

这种分离还支持升级和配置切换,但高可用属于更大的架构。如果单个 Varnish 进程不能成为单点故障,通常需要多实例、负载均衡器、健康检查和容量。

这一模式类似 Kamp 的内核工作:定义边界,使一个组件在发生故障时不必拥有整个系统的所有权限。价值在于实际遏制,而非完美隔离。

Varnish Shared Log 将结构化事件记录写入共享内存。工具可以读取请求、后端和缓存事务,而不必强制工作进程把每个事件同步追加到传统文件。

此设计减少了阻塞,并允许不同消费者检查同一数据流。运维人员可以追踪请求、聚合指标或将日志导出到另一系统。大流量记录保持在进程附近,而长期存储被委托出去。

共享内存是有限的。随着环形缓冲区前进,落后的消费者可能错过记录。用于事故调查的工具应当导出或保留必要数据,而不是把实时日志当作档案。

事件模型是专门化的。一个事务可能涉及客户端和后端请求、重试与缓存决策。理解记录需要熟悉 Varnish 标识符和生命周期。结构化日志改善了机器处理,但并没有消除对模式的需求。

隐私和安全同样适用。标头、URL 和后端信息可能包含敏感数据。导出方应减少字段并控制访问。快速日志可能产生大容量,其存储成本超过缓存自身的资源消耗。

该架构再次把工作从关键路径移出,并把责任转移到别处。Varnish 高效地暴露详细证据;运维人员拥有保留、搜索和访问策略。

Varnish 的工作模型使用线程和池来处理大量并发连接。一个线程可以在某些操作上阻塞而不停止所有流量,同时由系统控制创建和资源限制。

线程消耗栈和调度器注意力。太少会令客户端排队;太多会耗尽内存或增加争用。慢客户端和慢后端以不同方式占用资源。连接行为、keep-alive、超时和操作系统限制都影响安全范围。

实现已经演进,精确调优取决于部署版本。一般要点是:缓存很快并不代表并发免费。运维人员必须监测线程队列、丢弃、后端延迟和内存压力。

内存中命中缓存的工作负载不同于反复未命中并等待源站的工作负载。以命中为主的基准对后端变慢时的故障行为几乎无话可说。容量规划应包括未命中风暴、清除和重启场景。

Varnish 的窄数据路径为运维人员提供了清晰的计数器和控制。它也暴露了一个现实:性能是系统属性,内核网络、调度器、内存、存储、后端和应用策略都参与其中。

开放代码、商业支持与自愿资助仍是不同层次

Varnish Cache 是一个开源项目,拥有当前维护者、发布、软件包和模块。Varnish Software 是一家围绕该技术提供产品和服务的独立商业公司。Kamp 是原始架构师,仍与项目保持联系,但他并不拥有或控制当前的每一项决策或商业产品。

随着采用范围扩大,这一区别变得更加重要。企业想要支持、打包特性和问责。公司可以提供这些服务,并开发专有或另行治理的组件。上游项目维护公开代码库和社区流程。

商业活动可以支持开放开发,也会产生分歧的激励。客户可能要求不适合核心的功能。公司可能拥有比无附属维护者更大的工程能力。商标和产品名称可能让用户混淆自己购买的是哪一层。

一份站得住脚的人物档案应把架构和初始实现归功于 Kamp,把持续发布归功于当前维护者,并把 Varnish Software 的业务视为其自身的机构记录。不应把某一层的部署声明记到另一层头上。

这一原则同样适用于 FreeBSD。Kamp 历史上的核心团队和子系统工作很重要;当前项目由现有结构治理。当作者身份能得到尊重而不演变为永久所有权时,开放基础设施才能持久。

Kamp 与 Beer-Ware License 相关联。这是一份非正式的宽松文本,允许使用,并建议相关方见面时请作者喝杯啤酒。该许可证以刻意朴素的语言表达社会互惠。其法律适用性取决于语境,有正式合规要求的组织可能更倾向传统许可证。

Varnish Moral License 解决的是另一个问题。它是一种自愿机制,受益于 Varnish 的组织可以借此支持 Kamp 的工作。它不是软件许可证,使用代码并不要求它。“道德”框架意在让用户认识到宽松法律许可证无法强制他们出资支持的维护劳动。

Kamp 早在 2004 年就试验过对 FreeBSD 工作的直接社区赞助。这一模式显示出他对基础设施维护经济学的持续关切。被广泛使用的代码可以创造可观价值,而负责困难且非功能性工作的人获得的却是不确定的支持。

公开证据并未提供完整的年收入、参与者人数或项目预算。这些资金机制应被描述为实验,而非经过验证的通用模型。自愿捐助可以支持独立工作,也可能不可预测。

更广泛的教训是,代码效率并不会消除劳动。在最初的性能问题解决后,协议变更、安全审查、文档和发布仍在继续。一个减少机器工作的项目,仍可能依赖资金不可见的人类工作。

Kamp 的职业生涯并不符合简单的雇佣头衔序列。他目前的公开身份是独立、自雇的系统程序员和写作者。这种独立性可以保护他从事公司路线图之外的工作,但也暴露出维护基础设施的财务脆弱性——因为受益者分散。

2004 年的 FreeBSD 赞助实验、Beer-Ware 文本和 Varnish Moral License 处理的是这一问题的不同部分。直接赞助请求社区为开发时间出资。Beer-Ware 使用宽松的社会性请求,而非支付义务。Moral License 请求从 Varnish 获得可观价值的组织自愿捐助,而不改变其使用代码的合法权利。

在公开记录中,这些机制都没有提供完整项目预算。它们的重要性在于让一种令人不安的依赖变得可见。宽松许可证可以消除法律摩擦、让采用变得容易,但不能保证安全分诊、协议工作、文档和发布工程会得到资助。

公司常常通过雇佣维护者、购买支持或资助基金会间接解决这一问题。独立贡献者可能依靠咨询、赞助和自愿支付。每种模式都会塑造优先级。客户资金可能把注意力引向紧急部署。会员资金可能偏向大型参与者。自愿支持可能广泛但不可靠。

Kamp 的模式请求受益者在获得价值之后认可它。这种方法保留了自由,避免把上游变成订阅产品。但它也依赖采购系统并不擅长作出的道德回应。公司可以完全合规却分文不捐。

对使用 Varnish 或其他开放基础设施的领导者而言,这不是可有可无的慈善问题。维护者能力影响漏洞响应、工具链兼容性和协议时效。通过开源节省的成本,可能在无人受薪承担困难工作时以连续性风险的形式重新出现。

当决策权不清晰时,“Bikeshedding”是治理成本

Kamp 的技术文章常常从代码进入项目治理。bikeshedding 一词描述的是群体倾向于在简单、显眼的细节上花费过多注意力,而更难的决定却得到较少讨论。他 2026 年 7 月发表在 ACM Queue 上的文章延续了这种机构层面的反思。

这一现象不只是烦人的会议行为。基础设施项目的审查者注意力有限。关于命名的长时间争论可能推迟安全或架构决策。贡献者在自己有信心的领域参与,这可能使琐碎问题吸引的声音超过专业问题。

清晰的范围和决策权可以降低成本。维护者应当说明哪些反对意见具有实质意义、何时共识足够、何时必须作出决定。过度的中央权威会压制有用的审查;未定义的过程会让每项变更都受制于无休止的讨论。

Varnish 刻意保持的窄化在一定程度上是治理工具。拒绝成为通用 Web 服务器限制了项目需要裁定的特性数量。FreeBSD 的子系统接口同样将决策局部化。范围不仅是架构问题;它决定了一个仓库内有多少社区和激励相互碰撞。

Kamp 的论辩风格是其观点的第一人称证据,而不是每个项目都遭遇同样失败的外部证明。这些写作之所以有用,是因为它把技术复杂性与接受并资助它的社会系统联系起来。

窄核心把风险转移到扩展边界

窄缓存避免成为完整的应用服务器,其范围之外的功能可能需要 TLS 终结器、负载均衡器或另一代理。依赖内核虚拟内存简化了对象存储,并使内核调优变得重要。编译后的 VCL 降低请求开销,但需要安全的构建路径。每一次减法都有相邻的所有者。

这不是矛盾,而是架构的结果。系统可以通过清晰分配责任来变得更简单,而不是让总工作量消失。运维人员必须判断所选边界是否与团队专长和支持安排匹配。

现代 HTTP 增加了压力。HTTP/2、HTTP/3、TLS、边缘计算和复杂路由可能由 Varnish、相邻项目或商业产品处理,具体取决于版本和架构。不应把最初的每个后来特性都当作其创始范围的一部分来评判原始设计。

安全性和正确性也会抵制极简主义。缓存策略需要足够信息来保护个性化数据。可观测性系统需要足够细节来诊断故障。移除拥有必要控制的特性,只是隐藏了依赖。

Kamp 最重要的教训并非最小化每个程序,而是移除重复工作,并让剩余的所有者显式化。当相邻系统拥有该功能时,接口和故障路径应当被理解。

聚焦的缓存无法预见每一种认证方案、标头变换、路由决策或应用特有功能。通常称为 VMOD 的 Varnish 模块让运维人员和开发者可以在不把每个特性都放进核心守护进程的情况下扩展 VCL。

这种模式支持 Kamp 对窄基础设施的偏好。核心可以保留稳定的请求引擎并暴露扩展接口。专用代码可以随需要它的组织或供应商演进。模块可以集成那些作为通用默认值不恰当的数据、密码学或策略。

可扩展性造就了一条软件供应链。VMOD 可以在敏感进程上下文中运行、处理请求数据并影响缓存或后端决策。其源码、构建系统、发布节奏以及与所部署 Varnish 版本的兼容性,都成为安全边界的一部分。

升级期间二进制或 API 兼容性很重要。Varnish 发布可能改变接口,从而要求模块重建或更新。商业发行版可能支持一个上游未维护的模块。依赖某个扩展的组织需要知道自己能否独立重建、替换和审计它。

模块还影响事故归因。崩溃或错误响应可能源于核心代码、VCL、VMOD 或缓存背后的应用。共享内存日志和崩溃证据应保留足够上下文来区分这些层次。把每次故障都称为“Varnish”,会掩盖能够修复它的所有者。

这种治理取舍类似 FreeBSD 的子系统模型。共同接口使专用组件得以存在,而不必集中每个决策。接口仍需要维护者,以拒绝不安全假设并传达生命周期变化。

对领导者而言,扩展清单与 Varnish 版本同样重要。当许多模块、私有 VCL 库和管理包装器围绕核心累积时,极简核心也可能产生复杂部署。只有当移出核心的责任在别处得到命名和支持时,Kamp 的方法才仍然有效。

Varnish 由周围分发栈所拥有的一切来界定

Varnish 通常部署在客户端(或边缘代理)与应用源站之间。当对象可复用时,这一位置可以保护源站免于重复工作、降低响应延迟并吸收流量突发。它还把缓存放进一条可能包含 DNS、TLS 终结、负载均衡、Web 应用防火墙、内容管理系统和托管分发网络的链条中。

因此,通过排除法更容易理解产品边界。Varnish 不是完整的内容分发网络。它不会仅因某个 CDN 可能使用缓存就拥有全球接入点、客户路由、证书操作和托管控制平面。它不是应用服务器,不决定页面的业务含义,也不自动成为现代架构中最佳的 TLS 端点或唯一代理。

这些排除是性能策略的一部分。每增加一项责任都会增加代码路径、配置、状态和安全审查。聚焦的 HTTP 加速器可以优化对象生命周期和请求路径。集成式边缘平台可以通过拥有更多链条来简化采购和运维。选择取决于组织更重视组件控制,还是更重视整合的服务边界。

NGINX、Apache Traffic Server、Squid 和 HAProxy 与这一领域的不同部分重叠。NGINX 结合了 Web 服务、代理和缓存。Traffic Server 是拥有自身架构的实质性缓存代理。Squid 在正向和反向代理使用上历史更久。HAProxy 专注负载均衡和代理功能,而非呈现相同的缓存模型。托管 CDN 增加了全球基础设施和商业运营。

有用的比较不会问哪个名字普遍最快,而是问哪个组件拥有缓存语义、TLS、路由、健康、配置、可观测性和支持。当运维人员想要明确的 HTTP 策略并能集成相邻系统时,Varnish 的设计会很有吸引力。当组织不想要拥有这种集成时,托管边缘服务可能更合适。

这种竞争环境也改变了锁定的含义。开源缓存减少了对单个托管后端的依赖,但部署可能被定制 VCL、VMOD、专有管理层或未文档化的应用行为绑定。可移植性存在于源码和架构中,却仍需要有纪律的配置和测试。

Varnish 的聚焦范围可以让架构替换比替换集成式边缘平台更容易。源码、VCL 和 HTTP 边界都是可见的。当组织依赖未文档化的默认值、私有模块或仅存在于生产环境中的应用程序假设时,这一优势就会消失。

迁移需要行为测试:哪些响应可缓存、变体如何分离、何时允许过期内容、失效如何运作,以及源站故障时会发生什么。两个代理可以接受相似配置,却在一个 HTTP 边界场景上表现不同。

这是状态所有权的另一种形式。可执行配置记录了部分策略;测试记录了预期结果。缺少两者,开放组件就可能在运维上被锁定,即使没有任何许可证阻止替换。

Kamp 的极简架构减少了需要迁移的责任数量,但并没有消除保留剩余责任的需要。

故障测试比缓存命中基准更能说明问题

Varnish 因性能声明而广为人知,但最具揭示性的生产测试往往是降低可缓存性或破坏相邻层次的那些测试。当对象都是热点、源站健康时,站点可能看起来很高效,却会在清除、未命中激增或后端变慢时急剧失败。

缓存未命中风暴改变了瓶颈。以前在工作进程内结束的请求现在要等待源站容量。如果许多客户端请求同一个未缓存对象,请求合并或相关策略可以保护后端,具体取决于版本和配置。如果应用生成许多变体,缓存可能消耗内存却未能实现有用的复用。

内存压力是对虚拟内存取舍的又一检验。内核可能回收页面、产生缺页或与其他进程竞争。缓存可以在逻辑上保持正确,而延迟却变得不稳定。运维人员除了 Varnish 计数器,还需要主机级内存和分页证据。

配置重载和重启测试暴露运维所有权。团队应知道哪些对象能存续、客户端如何排空、失败的 VCL 如何被拒绝,以及工作进程崩溃在监测中如何呈现。只有当响应者能区分瞬时进程故障与重复缺陷或资源耗尽时,自动重启才有用。

后端健康策略也需要故障注入。过于激进地移除容量的检查可能把局部问题变成全面中断。提供过期内容可以保持可用性,也可能违反即时新鲜度的要求。正确的策略取决于应用,而不是仅取决于缓存。

这些测试支持 Kamp 更广泛的系统论点。性能不是峰值请求速率,而是在状态变化、资源紧缺和组件故障时交付有用的工作。只要剩余边界经过测试而非想当然,移除重复机制就能改善这种行为。

持久的方法是把状态放在能够被拥有的地方

在 FreeBSD、Varnish 和计时工作中,Kamp 反复追问状态应该放在哪里。jails 把隔离放在内核。GEOM 把存储组合放在共享框架。timecounter 抽象硬件时钟。Varnish 把驻留委托给虚拟内存,并通过 VCL 暴露 HTTP 策略。共享日志把事件产生与保留分开。

这些设计各不相同,却共享一条纪律:避免两个层次维护相互竞争的同一事实版本。重复状态会产生同步工作和不明确的故障所有权。当共同原语足够强大时,它可以同时减少两者。

这一方法也解释了 Kamp 对资金和治理的兴趣。如果没有人拥有维护,代码所有权就不够。如果每场功能讨论都能无限扩大项目范围,范围就不清晰。技术上的减法需要制度边界,以便在原作者离开后仍然保住决策。

Varnish 当今的社区和 FreeBSD 的持续演进表明,这项工作已经超越单个工程师。这一转变本身就是成就的一部分。衡量 Kamp 影响力的最佳方式,是看他人能维护哪些系统,以及他的架构迫使运维人员回答哪些问题。

性能只是结果之一。更深层的结果是可读性:重复机制更少、控制面更清晰,并且在系统故障时更有机会确定应当修复哪个层次。