🎬 开场白:你为什么要压测?
写完接口之后,按下启动键,控制台里绿油油的日志像生命的律动一样跳动。
但是!你的服务是否能承受200 次心跳每秒的考验?
这就像是:
- 你造了辆赛车 🚗,但从未上赛道;
- 你写了一首诗,却只念给自己听;
- 你写了个 API,却不让它被"蹂躏"一番。
压测,就是让 Next.js 暴露出性能的灵魂。
🧱 一点点底层思考
首先,我们要理解 Node.js(Next.js 的核心运行基础)里的处理模型:
它是单线程事件循环(event loop),靠异步 I/O 来实现高并发。
简化来看,一次请求 =
1️⃣ 客户端发起连接(HTTP 层握手)
2️⃣ Node 分配事件处理(非阻塞)
3️⃣ 响应逻辑跑完后返回结果
Node 不是多线程在同一时间处理请求,而是利用异步回调的机制不停地切换上下文 。所以想压测 200 req/s,我们关注的核心不是"并行",而是异步请求的高效管理。
🚀 架构图:Next.js 接受来自压力的"拥抱"
下面是个简易的小"示意图":
sql
+-------------+ 🔄 event loop
Requests → | Next.js ↑ | ← Redis / DB / API
(200/s) +-------------+
↑ ↑
loadtest axios/fetch脚本
🧪 教你用脚本手工制造"风暴"
我们可以有多种方式压测 Next.js,比如:
- 专业工具:k6、Artillery、JMeter、wrk
- 自己撸个脚本:我们今天选这个(因为你是程序员 🧙♂️)
下面是一段用 Node.js 写的小压测脚本,针对 http://localhost:3000/api/hello 发起 200 req/s 的请求负载。
⚡ 脚本代码:loadtest.js
ini
import fetch from "node-fetch";
const TARGET_URL = "http://localhost:3000/api/hello";
const REQUESTS_PER_SECOND = 200;
const DURATION_SECONDS = 10;
let count = 0;
let success = 0;
let failure = 0;
function sendRequest() {
fetch(TARGET_URL)
.then(res => {
if (res.ok) success++;
else failure++;
count++;
})
.catch(() => {
failure++;
count++;
});
}
// 定时发流量
let interval = setInterval(() => {
for (let i = 0; i < REQUESTS_PER_SECOND; i++) {
sendRequest();
}
}, 1000);
// 定时停止测试
setTimeout(() => {
clearInterval(interval);
setTimeout(() => {
console.log("📊 压测结果");
console.log("------------------------");
console.log("总请求数:", count);
console.log("成功请求:", success);
console.log("失败请求:", failure);
console.log("成功率:", ((success / count) * 100).toFixed(2) + "%");
console.log("------------------------");
}, 2000);
}, DURATION_SECONDS * 1000);
🧠 这段代码在底层干了啥?
- 事件循环(Event Loop) :负责调度这些异步请求的执行与返回。
- 微任务队列 :
fetch在返回时被推入任务队列,然后被循环系统调度执行回调。 - 调用堆栈:发送请求不会阻塞主线程,因此 200 次请求不会让主线程崩溃。
如果你用 top 或 htop 看 CPU 占用,会发现它不是 100% 满载的状态,而是在事件驱动中高效切换。
📈 想更科学一点?
我们可以用 Artillery 来做同样的压测:
bash
npm install -g artillery
artillery quick --count 10 --num 200 http://localhost:3000/api/hello
这条命令会在 10 轮中发起 200 次请求,很快就能得到延迟分布与吞吐率。
🪄 一点人文关怀:服务器也需要尊重
压测虽然令人兴奋,但切记:
"测试不是折磨机器,而是认识它的极限。"
所以:
- 在生产环境压测前,请先备份 💽
- 分阶段递增你的请求速率,比如先 50,再 100,再 200
- 打开
pm2,top,docker stats等工具观察内存与 CPU 曲线
🔍 实验后的发现
当你运行完脚本,会发现一些有趣的现象:
| 指标 | 理论值 | 实际值(示例) |
|---|---|---|
| 请求数 | 2000(10秒) | 1985 |
| 成功率 | 100% | 99.3% |
| 平均响应时间 | 5ms | 12ms |
这些数值的偏差,其实正是 事件循环调度延迟 、系统调用拥挤 、TCP连接重用 和 垃圾回收暂停 的真实写照。
是的,理想是数学,而现实是操作系统。
🧩 小结:技术与诗
压测看似冷冰冰,其实它很有浪漫。
它告诉我们系统能承受多少"爱意",在多大的负载下依然能"回你一句 hello"。
所以,当你的 Next.js 在 200 req/s 下依然优雅地返回 200 OK 时,不妨微微一笑:
"我和我的服务器,都成长了。"
🧭 延伸阅读
- Node.js Event Loop 深入解析
- Artillery 官方文档
- Next.js API Routes 性能优化手册