如何对 React SSR 性能进行基准测试
构建可重复的 React SSR 基准,包括内容验证、加载、p95 延迟、每个响应的 CPU、内存和浏览器检查。
PRNext 0.1.18-alpha 可用。为了配合此版本的发布,我们将发布 10 月 29 使用其开发候选产品进行的测量。在小型 VPS 上,CPU 时间和内存与请求速度一样重要。我们将此代码与两台 Linux 机器上的 Next.js 进行比较,然后限制它们的资源以查看结果如何随工作负载变化。
PRNext 候选方案在我们的 100-row SSR 页面上以两倍 CPU 预算提供 57% 更高的吞吐量。在小型 VPS 上,同一页面每次响应使用约 37% 少 CPU,但更多 RAM。这些结果共同解释了这种比较的目的:确定 PRNext 在哪些方面有帮助、成本如何以及 Next.js 在哪些方面做得更好。
使用两个 CPU 和 1 GiB,候选者在 100-row SSR 页面上达到每秒 224.70 响应,而在 100-row SSR 页面上达到 142.97,大约多出 57% 吞吐量。在相同预算的 1,000-row 页面上,Next.js 领先。在两台 VPS 机器上使用 Next.js 测量水合作用也更快。
在小型 VPS 上,普通 SSR CPU 成本下降约 37%,但 PRNext 使用更多内存。工作线程睡眠释放 RAM 以换取较慢的唤醒速度。以下部分提供了每个场景的版本、测量和限制。
10 月 29, 2026 的测量在提交 2856155. 时使用 0.1.18-alpha 开发候选版本,其清单仍然携带内部版本 0.1.17-alpha,但其代码和优化与 npm 0.1.17-alpha 包不同。准确测量的源和工件哈希值在本文末尾链接。
参考是 Next.js 16.4.3,,使用相同的 React 19.3.1 系列和应用源。小型VPS运行Node.js 22.23.4;大的运行 Node.js 24.22.1. 在每台机器中,每个引擎都使用完全相同的 Node 可执行文件。跨机器差异不能仅仅归因于硬件,因为节点也会发生变化。
PRNext 运行平衡配置文件及其默认 Web 渲染器。相关数据包括完整的 Linux 二进制文件和候选包哈希值、修复前的结果和吞吐量范围。 10 月 30 发布的 npm 0.1.18-alpha 版本来自提交 05a9ccd,并包含其他构建和开发修复。因此,该活动既不衡量 npm 0.1.17-alpha 包,也不衡量最终的 0.1.18-alpha 档案。这些数字描述了已确定的候选者,但没有为后续变化分配新的基准。
第一个 VPS 有一个 vCPU 和大约 1.9 GiB 或 RAM。第二个有八个 vCPU,大约 23 GiB。目标进程接收 cgroup v2 CPU 和内存限制,无交换。小型机仅限CPU和700 MiB之一中的70%;大型机器在一个 CPU 和 384 MiB、两个 CPU 和 1 GiB 上进行测试,然后在四个 CPU 和 2 GiB 上进行测试。
主矩阵包含 96 窗口:四个预算、四个场景、三个变体和两个交替通道。变体是修复之前的 PRNext、测量的 PRNext 候选者和 Next.js。每个窗口都有 5 秒的预热时间,然后是 15 秒的测量秒数,使用 16 个连接和 gzip。这些表将候选者与 Next.js 进行比较,并报告每个指标的两个窗口的中位数。
这些场景是动态 100-row SSR 页面、1,000-row 页面、十六个条目 JSON API 和具有 40 ms 暂停延迟的页面。新的标识符和 cookie 检查响应的正确性和隔离性。吞吐量仅计算成功且经过验证的响应。这不是对 CDN 提供的静态页面的比较。
p95 是 95% 请求在窗口中完成的持续时间。 CPU 是每次成功响应的 CPU 工作的毫秒数,而不是延迟。 RAM 是目标进程树中的中值比例集大小(PSS),包括本机引擎和节点工作线程。响应可能需要 100 ms,而仅使用几毫秒的 CPU。
负载生成器具有单独的限制,但共享小型 VPS 的单个物理 CPU。快速API场景可以达到其天花板,特别是在小型机器和四CPU场景中。现有服务保持活动状态:配额并不能消除这些 VPS 上的争用。两次短传不提供置信区间。微小的差异不应成为营销承诺。
在 0.7 CPU 和 700 MiB 处,PRNext 每秒针对 Next.js 的 51. 提供 81.33 SSR 响应,其 p95 是针对 420.90 ms 的 264.25 ms。每个响应的 CPU 成本从 13.39 下降到 8.46 ms,大约减少 37%。然而,内存是 113.88 MiB 与 101.38 MiB 相对:PRNext 在本页上更多地使用了 12% 。
流式渲染达到每秒 138.13 个请求,对比值为 80.03,每个响应的 CPU 消耗约低 42%。重度渲染页面的差距较小,分别为每秒 11.33 和 10.33 个请求。本次测试中,API 场景的结果有利于 PRNext,但负载生成器与服务争用同一个物理 CPU,仍是这项测试的局限。
在小屏幕上,水平滚动表格。
| 场景/引擎 | 请求数/秒 | p95(毫秒) | CPU(毫秒/请求) | RAM (MiB) |
|---|---|---|---|---|
| SSR 100 / PRNext | 81.33 | 264.25 | 8.46 | 113.88 |
| SSR 100 / Next.js | 51.00 | 420.90 | 13.39 | 101.38 |
| SSR 1 000 / PRNext | 11.33 | 1,550.25 | 58.92 | 139.51 |
| SSR 1 000 / Next.js | 10.33 | 1,661.80 | 62.10 | 119.46 |
| API JSON / PRNext | 518.17 | 61.40 | 1.27 | 139.63 |
| API JSON / Next.js | 352.80 | 90.05 | 1.94 | 113.08 |
| 40 ms 流媒体 / PRNext | 138.13 | 182.65 | 4.98 | 135.32 |
| 40 ms 流媒体 / Next.js | 80.03 | 307.25 | 8.62 | 115.54 |
在此计算机上的所有四种场景中,PRNext 使用的 PSS 都多于 Next.js。观察到的优势主要是普通 SSR 和流媒体上的 CPU 效率。一揽子声称较低的 RAM 会歪曲这些结果。
在仅限 CPU 和 384 MiB 之一的大型 VPS 上,SSR 页面每秒达到 99.77 请求,而 59.90. CPU 成本大约较低 41%,PSS 大约较低 13%。流式传输每秒达到 220.90 对应 86.27 请求,每次响应使用 4.51 对应 11.47 ms 或 CPU。
候选者更严格的内存策略还相对于我们早期的 PRNext 代码减少了 RAM ,但 API 相对于早期的代码损失了大约 13% 的吞吐量。 PRNext 在此测量中仍然领先 Next.js;这并不能消除内部回归。垃圾收集和吞吐量之间的平衡需要更多的工作。
在小屏幕上,水平滚动表格。
| 场景/引擎 | 请求数/秒 | p95(毫秒) | CPU(毫秒/请求) | RAM (MiB) |
|---|---|---|---|---|
| SSR 100 / PRNext | 99.77 | 227.20 | 9.90 | 109.85 |
| SSR 100 / Next.js | 59.90 | 365.35 | 16.78 | 126.50 |
| SSR 1 000 / PRNext | 13.60 | 1,329.65 | 72.82 | 139.97 |
| SSR 1 000 / Next.js | 10.00 | 1,932.90 | 95.47 | 158.74 |
| API JSON / PRNext | 849.63 | 38.75 | 1.18 | 128.40 |
| API JSON / Next.js | 409.13 | 76.85 | 2.45 | 163.78 |
| 40 ms 流媒体 / PRNext | 220.90 | 108.50 | 4.51 | 140.27 |
| 40 ms 流媒体 / Next.js | 86.27 | 299.30 | 11.47 | 167.14 |
使用两个 CPU 和 1 GiB 时,100-row SSR 页面在 PRNext 中每秒达到 224.70 请求,而在 Next.js 中每秒达到 142.97 请求。也就是说,吞吐量增加了 57%,每个响应减少了 26% 大约 CPU,PSS 减少了 32%。 p95 是 89.80 ms 对 154.60 ms。
1,000-row 页面反转结果:Next.js 相对于 PRNext 的 24, 达到每秒 27.63 请求,相对于 740.80 ms 达到 622.20 ms 的 p95。每个响应 PRNext 使用较少的 RAM 但约 29% 更多 CPU。重 React 渲染仍然是一个具体的改进目标。
在小屏幕上,水平滚动表格。
| 场景/引擎 | 请求数/秒 | p95(毫秒) | CPU(毫秒/请求) | RAM (MiB) |
|---|---|---|---|---|
| SSR 100 / PRNext | 224.70 | 89.75 | 7.57 | 117.50 |
| SSR 100 / Next.js | 142.97 | 154.55 | 10.29 | 173.30 |
| SSR 1 000 / PRNext | 24.00 | 740.75 | 64.42 | 164.17 |
| SSR 1 000 / Next.js | 27.63 | 622.25 | 49.91 | 198.96 |
| API JSON / PRNext | 2,078.33 | 14.00 | 0.83 | 144.80 |
| API JSON / Next.js | 1,001.40 | 28.25 | 1.22 | 203.93 |
| 40 ms 流媒体 / PRNext | 341.00 | 55.15 | 4.40 | 154.70 |
| 40 ms 流媒体 / Next.js | 218.67 | 105.00 | 6.31 | 206.20 |
流式渲染的吞吐量仍高约 56%,每个响应的 CPU 消耗低约 30%。这些结果仅适用于本次动态应用、性能配置和资源配额,不能推广到所有 React 项目。
在四个 CPU 和 2 GiB 中,PRNext 使用两个工作线程。 Next.js 在私有 Node 代理后面使用两个进程,其中包括 CPU 和 RAM。其他三个预算使用直接服务器。这种拓扑差异是结果的一部分。
对于此 Next.js 引用,PRNext 每秒针对 247.13 达到 383.30 SSR 请求数。其 PSS 是 206.60 MiB 对 458.33 MiB。这并没有建立通用的 55% RAM 保存:不同的拓扑或代理可能会改变结果。 API 也可以达到发电机上限。
在小屏幕上,水平滚动表格。
| 场景/引擎 | 请求数/秒 | p95(毫秒) | CPU(毫秒/请求) | RAM (MiB) |
|---|---|---|---|---|
| SSR 100 / PRNext | 383.30 | 56.35 | 8.49 | 206.60 |
| SSR 100 / Next.js | 247.13 | 133.50 | 11.80 | 458.33 |
| SSR 1 000 / PRNext | 46.37 | 450.10 | 68.28 | 272.22 |
| SSR 1 000 / Next.js | 45.50 | 688.85 | 62.55 | 520.04 |
| API JSON / PRNext | 3,421.17 | 8.20 | 0.91 | 242.97 |
| API JSON / Next.js | 1,582.60 | 24.05 | 1.90 | 525.35 |
| 40 ms 流媒体 / PRNext | 356.90 | 48.45 | 5.09 | 262.35 |
| 40 ms 流媒体 / Next.js | 313.77 | 68.75 | 7.98 | 542.40 |
与我们之前在此预算下的 PRNext 代码相比,候选者在重页上损失了大约 10% 的 SSR 吞吐量和大约 6% 的吞吐量。更多的 CPU 并不能保证每条路径都会得到改善。跨工作人员的扩展和大量渲染分配仍然需要努力。
低流量站点不会整天让处理器饱和。空闲内存比峰值吞吐量更重要。 PRNext 可以在空闲期后退出其节点工作线程,同时保持 Rust 服务器监听。下一个渲染请求将重新创建它所需的工作人员。
我们在具有简单 SSR 页面和加速的两秒空闲阈值的小型 VPS 上测试了此机制。工人退休后观察记忆,大约需要两秒钟;保温控制等待大约六秒钟。这是每个设置的一个功能探针,与负载和耐久性测试分开。
在小屏幕上,水平滚动表格。
| PRNext 设置 | 安静 RAM (MiB) | 唤醒请求(毫秒) |
|---|---|---|
| 闲置工人退休 | 10.5 | 1,130.0 |
| 预热然后闲置退休 | 10.4 | 1,126.6 |
| 预热并保暖 | 106.8 | 22.6 |
在本次调查中,工人退休后 PSS 降至约 10.5 MiB,而在保温时则降至 106.8 MiB。成本出现在唤醒请求中:相对于 22.6 ms 大约 1.13 秒。 10.5 MiB 图描述了这个简单应用程序在该状态下的进程树,而不是整个 VPS 或每个应用程序。
使用 --prewarm 启动预热会在接受请求之前初始化框架。它不会阻止后续的空闲退出,也不会调用应用程序页面或 API 处理程序。为了保留使用过的渲染主机,显式设置为 --worker-idle-seconds 0. 因此,单独预热并不能消除睡眠后唤醒的成本。
此探测器中未测试等效的 Next.js 睡眠配置。它并未确定外部基础设施无法停止或重新启动 Next.js。
对于不同时间访问的几个小项目,释放不活动的worker内存可以为活动的应用程序留出更多空间。更好的 CPU 效率还可以在相同的配额内留下更多有用的工作。这可能与小型公共站点、演示和间歇性内部工具相关。
这是根据测量得出的推论,而不是托管密度基准。我们还没有确定一台服务器可以容纳多少个额外项目,也没有测量账单或节能情况。操作系统、数据库、网关、同时突发和唤醒也会消耗资源。
该框架还有一个本地 prnext 主机命令,可以让整个应用程序在网关后面休眠。这与此处衡量的工人退休金是分开的。网关保持活动状态;跟踪的请求和连接可以保护正在进行的工作,以后的访问可以唤醒应用程序。该活动并未量化其总成本。
睡眠会丢弃仅在进程内部保存的状态。持久数据属于磁盘或适当的服务;未跟踪的后台工作不得依赖于进程的存活。托管 PRNext Host 服务又是另一层。本文不衡量其定价或部署性能。
六个十分钟的混合负载运行涵盖了两个 VPS 上的三个变体。每次运行后都会有 30 个流取消和 46 安静秒。在这些最终的活动中,没有观察到测试服务器的内容故障、加载错误或内存不足。
在小屏幕上,水平滚动表格。
| VPS/引擎 | 请求数/秒 | 第一分钟 RAM (MiB) | 最后一刻 RAM (MiB) |
|---|---|---|---|
| 小/PRNext | 255.6 | 125.3 | 131.3 |
| 小/Next.js | 202.3 | 106.5 | 114.8 |
| 大/PRNext | 348.5 | 119.0 | 130.4 |
| 大/Next.js | 317.6 | 152.5 | 158.0 |
初始耐力尝试暴露了负载生成器中的内存保留,而不是测试的服务器中的内存保留。修复工具后,使用相同的校正生成器完全重复所有六次最终运行。该工具链接指向提交 fb59284,与测量的引擎提交分开。
内存仍然存在变化:在受限的大型 VPS 上,PRNext 在第一分钟和最后一分钟之间从 119.0 移动到 130.4 MiB。其混合吞吐量大约比我们之前在该配置上的 PRNext 代码低 12% 。十分钟既不能确定不存在泄漏,也不能确定几周内的稳定性。
取消和等待后,PRNext 的文件描述符回落到 44. 这不足以声明泄漏或在较长时间内排除泄漏。浏览器验证添加了 48 定时上下文和十项功能检查,包括强制回退。它并未证明与所有 Next.js 应用程序完全兼容。
最有力的论点是普通 SSR 的 CPU 效率以及跨多个有限预算的流。内存也可以是有利的,但它不适用于本次活动中的物理小型 VPS。睡眠为间歇性项目提供了另一种选择:释放 RAM 或保持温暖的反应。
接下来的优先事项是大量渲染分配、水合作用、某些预算下的吞吐量回归以及跨工作人员的扩展。此活动中的少数构建测量也不支持更快构建的一般主张。
PRNext 仍处于实验阶段,其 Next.js 兼容性是部分的。要确定它是否适合您的应用程序,请使用已识别的工件重现其昂贵的路线、流量、安静期和唤醒。这些结果提供了一个可验证的起点,而不是框架的通用排名。
PRNext 0.1.18-alpha: published release / version publiée (在新选项卡中打开)
Benchmark data / Données du benchmark (JSON) (在新选项卡中打开)
PRNext: measured source / code mesuré (2856155) (在新选项卡中打开)
Application fixture / application de test (在新选项卡中打开)
Corrected load generator / générateur corrigé (fb59284) (在新选项卡中打开)
PRNext: rendering, prewarming and worker retirement (在新选项卡中打开)