Vert.x HttpClient调用后端服务时使用Idle Timeout和KeepAlive Timeout的行为分析

其实网上有大量讨论HTTP长连接的文章,而且Idle Timeout和KeepAlive Timeout都是HTTP协议上的事情,跟Vert.x本身没有太大关系,只不过最近在项目上遇到了一些问题,用到了Vert.x的HttpClient,就干脆总结一下,留给自己今后做参考。

在使用Vert.x的HttpClient的时候,可以使用HttpClientOptions配置KeepAlive Timeout以及Idle Timeout的行为,本文将讨论在Vert.x HttpClient中Idle Timeout的设置、如何启用和禁用KeepAlive,以及如果启用KeepAlive,其超时设置(Timeout)对HTTP连接保活的影响。

需要注意的是,这是客户端的设置,服务端由于实现技术多样,这里不深入讨论,本文默认服务端已经开启了KeepAlive(事实上也是大多数HTTP服务器的默认行为)。

本文讨论的场景仅适用HTTP/1.1的情况,HTTP/1.0处理KeepAlive方式略有不同,HTTP/1.1默认支持KeepAlive,HTTP/1.0需要显式在header里加入Connection: keep-alive。

场景演练

这里我们设定多个场景来测试不同情况下,整个系统的行为表现是什么。

场景一:HttpClient禁用 KeepAlive

HttpClientOptions里使用setKeepAlive(false)来禁用KeepAlive:

 
final HttpClientOptions options = new HttpClientOptions()
.setKeepAlive(false);

此时,Vert.x Http Client会在请求头中加入connection: close,表示在完成一次HTTP request/response的流程后,服务端需要主动发起关闭连接请求:

Wireshark抓包分析:

  1. Vert.x HttpClient使用60489端口与服务端建立连接(SYN),服务端以(SYN, ACK)数据包回应,同意建立连接
  2. Vert.x HttpClient向服务端发送HTTP请求,服务端处理请求并返回
  3. 由于Vert.x HttpClient在发出HTTP请求时,使用了connection: close,所以服务端主动发起(FIN, ACK)数据包,表示服务端已关闭连接,客户端获得数据包后,返回ACK表示确认,然后也向服务端发出(FIN, ACK),表示客户端也关闭了连接,最后服务端返回ACK,表示确认

场景二:HttpClient启用KeepAlive

HttpClientOptions里使用setKeepAlive(false)来禁用KeepAlive:

 
final HttpClientOptions options = new HttpClientOptions()
.setKeepAliveTimeout(15)
.setKeepAlive(true);

 此时,Vert.x Http Client并不会发送connection: close头,因为HTTP/1.1默认使用长连接,所以无需额外指定任何请求头。在KeepAlive超时后,会由客户端主动关闭HTTP连接。

Wireshark抓包分析:

  1. Vert.x HttpClient使用60937端口与服务端建立连接(SYN),服务端以(SYN, ACK)数据包回应,同意建立连接
  2. Vert.x HttpClient向服务端发送HTTP请求,服务端处理请求并返回
  3. Vert.x HttpClient在等待了大约15秒以后(上面代码中setKeepAliveTimeout设置的15秒),由于没有新的HTTP请求需要占用连接,于是就向服务端发起(FIN, ACK)数据包,表示客户端已关闭连接,服务端获得数据包后,返回ACK表示确认,然后也向客户端发出(FIN, ACK),表示服务端也关闭了连接,最后客户端返回ACK,表示确认

如果服务端的KeepAlive Timeout大于HttpClient的KeepAlive Timeout,那么当一段时间内没有任何HTTP请求发出,在HttpClient KeepAlive首先超时前,HTTP连接可以一直被重用,直到HttpClient KeepAlive超时,由客户端发起关闭连接请求:

  1. 可以看到,客户端端口63094的连接在多次HTTP请求中一直被重用
  2. 15秒内,没有新的HTTP请求,客户端主动发起断开连接数据包

如果服务端的KeepAlive Timeout小于HttpClient的KeepAlive Timeout(比如服务端KeepAlive Timeout为10s),那么当一段时间内没有任何HTTP请求发出,服务端会首先发起关闭连接请求:

  1. Vert.x HttpClient使用64282端口与服务端建立连接(SYN),服务端以(SYN, ACK)数据包回应,同意建立连接
  2. 在多次HTTP请求过程中,HTTP连接被重用
  3. 10秒过后,服务端首先发起关闭连接请求
  4. 之后客户端再次发出HTTP请求,会重新新建一个HTTP连接

场景三:HttpClient同时使用Idle Timeout和KeepAlive Timeout

为了模拟这样的场景,在创建Vert.x HttpClient时,使用如下HttpClientOptions

 
final HttpClientOptions options = new HttpClientOptions()
.setIdleTimeout(5)
.setIdleTimeoutUnit(TimeUnit.SECONDS)
.setKeepAliveTimeout(20)
.setKeepAlive(true);

然后让服务端在返回HTTP Response的时候,先等待7秒钟:

 
[HttpGet(Name = "GetWeatherForecast")]
public async Task<IEnumerable<WeatherForecast>> Get()
{
await Task.Delay(7000);
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}

Wireshark抓包分析:

  1. 建立连接
  2. 发送请求,服务器开始处理请求,需要7秒才能处理完
  3. 5秒后,客户端Idle Timeout了,等不起,就向服务端发起关闭连接,服务端响应关闭连接
  4. 下一次请求,需建立新的连接

因此,可以这样理解这两个设置:

  • 短的 Idle Timeout 和长的 KeepAlive Timeout: 如果 IdleTimeout 设置得比较短,而 KeepAliveTimeout 设置得比较长,连接会因为空闲超时(Idle Timeout)而关闭。因此,当新的 HTTP 请求到来时,需要建立新的连接。
  • 长的 Idle Timeout 和短的 KeepAlive Timeout: 如果 IdleTimeout 设置得比较长,而 KeepAliveTimeout 设置得比较短,在 Keep-Alive 有效时间内,即使当前连接上有请求在等待响应,该连接仍然可以接收新的 HTTP 请求,直到 Keep-Alive 超时触发。
  • 如果某个HTTP请求在某个HTTP连接上等待服务端返回,那么这个HTTP连接仍然处于活跃状态,此时并不会触发KeepAlive的倒计时

在vert.x中,RequestOptions也有类似的setIdleTimeout的方法来设置Idle Timeout,但它的作用域仅限于当前的HTTP请求,而HttpClientOptions.setIdleTimeout作用域为整个应用程序全局。

场景四:在服务端KeepAlive即将到期的时候发送HTTP请求

仍然使用上面【场景二】的环境设定,只是让客户端每隔KeepAlive Timeout相同时间发送一次请求,会发现,多数情况下,请求可以成功,但有时候会发生错误。比如,如果服务端KeepAlive Timeout为10秒,客户端也是每隔10秒发送请求:

  1. 建立连接,并发送HTTP请求,服务端正常响应
  2. 10秒后,客户端再次发出请求,服务端ACK了请求,但与此同时,服务端KeepAlive超时,于是就向客户端发送(RST, ACK)数据包用于复位连接(异常关闭连接),此时客户端就会报错:io.vertx.core.net.impl.ConnectionBase SEVERE: Connection reset

总结

  1. 一个HTTP连接是否能够重用,同时取决于客户端和服务端的KeepAlive行为
  2. 服务端通常是默认开启KeepAlive的,它也有一个默认值(不同服务端实现不一样)
  3. 客户端可以选择是否启用HTTP连接重用(启用或者禁用KeepAlive)
    1. 在HTTP/1.0中,启用时需要在Request Header中加入Connection: keep-alive,默认禁用
    2. 在HTTP/1.1中,禁用时,需要在Request Header中加入Connection: close,默认启用
  4. 如果客户端禁用,则HTTP连接不会重用,每次请求都会创建新的HTTP连接
  5. 如果客户端启用,并且客户端KeepAlive Timeout(ckt)小于服务端KeepAlive Timeout(skt),那么在min(ckt, skt)时间段内如果没有新的HTTP请求,并且HTTP连接处于空闲状态,客户端会发起HTTP连接关闭
  6. 如果客户端启用,并且客户端KeepAlive Timeout(ckt)大于服务端KeepAlive Timeout(skt),那么在min(ckt, skt)时间段内如果没有新的HTTP请求,并且HTTP连接处于空闲状态,服务端会发起HTTP连接关闭
  7. 当一个HTTP请求发送到服务端后,服务端需要一定时间处理,Vert.x HTTP Client设置Idle Timeout,可以使得当服务端在一定时间内没有响应时,客户端可以主动关闭HTTP连接。在客户端由于Idle Timeout而关闭连接之前,该HTTP请求仍在等待服务端的返回,此时承载该HTTP请求的HTTP连接仍可继续接受其它的HTTP请求
  8. 当服务端需要一定时间处理HTTP请求时,如果这个处理时间恰好与服务端KeepAlive Timeout相当,是有可能出现HTTP连接被异常关闭导致客户端报错的情况的。常见解决办法:
    1. 尽量避免在服务端KeepAlive超时时发出请求(根据实际情况调整KeepAlive参数或者定制HTTP请求发起策略)
    2. 重试机制
    3. 确保客户端和服务端超时设置合理,根据实际情况进行调整

KeepAlive Timeout和Idle Timeout的关系

两者是独立的设置,但在某些情况下可能会产生交互。例如,如果 IdleTimeout 设置的时间比 KeepAliveTimeout 短,那么连接可能会因为空闲超时而关闭,即使 Keep-Alive 允许更长时间的连接复用。

最佳实践(参考自ChatGPT)

  • 根据应用需求调整:
    • 如果应用程序需要频繁复用连接,可以设置较长的 KeepAliveTimeout
    • 如果需要防止连接长时间空闲占用资源,可以设置较短的 IdleTimeout
  • 平衡性能和资源:
    • 设置 IdleTimeout 时,确保它足够长以完成请求处理,但不要过长以免浪费资源。
    • 设置 KeepAliveTimeout 时,确保它能够有效地复用连接以提高性能。
  • 测试和监控:
    • 在实际应用中,监控连接的使用情况,并根据性能和资源使用情况调整这些超时设置。

通过合理设置这两个超时值,可以优化连接的使用效率,同时避免不必要的资源占用。

外包干了三年,快要废了。。。-CSDN博客  https://blog.csdn.net/HUA6911/article/details/142107404?spm=1000.2115.3001.6382&utm_medium=distribute.pc_feed_v2.none-task-blog-hot-4-142107404-null-null.329^v9^%E4%B8%AA%E6%8E%A8pc%E9%A6%96%E9%A1%B5%E6%8E%A8%E8%8D%90%E2%80%94%E6%A1%B66&depth_1-utm_source=distribute.pc_feed_v2.none-task-blog-hot-4-142107404-null-null.329^v9^%E4%B8%AA%E6%8E%A8pc%E9%A6%96%E9%A1%B5%E6%8E%A8%E8%8D%90%E2%80%94%E6%A1%B66

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/426900.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react学习笔记一:react介绍

将view规划成一个个的组件&#xff0c;是一个响应式的声明式的设计。 虚拟dom&#xff0c;减少dom操作。vue的虚拟dom是在react的基础上拓展来的。 单向数据流&#xff1a;是一种数据流动的模式。数据流的方向是有上到下的&#xff0c;在react中主要是从父组件流向子组件。 …

C语言进阶四:(指针和数组笔试题解析1)

一维数组&#xff1a; sizeof是计算内存大小的&#xff0c;strlen是计算字符串的长度。 int main() {//一维数组int a[] {1,2,3,4};printf("%d\n", sizeof(a));printf("%d\n", sizeof(a 0));printf("%d\n", sizeof(*a));printf("%d\n&q…

GitLab邮箱发送邮件:如何实现自动化发信?

gitlab邮箱发送邮件设置教程&#xff1f;Gitlab邮箱配置和使用&#xff1f; GitLab不仅提供了代码版本控制、持续集成/持续部署等功能&#xff0c;还支持通过其内置的邮件功能实现自动化邮件发送。AokSend将深入探讨如何在GitLab中配置和使用邮箱发送邮件功能。 GitLab邮箱发…

ERP进销存管理系统的业务全流程 Axure高保真原型源文件分享

这是一套ERP进销存管理系统的业务全流程Axure高保真原型设计文档。 原型预览地址&#xff1a;https://ppndif.axshare.com 产品意义&#xff1a; 提高工作效率&#xff1a; 电子记账替代手工记账&#xff0c;减少工作负担和人为错误。 实时查看库存情况&#xff0c;减少盘点时…

Tomcat_WebApp

Tomcat的目录的介绍 /bin&#xff1a; 这个目录包含启动和关闭 Tomcat 的脚本。 startup.bat / startup.sh&#xff1a;用于启动 Tomcat&#xff08;.bat 文件是 Windows 系统用的&#xff0c;.sh 文件是 Linux/Unix 系统用的&#xff09;。shutdown.bat / shutdown.sh&#xf…

ICMC 2024 has Arrived, and We’ll See You There

It’s finally time for the International Cryptographic Module Conference this year! ICMC 2024 will perhaps be the most energized ICMC to date, as post-quantum cryptography (PQC) – a topic that’s been weighing on most of our minds – features prominently …

大模型研发全揭秘:带你掌握训练后模型的最佳存储方案

在大模型项目的研发中&#xff0c;模型保存是每个AI从业者都必须掌握的重要技能。保存模型不仅能让我们在未来进行推理和预测&#xff0c;还能帮助我们继续优化和调整模型。因此&#xff0c;掌握如何高效保存模型显得尤为重要。本文将通过详细的技术细节和清晰的步骤&#xff0…

使用密钥文件登陆Linux服务器

假设A服务器为登陆目标,已经运行ssh服务。 B服务器作为登陆发起端。 登陆A服务器,账户S。 运行命令: ssh-keygen -t rsa 此时账户S家目录下会自动创建目录“.ssh”,目录下会有id_rsa和id_rsa.pub两个文件。 id_rsa为私钥,id_rsa.pub为公钥。 id_rsa文件内容下载到B服务…

【无人机/平衡车/机器人】详解STM32+MPU6050姿态解算—卡尔曼滤波+四元数法+互补滤波(文末工程资料下载)

效果: 目录 基础知识详解 欧拉角 加速度计(Accelerometer)与姿态测量 陀螺仪(Gyroscope)与姿态测量 姿态解算算法1-互补滤波 姿态解算算法2-四元数法 姿态解算算法3-卡尔曼滤波 组成 1.预测状态方程 2. 预测协方差方程 3. 卡尔曼增益方程 4. 跟新最优值方程(卡尔…

攻防世界--->BABYRE

做题笔记。(可以作为例题。) 下载 查壳 64ida打开。 分析&#xff1a; 动态试一试。 跟进judge 很奇怪是一段.data(数据段) 报错&#xff0c;但是程序并没有结束&#xff1a; 我们对其进行处理&#xff1a;&#xff08;动态函数处理&#xff09; 因为call不能用在.data段&…

4.qml单例模式

这里写目录标题 js文件单例模式qml文件单例模式 js文件单例模式 直接添加一个js文件到qml中 修改内容 TestA.qml import QtQuick 2.0 import QtQuick.Controls 2.12 import "./MyWork.js" as MWItem {Row{TextField {onEditingFinished: {MW.setA(text)}}Button…

Docker部署及基本操作

Docker是一个开源的平台 &#xff0c;用于开发、交付和运行应用程序。它能够在Windows&#xff0c;macOS&#xff0c;Linux计算机上运行&#xff0c;并将某一应用程序及其依赖项打包至一个容器中&#xff0c;这些容器可以在任何支持Docker的环境中运行。容器彼此隔离&#xff0…

MySQL实战面试题(附案例答案+建表语句+模拟数据+案例深度解析),练完直接碾压面试官

知识点思维导图 案例1 建表语句与模拟数据 用户表 users CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL UNIQUE, signup_date DATE NOT NULL ); INSERT INTO users (username, email, signu…

『功能项目』QFrameWork框架重构OnGUI【63】

我们打开上一篇62QFrameWork背包框架的项目&#xff0c; 上文将功能实现在一个脚本中 本章要做的事情让脚本实现背包框架思想 首先按照图示创建脚本&#xff1a; 创建脚本&#xff1a;Item.cs namespace QFramework {public class Item{//道具public string Key;public string …

2024秋季云曦开学考

web ezezssrf 打开环境&#xff0c;代码审计 看起来有点多&#xff0c;要绕过五层 第一层&#xff1a;存在弱比较&#xff0c;使用数组或0e绕过 yunxi[]1&wlgf[]2 yunxis878926199a&wlgfs155964671a 第二层&#xff1a;存在强比较&#xff0c;此处使用string限制…

superset 解决在 mac 电脑上发送 slack 通知的问题

参考文档: https://superset.apache.org/docs/configuration/alerts-reports/ 核心配置: FROM apache/superset:3.1.0USER rootRUN apt-get update && \apt-get install --no-install-recommends -y firefox-esrENV GECKODRIVER_VERSION0.29.0 RUN wget -q https://g…

【智路】智路OS airos-edge

欢迎来到智路OS https://gitee.com/ZhiluCommunity/airos-edge 智路OS是全球首个开源开放的智能网联路侧单元操作系统&#xff08;简称“智路OS”&#xff09;&#xff0c; 是以高等级自动驾驶技术为牵引&#xff0c;沉淀出来的“车路云网图”一体化的智能交通基础软件平台。…

Ansible——Playbook基本功能

文章目录 一、Ansible Playbook介绍1、Playbook的简单组成1&#xff09;“play”2&#xff09;“task”3&#xff09;“playbook” 2、Playbook与ad-hoc简单对比区别联系 3、YAML文件语法&#xff1a;1. 基本结构2. 数据类型3. 列表4. 字典&#xff08;映射&#xff09;5. 注释…

【数据结构】排序算法---归并排序

文章目录 1. 定义2. 算法步骤3. 动图演示4. 性质5. 算法分析6. 代码实现C语言——迭代版C语言——递归版PythonJavaC——迭代版C——递归版Go 结语 1. 定义 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效的排序算法。该算法是采用分治法&#xff0…

CentOS7.9环境上NFS搭建及使用

Linux环境NFS搭建及使用 1. 服务器规划2. NFS服务器配置2.1 主机名设置2.2 nfs安装2.2.1 repo文件替换2.2.2 NFS服务安装 2.3 nfs配置2.4 服务查看2.5 资源发布2.6 配置nfs服务开机自启2.7 端口开放 3.应用服务器配置3.1 主机名设置3.2 nfs安装3.2.1 repo文件替换3.2.2 NFS服务…