You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js服务与Apache ab工具并发测试异常:请求计数不符

排查Hapi.js服务高并发下请求处理次数异常问题

这是个典型的并发场景下的疑难问题,我来帮你一步步拆解排查方向和验证方法:

先明确核心现象

从你的测试数据能看出规律:

  • 低并发(-c=1/2)时,服务日志数和ab指定的请求数完全一致
  • 并发越高,服务日志数超出请求数的差值越大
  • 差值不稳定但持续存在

这说明问题和并发压力下的请求发送/处理逻辑直接相关,我们可以从「ab工具是否多发送了请求」和「服务端是否重复处理了请求」两个方向入手验证。


第一步:验证ab实际发送的请求数量

首先要搞清楚:是ab偷偷发了更多请求,还是服务端自己重复处理了相同请求?

用抓包工具确认真实请求数

在CentOS 6.9上可以用tcpdump抓本地回环接口的请求,统计实际发送的GET /test请求数量:

# 1. 准备日志文件
> server.log
> request_count.txt

# 2. 后台启动服务,把日志输出到文件
node ./server.js > server.log 2>&1 &
SERVER_PID=$!

# 3. 启动tcpdump抓包并统计GET请求数
tcpdump -i lo port 3000 -l 2>/dev/null | grep "GET /test" | wc -l > request_count.txt &
TCPDUMP_PID=$!

# 4. 执行ab压测
/usr/bin/ab -n 1000 -c 1000 localhost:3000/test

# 5. 停止相关进程并查看结果
kill $TCPDUMP_PID
kill $SERVER_PID

echo "ab指定请求数: 1000"
echo "抓包实际请求数: $(cat request_count.txt)"
echo "服务日志处理次数: $(wc -l server.log)"

对比这三个数值就能定位问题:

  • 如果抓包数=服务日志数>ab指定数:说明ab在高并发下发送了超出指定数量的请求
  • 如果抓包数=ab指定数<服务日志数:说明服务端重复处理了同一批请求

第二步:针对不同结论的排查方向

情况1:ab发送了额外请求

CentOS 6.9默认的ab版本是2.2,在高并发场景下可能存在两个导致额外请求的原因:

  1. 系统资源限制导致连接失败,ab隐式重试:CentOS 6.9默认文件描述符限制是1024,当-c=1000时,需要同时建立1000个TCP连接,很可能触发资源限制导致部分连接失败,部分旧版本ab会在这种情况下自动重试请求。

    • 验证方法:查看ab输出中的Failed requests数值,如果大于0,说明有请求失败,可能伴随重试。
    • 解决方法:临时提升系统文件描述符限制(ulimit -n 2048),或者更换更可靠的压测工具(如wrk、k6)。
  2. ab本身的并发逻辑bug:旧版本ab在高并发下可能存在计数不准确或重复发送请求的问题,你可以换用其他工具测试对比:

    # 用wrk测试示例
    wrk -t1 -c1000 -d1s http://localhost:3000/test
    

情况2:服务端重复处理请求

如果抓包数和ab指定数一致,但服务日志数更多,说明是Node.js或Hapi.js的请求处理逻辑存在问题:

  1. Node.js http模块的旧版本bug:你使用的Node.js v10.14.1是比较老的版本,存在一些高并发下的请求解析bug,比如TCP连接异常时重复触发request事件。

    • 解决方法:升级Node.js到LTS版本(如v16.x或v18.x),再测试是否复现问题。
  2. Hapi.js的路由处理异常:虽然你的代码只注册了一次/test路由,但Hapi 17.x的部分版本在高并发下可能存在路由匹配的重复触发问题。

    • 解决方法:升级Hapi.js到最新的17.x补丁版本,或直接升级到v18+版本。

额外提示:修复count变量的并发安全问题

虽然这不是导致日志数异常的直接原因,但你的全局count变量使用count++不是原子操作,高并发下会出现计数不准确的问题。可以改用Node.js的Atomic类来保证并发安全:

'use strict';
var Hapi = require("hapi");
const count = new require('atomic-sleep').AtomicInteger(0); // 或者用Atomics模块

const server = Hapi.server({ port: 3000, host: 'localhost' });

server.route({
  method: 'GET',
  path: '/test',
  handler: (request, h) => {
    const currentCount = count.incrementAndGet(); // 原子操作
    console.log(currentCount);
    return currentCount;
  }
});

// 剩余代码不变...

内容的提问来源于stack exchange,提问作者zsimo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:16:37