Next.js 服务端渲染性能基准测试:构建与运行 bench/rendering 渲染基准
本文基于 Next.js 官方仓库中的 bench/rendering 基准测试目录展开,讲解如何从零构建该服务端渲染基准应用、使用 Apache Bench(ab)对生产模式的 Next.js 服务发起压测,并深入分析两个无状态(stateless)压测页面的实现细节。读完本文,你将能够完整复现 Next.js 官方的 SSR 吞吐基准流程,理解 ab 参数的含义,并知道当需要更细粒度的渲染管线剖析时应转向哪个进阶工具。
一、bench/rendering 是什么
bench/rendering 是 Next.js 仓库中一个专门用于服务端渲染(SSR)吞吐基准的最小化压测应用。它包含两个无状态页面路由,配合 ab(Apache Bench)工具对 next build + next start 启动的生产服务器发起大量 HTTP 请求,从而度量服务端渲染单个页面的吞吐与延迟能力:
- pages/stateless.js:渲染单个
<h1>My component!</h1>的最简页面; - pages/stateless-big.js:渲染 10,000 行
<li>列表的大体积页面。
与仓库中其他更复杂的基准(见 bench/BENCHMARKING.md 的 Render Pipeline 手册)不同,这个基准刻意保持极简:不依赖路由中间件、不测流式渲染,只回答一个基础问题——在相同条件下,服务端渲染一个轻/重页面各能支撑多少请求。
二、前置准备:安装依赖与确认 ab
官方 readme 要求按 contributing.md 的步骤安装仓库依赖。对于 Next.js 源码仓库,这意味着使用 pnpm 安装工作区依赖,并在框架源码有改动时先执行 pnpm build 构建 Next.js 本体(构建流程见 contributing/core/building.md),确保压测对象是最新的 next 包。
此外,两个基准都使用 ab 发起请求,因此本机必须安装 Apache Bench(通常随 Apache HTTP Server 发行版提供)。ab 的关键参数在本基准中的用法为:
| 参数 | 含义 | 本基准取值 |
|---|---|---|
-c1 |
并发连接数为 1(串行压测) | 两个脚本均固定为 1 |
-n3000 / -n500 |
总请求数 | 轻页面 3000 次,重页面 500 次 |
注意:
-c1表示串行请求,此时测得的是单连接下的纯渲染耗时与吞吐,不会暴露并发争用问题。若需并发场景,可参考后文进阶基准中的闭环压测模型。
三、构建并启动基准应用
在 bench/rendering 目录下,先构建并启动应用。package.json 中定义了对应脚本(仓库主工作区使用 pnpm,但脚本本身与 npm 等价):
npm run start
该脚本的实际内容为:
NODE_ENV=production pnpm build-application && NODE_ENV=production next start
即先以生产模式执行 next build,再执行 next start 启动 http://0.0.0.0:3000 的生产服务器。这是整个流程中唯一的前置步骤,后续所有压测请求都打向这个已构建好的服务器。
四、两个压测场景
4.1 轻量无状态页面(3000 次请求)
npm run bench:stateless
对应脚本:
ab -c1 -n3000 http://0.0.0.0:3000/stateless
被压测的页面实现极简,完整源码如下(pages/stateless.js):
import React from 'react'
export default () => <h1>My component!</h1>
由于每次请求的输出恒定且极小,3000 次串行请求足以得到稳定的均值。这个场景主要度量渲染一个几乎无内容页面的固定开销:请求解析、组件求值、HTML 序列化与响应写出的整体成本。
4.2 大体积无状态页面(500 次请求)
npm run bench:stateless-big
对应脚本:
ab -c1 -n500 http://0.0.0.0:3000/stateless-big
该页面(pages/stateless-big.js)在服务端生成 10,000 行列表:
import React from 'react'
export default () => {
return <ul>{items()}</ul>
}
const items = () => {
const out = new Array(10000)
for (let i = 0; i < out.length; i++) {
out[i] = <li key={i}>This is row {i + 1}</li>
}
return out
}
从源码结构看,每次请求都会重新执行 items() 构建一个 10,000 元素的 React 元素数组并完整序列化,因此单个响应的 HTML 体积和 CPU 成本都显著高于轻页面,这也是请求数从 3000 降到 500 的原因。该场景用于度量大体积 HTML 的序列化与输出吞吐,是判断“页面越大渲染越慢”这一线性关系是否成立的基准线。
4.3 结果如何解读
ab 运行结束会输出完整的统计报告(总请求数、每秒请求数、请求耗时分布等)。解读时建议关注:
- Requests per second:串行模式下直接反映单请求平均成本;
- Time per request 的 min/avg/max:观察渲染耗时是否稳定,最大值若明显偏高说明存在 GC 或首次编译抖动;
- 两个场景的对比:
stateless-big相对stateless的每请求耗时增量,近似就是“序列化 10,000 行 DOM”的边际成本。
由于基准使用固定输入(页面数据无随机性),A/B 对比时字节与输出是确定的,任何吞吐差异都可归因于代码改动本身。
五、附带的微基准:recursive-copy 对比
同一 package.json 中还定义了一个与渲染无关的辅助脚本:
npm run bench:recursive-copy
它执行 bench/recursive-copy/run.js:先随机生成 100 个文件到 fixtures/src,然后各跑 10 轮,分别测量第三方 recursive-copy npm 模块与 Next.js 内置实现 next/dist/lib/recursive-copy 拷贝同一目录树所耗时,并打印 sum/次数/平均值。该脚本用 process.hrtime 计时、每轮之间清空目标目录,属于典型的库级微基准,用于验证 Next.js 自研递归拷贝实现相对社区库的性能收益,与上文 HTTP 压测形成“函数级 vs 请求级”的互补。
六、进阶方向:Render Pipeline 基准
bench/rendering 回答的是基础吞吐问题;若你修改的是渲染管线本身(App Router 渲染路径、流式 SSR、Flight 序列化),仓库提供了更强的工具链,见 bench/render-pipeline/README.md 与 bench/BENCHMARKING.md:
# 生产全栈 e2e 场景:next build + next start,完整 router-server 路径
pnpm bench:render-pipeline --scenario=e2e --stream-mode=node
# 最小服务器场景:绕过 router-server,隔离测量渲染管线
pnpm bench:render-pipeline --scenario=minimal-server --stream-mode=node
与 ab 的串行单连接模型不同,该基准使用闭环(closed-loop)负载生成器,支持 --load-concurrency 并发压测、/streaming/* 系列流式压力路由、TTFB 与 Flight 内联脚本字节数统计,以及 CPU profile / Node trace 抓取与 pnpm bench:render-pipeline:analyze 热点分析。其手册明确给出噪声控制规则(先构建、固定参数、多次重复、独立 artifact 目录)和 A/B 分支对比规范(快路由至少 500 次串行 + 5000 次负载请求、每侧至少跑 3 轮、对比绝对 req/s 而非单次百分比差值),这些经验同样适用于本文 ab 基准的严谨化运行。
七、小结
bench/rendering是 Next.js 官方最轻量的服务端渲染吞吐基准:npm run start构建并启动生产服务器后,npm run bench:stateless(3000 次请求)与npm run bench:stateless-big(500 次请求、10,000 行输出)分别度量轻/重页面的 SSR 成本;- 所有脚本均基于
ab -c1 -n<N>,要求本机安装 Apache Bench,且压测前需按 contributing.md 完成仓库构建; - 页面源码见 pages/stateless.js 与 pages/stateless-big.js,脚本定义见 package.json;
- 涉及流式渲染、Flight 序列化或需要并发/百分位/剖析级数据的场景,应转向 bench/render-pipeline 基准及其配套分析流程。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00