Nodejs 实测http.request的keep-alive无效

Nodejs 实测http.request的keep-alive无效

利用http.Agent保持http连接,以便重用,但是实测每次都重新建立新连接,代码如下:

var http = require('http');
var agent = new http.Agent();
agent.maxSockets = 2;//设置最大两个连接

var options = {
  hostname: 'www.baidu.com',
  path: '/img/bd_logo1.png',
  agent: agent,
  headers: {'Connection': 'keep-alive'}
};

function reqBaidu(){
  var req = http.get(options, function(res) {
    console.log("Got response: " + res.statusCode);
  });
}

reqBaidu();//运行结果:Got response: 200
setTimeout(reqBaidu, 100);//运行结果:Got response: 200
setTimeout(reqBaidu, 4000);//运行结果:等了很久(60多秒)才出结果Got response: 200,难道连接池中的两个socket被占用了?

使用Microsoft Network Monitor 3.4查看tcp连接情况如下,三次http请求都使用了新的socket,这是为什么呢,或许是我分析错了,还请指正。

捕获.PNG


4 回复

Node.js 实测 http.request 的 Keep-Alive 无效

背景

在使用 Node.js 的 http.request 方法时,我们希望重用 HTTP 连接以提高性能。为了实现这一点,我们可以使用 http.Agent 来管理连接池。然而,在实际测试中发现,每次请求似乎都会重新建立新的连接,而不是重用已有的连接。

示例代码

var http = require('http');

// 创建一个 Agent 对象,并设置最大连接数为 2
var agent = new http.Agent({
  maxSockets: 2,
  keepAlive: true,
  keepAliveMsecs: 1000
});

var options = {
  hostname: 'www.baidu.com',
  path: '/img/bd_logo1.png',
  agent: agent,
  headers: {'Connection': 'keep-alive'}
};

function reqBaidu() {
  var req = http.get(options, function(res) {
    console.log("Got response: " + res.statusCode);
  });

  // 请求错误处理
  req.on('error', function(e) {
    console.error(`Got error: ${e.message}`);
  });
}

// 运行三次请求,间隔时间分别为 0ms 和 4s
reqBaidu(); // 运行结果:Got response: 200
setTimeout(reqBaidu, 100); // 运行结果:Got response: 200
setTimeout(reqBaidu, 4000); // 运行结果:等了很久(60多秒)才出结果 Got response: 200,难道连接池中的两个 socket 被占用了?

分析与解决

从上述代码和运行结果来看,我们期望通过 http.Agent 重用连接,但实际上每次请求都创建了一个新的连接。这可能是由于以下几个原因:

  1. 服务器端的限制:服务器可能配置了某些限制,导致它不支持或不响应 keep-alive 请求。
  2. 超时问题:如果连接在一段时间内没有活动,可能会被关闭。可以通过设置 keepAliveMsecs 来延长空闲连接的存活时间。
  3. 连接池限制:虽然设置了 maxSockets 为 2,但有可能在这段时间内连接池中的两个 socket 都被占用。

解决方案

为了验证和解决问题,可以尝试以下步骤:

  1. 增加日志输出:添加更多的日志输出,以了解连接的状态。
  2. 检查服务器配置:确保服务器支持 keep-alive
  3. 调整超时设置:增加 keepAliveMsecs 时间,延长空闲连接的存活时间。
var agent = new http.Agent({
  maxSockets: 2,
  keepAlive: true,
  keepAliveMsecs: 5000 // 延长空闲连接的存活时间
});

通过以上步骤,应该能够更好地理解并解决 http.requestkeep-alive 失效的问题。


楼主分析的好细致,学习了

0.10 的 http agent 需要有请求排队的情况才会出现keepalive,如果没有排队请求,会马上断开socket连接。

根据你的描述,http.requesthttp.getkeep-alive 机制没有按预期工作。这里有几个可能的原因:

  1. Node.js 版本问题:某些旧版本的 Node.js 对 keep-alive 支持不完善。确保你使用的是最新版本的 Node.js。

  2. 代理或中间件:某些网络环境或代理服务器可能会干扰 keep-alive 连接。

  3. 重用连接池http.Agent 的作用是管理连接池,但需要确保每次请求时使用的 Agent 实例是一致的,并且 Agent 池中有可用的连接。

以下是一个示例代码,展示了如何正确配置 http.Agent 来实现 keep-alive

const http = require('http');

// 创建一个自定义的 Agent 实例,设置最大连接数为 2
const agent = new http.Agent({
  maxSockets: 2,
});

const options = {
  hostname: 'www.baidu.com',
  path: '/img/bd_logo1.png',
  agent: agent, // 使用自定义的 Agent
  headers: { 'Connection': 'keep-alive' }
};

function reqBaidu() {
  const req = http.get(options, (res) => {
    console.log(`Got response: ${res.statusCode}`);
  });

  req.on('error', (err) => {
    console.error('Request error:', err.message);
  });
}

// 初始请求
reqBaidu();

// 间隔一段时间后再次请求
setTimeout(reqBaidu, 100);

// 更长间隔时间后再次请求
setTimeout(reqBaidu, 4000);

关键点解释:

  • http.Agent:用于管理连接池。通过设置 maxSockets 可以限制同时打开的最大连接数。
  • agent: agent:在 options 中指定使用自定义的 Agent 实例。
  • headers: { 'Connection': 'keep-alive' }:明确设置 keep-alive 头。

如果你仍然遇到问题,请检查是否网络环境或代理服务器影响了连接复用。

回到顶部