http.Agent官方文档

附图,个人对http.Agent的理解:

image.png

一个 Agent是在client端用来管理链接的持久性和重用。对于一个host+port维持着一个请求队列,这些请求重复使用一个socket,直到这个队列空,这时,这个socket会被destroy或者放到pool里,在pool里时这个socket将会被再次重用(这两个行为取决于keepAlive的配置)

keepAlive
keepAliveMsecs
maxSockets
maxFreeSockets

在pool中的链接已经开启了tcp的Keep-Alive,然而在server端会有如下行为影响pool中的链接:

测试代码准备:

client.js


const http = require('http');const agent = new http.Agent({keepAlive: true,keepAliveMsecs: 1000,maxSockets: 4,maxFreeSockets: 2
});const test = () => {return new Promise((resolve, reject) => {const option = {protocol: 'http:',host: 'localhost',port: 9990,path: `/`,agent: agent,// agent: agent,headers: {"Connection": "keep-alive"},method: 'GET'};const req = http.request(option, function(res) {res.setEncoding('utf8');let body = '';res.on('data', (chunk) => {body += chunk;});res.on('end', () => {resolve(body)});});req.on('error', (e) => {console.error(`problem with request: ${e.message}`);console.log(e.stack)});req.end();})
};const sendReq = (count) => {let arr = [];for (let i=0;i<count;i++) arr.push(test())Promise.all(arr).then(function(){console.log('======end======')})
}

server.js

const http = require('http');let server = http.createServer(function(req, res) {console.log(req.connection.remotePort);res.end('200');}).listen(9990);server.keepAliveTimeout = 5000; // 这个值默认就是5s,可以直接赋值修改
  • server端主动关闭空闲链接:client收到通知后,当前socket会从pool中移除,下一次请求时会创建一个新的socket

Pooled connections have TCP Keep-Alive enabled for them, but servers may still close idle connections, in which case they will be removed from the pool and a new connection will be made when a new HTTP request is made for that host and port.

client.js补充

sendReq(1);  // 先发送一个reqsetTimeout(() => {sendReq(1)}, 10 * 1000); //隔10s后再次发送一次req

server.js输出如下:

 // console.log(req.connection.remotePort);53957 // 发送第一个请求的socket port54011 // 隔10s后发送第二个请求的socket port。port不同,说明第一个socket已经被关闭

wireshark抓包如下:

image.png

可以看到每隔1s发送向server端发送了一次TCP Keep-Alive探测。由于server端设置的keepAliveTimeout为5s(默认就是5s),所以在5s后关闭了这个tcp链接,相应的,client端收到关闭的信号就会close到当前的socket,并从pool中移除这个socket

_http_agent.js

Agent.prototype.removeSocket = function removeSocket(s, options) {var name = this.getName(options);debug('removeSocket', name, 'writable:', s.writable);var sets = [this.sockets];// If the socket was destroyed, remove it from the free buffers too.if (!s.writable)sets.push(this.freeSockets);for (var sk = 0; sk < sets.length; sk++) {var sockets = sets[sk];if (sockets[name]) {var index = sockets[name].indexOf(s);if (index !== -1) {sockets[name].splice(index, 1);// Don't leakif (sockets[name].length === 0)delete sockets[name];}}}// 省略其他代码
};
  • server端拒绝多个请求共用一个tcp链接,在这种情况下,在每次请求时链接都会建立并且不能被pool。agent仍然会处理请求的发送,只是每个请求都会建立在一个新的tcp链接上

Servers may also refuse to allow multiple requests over the same connection, in which case the connection will have to be remade for every request and cannot be pooled. The Agent will still make the requests to that server, but each one will occur over a new connection.

client.js不变

server.js添加如下代码

    res.shouldKeepAlive = false; // 禁用shouldkeepAliveres.end('200');

wireshark抓包如下:

image.png

可以看到,请求结束后,server就会关闭socket

When a connection is closed by the client or the server, it is removed from the pool. Any unused sockets in the pool will be unrefed so as not to keep the Node.js process running when there are no outstanding requests. (see socket.unref()).

当想要保持一个http请求很长时间并不在pool中,可以调用“agentRemove”(这个时间取决于server端socket close的时间)

Sockets are removed from an agent when the socket emits either a 'close' event or an 'agentRemove' event. When intending to keep one HTTP request open for a long time without keeping it in the agent, something like the following may be done:

client.js

      // newreq.on('socket', (socket) => {socket.emit('agentRemove');});

server.js

server.keepAliveTimeout = 20000; // 为了清楚,服务端设置20s后再关闭

wireshark抓包如下:

image.png

可以看到,触发“agentRemove”后,当前socket并没有发送探测包,并且知道server端通知关闭才关闭。

当agent参数设置为false时,client将会为每一个http请求都创建一个链接。


node keep-alive还是很有必要开启的,尤其时作为中间层代理,当有如下模式时:高并发下优势更明显

browser浏览器 -> nginx -> node -> nginx -> java

当nginx和node都开启keep-alive时,性能测试如下:

image.png

参考资料mark:
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html

https://stackoverflow.com/questions/30365250/what-will-happen-if-i-use-socket-setkeepalive-in-node-js-server

https://stackoverflow.com/questions/19043355/how-to-use-request-js-node-js-module-pools

https://github.com/nodejs/node/issues/10774

NodeJS的底层通信

这篇文章很详细,赞一个
https://www.zhuxiaodong.net/2018/tcp-http-keepalive/

HTTP Agent理解相关推荐

  1. Agent系列(一) 什么是Agent

    声明:此文章为原创,不得转载. 本文主要是介绍下什么是Agent , Agent有什么特性,并简要的分析了Agent技术的应用前景. 一.Agent定义 通常,我们可以把Agent理解为"个 ...

  2. 场景理解的统一感知分析ECCV2018

    目录 前置内容-PPM 摘要 1.Introduction 1.1.Related work 2.统一感知解析的定义 2.1.Datasets 2.2.Metrics 3.Designing Netw ...

  3. VLN阅读报告1:Vision-and-Language Navigation综述(2022ACL)

    本博文是结合论文Vision-and-Language Navigation: A Survey of Tasks, Methods, and Future Directions,对VLN进行学习总结 ...

  4. vnx 服务器映射,主机到VNX系统的常见注册方式

    介绍 通常情况下,在主机和VNX存储系统物理连接正常后,新安装的主机都要到存储系统上完成注册.注册过程中会将主机IP地址.主机名称和操作系统信息发送到存储系统,以方便存储系统对主机的日后管理.目前有三 ...

  5. Unity的机器学习工具包ML-Agents

    官方:Unity ML-Agents深度学习工具包|Unity中国官网 | Unity中国官网 Github下载链接:https://github.com/Unity-Technologies/ml- ...

  6. VLN阅读报告6:SOON: Scenario Oriented Object Navigation with Graph-based Exploration

    SOON: Scenario Oriented Object Navigation with Graph-based Exploration 一,引言 二,SOON任务(Scenario Orient ...

  7. Relational Deep Reinforcement Learning

    Abstract 我们介绍了一种深度强化学习的方法,它通过结构化感知和关系推理提高了传统方法的效率.泛化能力和可解释性.它使用self-attention来迭代推理场景中实体之间的关系,并指导无模型策 ...

  8. 理解一个名词:用户代理(user agent)

    文/牛海彬 原文: The term user agent and the lack of understanding what a user agent is can also be a probl ...

  9. 读后感与机翻《理解工具:面向任务的对象建模、学习和识别》

    以下是研究朱松纯FPICU概念中P(physics)的第一篇论文记录: 目录 读后感: 作者干了什么事? 作者怎么做的? 效果怎么样? 局限性 摘要 1 介绍 2 面向任务的对象表示 2.1 三维空间 ...

最新文章

  1. 内存对齐与ANSI C中struct型数据的内存布局 【转】
  2. linux fdisk等命令,Linux fdisk命令操作磁盘(添加、删除、转换分区等)
  3. React从入门到精通系列之(12)深入理解JSX
  4. mysql8.0编译安装
  5. C#学习笔记四: C#3.0自动属性匿名属性及扩展方法
  6. 获取数据 - 将Excel文件读入矩阵matrix中 - Python代码
  7. 网络协议 3 - 从物理层到 MAC 层
  8. 书单丨把握Java技术发展的新趋势!
  9. 管理感悟:出了事故,关键是想想自己哪里能改进
  10. java获取文本文件的编码格式
  11. python音乐下载器
  12. 前端接收pdf文件_前端利用pdfobject.js处理pdf文件
  13. (转)用4年多时间, 带领微软重登全球市值第一宝座, 纳德拉是如何做到的?
  14. csgo怎么一直连接服务器失败,CSGO提示连接到官方任意服务器失败怎么办?
  15. vue3.0父传子,父传孙,子传孙,孙传父,孙传子的传值
  16. easyx的基础应用教程
  17. unittest教程(2w字实例合集)——Python自动化测试一文入门
  18. MySQL数据库获取字段名
  19. java开发微信公众号:微信公众号对接
  20. XBee/XBee-Pro ® ZigBee 模块

热门文章

  1. 2022年国内运营商最全号段,联通、移动、电信、广电四大运营商
  2. 计算机组成原理——微指令格式
  3. 光遇服务器修复时间,光遇:测试服调整,瞬间Bug被修复?几家欢喜几家愁
  4. 互联网中所说的“旁注”是什么?
  5. 判断excel表格中某个单元格是否是合并单元格
  6. cad画不规则实体_如何在CAD中徒手画不规则的图形
  7. SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码)
  8. drf 安装_drf 生成接口文档
  9. MySQL ORDER BY 使用自定义排序顺序
  10. Linux——使用for循环语句