乐于分享
好东西不私藏

Delphi开发的软件-8:开源跨平台高性能 REST 服务器框架mORMot 2

Delphi开发的软件-8:开源跨平台高性能 REST 服务器框架mORMot 2

Delphi/Object Pascal 仍然是高性能 REST 服务器的有力竞争者

感谢法国Pascal程序员Arnaud Bouchez对mORMot 2库的贡献。mORMot 2 是一个极其庞大、全面且高度优化的库,用于使用 Delphi 构建 Web 服务(以及其他服务)。Arnaud 多年来一直致力于开发这款开源工具,其成果令人瞩目。
在本文中,我们将深入探讨使我们的开源mORMot 2库能够与 nginx、Kestrel 和原始 C++ 实现竞争(有时甚至超越它们)的架构。
该库提供了多个 HTTP 服务器。mormot.net.server单元包含传统的mORMot1Web 服务器——主要包括THttpServer用于 HTTP/1.0 短请求的线程池以及每个保持活动的 HTTP/1.1 连接一个线程,以及THttpApiServer(在 Windows 上使用高效的 http.sys 内核 API)。
但自mORMot 2起,我们的mormot.net.async单元才是真正跨平台的现代化异步实现。

正如 Linus 所说:一切都与数据结构有关。

在mORMot 2中开发异步 HTTP 服务器多年后,我确信语言的选择远没有人们想象的那么重要——真正重要的是工程决策
该服务器经常在 TechEmpower 排名中名列前茅(包括多次在缓存 ORM 结果中排名第一)。
以下是我们搭建它的方法。

操作系统专属网络:没有万能的解决方案

我们特意针对不同平台采用不同的策略:
  • Linux:epoll采用边沿触发通知的直接模式。简洁、成熟,对于我们的事件驱动模型来说极其高效。我评估过io_uring,但最终认为对于普通以太网上的典型 REST/JSON 流量而言,增加的复杂性得不偿失。
  • Windows:IOCP采用非对称模式。通常情况下,我们通过 IOCP 注册接收数据,但对于较小的动态响应(主要情况),我们send()直接调用套接字进行写入操作,而不是注册写入操作。只有大文件传输才会经过完全重叠的 I/O 注册。
  • BSD发行版(如 MacOS 或 OpenBSD/FreeBSD):poll提供足够好的性能的常规 API。
在这些平台上,切换到异步模式后,仅需几个线程即可处理数千个并发连接。这是我们之前THttpServer版本的主要优势,而之前的版本即使在 nginx 代理等环境下也能发挥出色性能。
http.sys在 Windows 系统上,`http.sys`和`http.sys` 之间的差异IOCP非常显著。微软长期以来一直将 `http.sys` 宣传http.sys为 Windows 平台上的终极高性能解决方案。由于内核模式缓存和零用户模式转换,它在处理静态文件方面表现出色。然而,对于用户空间生成的动态内容(例如 JSON、模板化的 HTML 等),我们原始的 IOCP 实现实际上速度更快——我的测试表明,在处理 4KB 的 JSON 数据时,使用 IOCP 比使用 `http.sys` 快了大约 50%。有时,通用内核抽象带来的开销甚至超过了它节省的开销。
在 TechEmpower 基准测试中,我们通过在同一进程内运行多个 HTTP 服务器实例来实现扩展,将负载分散到可用的核心上,并尽可能共享内存。这种方法虽然简单,但非常有效。在现代硬件和操作系统上,有时无需在代码中完全切换到异步模型,而且由于编译器的一些“魔法”(例如隐藏的状态机),还会增加一些额外的开销。

记忆训练:真正的秘密武器

现代性能的限制因素往往是分配器压力和缓存未命中,而不是原始的 CPU 周期。
我们mormot.net.async竭尽全力避免在热路径上进行分配:
  • 典型的静态 GET 请求只需要分配一次内存——URI 字符串。所有其他缓冲区都是静态的或可重复使用的。
  • 响应构造、标头生成和 JSON 序列化会积极地重用预分配的结构——这正是mormot.core.json库内核的优势所在。
我们还依赖于经过高度优化的基数树(压缩trie树)进行URI路由和解析。它提供了卓越的查找性能、低内存开销和可预测的缓存行为。
这种避免内存分配的设计是 Pascal 保持竞争力的主要原因之一:该语言让我们能够很好地控制内存布局和生命周期,而无需像高级语言那样承担通常的安全/GC 成本。

制作特色做得好

性能若缺乏可操作性则毫无意义。因此,我们集成了多项关键功能,并将对关键路径的影响降至最低:
  • 通过THttpAcceptBan易于加载的 Spamhaus 或自定义 CIDR 黑名单来缓解 IP 威胁
  • 身份验证——基本身份验证、摘要式身份验证、JWT 身份验证以及通过 SSPI/GSSAPI 实现的完整企业级 Kerberos 身份验证
  • 高效日志记录(采用与THttpLogger Apache/Nginx 兼容的格式,但设计用于在高吞吐量下实现低开销)
  • 通过全球分析和监控,THttpAnalyzer提供汇总的响应统计数据,例如按月/日/小时统计。
  • 通过mormot.net.ws.async单元准备 WebSocket
由于mORMot 2被用于多个业务关键型项目,我们可以在各种生产环境中获得最终用户的即时反馈。

现实世界的复杂性:渐进式缓存

我们的一项独特功能是代理/对等缓存支持。
当提供部分填充的内容(数据仍在从其他后端连接到达)时,我们使用注册写入和一个轻量级后台线程,在新数据块可用时推送它们。资源加载完毕后,我们会切换到快速的直接发送路径。
这种设计优先考虑并发客户端之间的稳定带宽共享,而不是单个客户端的峰值吞吐量——这正是您在实际缓存/代理场景中所需要的。

Linux 对比 Windows:直面现实

在相同的硬件配置下,Linux 版本在动态 JSON 工作负载下的吞吐量是 Windows IOCP 版本的两倍以上。这主要是由于内核网络协议栈、调度器行为和生态系统调优方面的差异。Windows IOCP 的性能依然非常出色(在同一操作系统上甚至优于 nginx),但差距依然存在。
我们接受这个现实。实际上,对于大多数部署而言,Windows 的速度已经绰绰有余——尤其是在您重视其身份验证生态系统或现有 IT 基础架构的情况下。但如果您希望将硬件和软件的性能提升到更高的稳定性和生产级别,Linux 才是最佳选择。

为什么 Pascal 架构在 2026 年仍然有机会?

现代 Object Pascal(尤其是 Free Pascal +mORMot 2)为我们提供了一种罕见的组合:
  • 底层控制可与 C/C++ 相媲美(手动内存管理、静态缓冲区、直接操作系统 API 访问)
  • 高生产力(简洁的语法、强大的 RTTI、优秀的mORMot 2标准库)
  • 性能可预测,无垃圾回收暂停或隐藏成本
最终得到的软件解决方案在关键之处速度极快,易于维护,并且在生产环境中表现出卓越的稳定性。您的高级服务代码仍然可以使用安全简洁的高级对象 Pascal 类型(例如,泛型、动态数组、RTTI 等)编写string,interface而所有底层底层工作都可以在mORMot 2层面完成。这无疑是一个值得考虑的技术方案。

结语

TechEmpower 在激励开发者和进行跨框架比较方面非常出色,但真正的成功体现在能够长期运行、处理持续流量并具备监控、安全性和可靠性的生产服务器上。
值得注意的是,TFB 挑战赛最近已关闭,其 GitHub 代码库自 2026 年 3 月起已被存档。他们没有给出任何理由,但可能是因为主要赞助商微软(提供硬件)未能像使用我们熟悉的 Pascal 代码那样,用 C#

达到最高水平——当然,这只是猜测。TFB 是一个知名的第三方基准测试,参赛者众多,但它确实只是一个微基准测试。

我们的mormot.net.async产品在设计之初就以生产就绪代码为目标。它并不追求在所有微基准测试中都拔得头筹,而是力求成为真正 REST 服务的优秀且务实的选择。
代码是开源的。如果您对高性能网络、低资源分配设计或 Pascal 跨平台系统编程感兴趣,欢迎您来了解一下。
一如既往,我们欢迎您在论坛上提出问题和贡献代码。