当前位置: 首页 > news >正文

nginx keepalive设置失效k6显示i/o timeout解决方案

nginx keepalive设置失效

原因:没有启用http1.1以及没有取消'Connection:close'请求头

解决方案:

    location / {
        # ...
        proxy_set_header Connection "";
        proxy_http_version 1.1;
    }

k6显示i/o timeout

原因:keepalive_timeout设置为了0,导致nginx会在http相应中加入connection:close断开连接,显示i/otimeout的http请求根本没有发送给nginx,不清楚是tcp连接建立失败还是k6根本没有发起握手。根据抓包结果来看,对于k6发起的syn包nginx都有回复ACK,所以我倾向于k6没有发起握手。

解决方案:

http {
    #...
    keepalive_timeout  65;
    #...
}

下面是问题的一些排除思路:

最初发现问题是因为拿k6做负载性测试时nginx返回了502 bad getway页面,以及k6报错i/o timeout,但是当我直接用k6请求后端服务器的时候结果可以正常返回,所以我用控制变量的思路将upstream设置成了刚刚测试的一台后端服务器,发现nginx和k6依然报错。由此,我定位问题在nginx的配置上。

我查看nginx的error.log日志发现报错

2025/03/18 08:08:52 [error] 35#35: *59365 connect() failed (111: Connection refused) while connecting to upstream, client: 172.17.0.1, server: localhost, request: "POST /orders HTTP/1.1", upstream: "http://<后端服务器ip>:3001/orders", host: "192.168.1.34:3001"

该错误标明nginx和后端服务器建立连接失败,因为在不启用长连接的情况下,nginx每建立一条连接就要消耗一个临时端口,所以首先我想到的是nginx临时端口耗尽导致无法和后端服务器建立连接。

于是我在设置了keepalive:100,然后负载性测试时检测了动态端口的使用总数,发现没有超限(其实不设置的话应该也不会超限,因为keepalive:100其实并未生效,我当时没有控制变量)。

接下来我怀疑是文件描述符不足,由于我的nginx运行在docker内,宿主机是windows系统,windows并没有文件描述符的概念,类似的概念是文件句柄,于是我打开任务管理器动态监测了文件句柄。我的docker原本同时在运行其他容器,句柄数达到了21000以上,我将其他容器关掉后运行k6的句柄峰值在3000左右,所以我认为不是文件描述符不足的原因。

最后我决定直接抓包分析一下,我给k6发出的每个请求加上了请求头X-Request-Id,并且设置了'proxy_set_header X-Request-Id $http_x_request_id;'确保nginx发送给后端服务器的请求也会带上请求头X-Request-Id,其值由uuidv4生成,同时记录了请求发送的时间,先直接请求后端服务器,在运行k6的客户端上抓包。然后请求nginx,在运行k6的客户端和nginx服务器上分别抓包,对比k6发送给后端服务器的请求和nginx发送给后端服务器的请求的区别。

1. k6发送的http请求版本是http/1.1,nginx发送的http请求版本是http/1.0

2. k6发送的http请求没有添加connection字段,nginx发送的http请求添加了请求头connection:close

3. 右键追踪流-TCP stream,发现k6建立的一条tcp连接会发送多次Http请求与响应,nginx建立的一条tcp连接在服务器发送完第一条http响应后就被服务器端关闭

4. 拿抓包结果验证使用的端口数量,路径是统计-端点-ipv4,发现nginx使用了三千多的临时端口

以上证据都标明k6启用了长连接,而nginx并未启用长连接,而证据1、2其实就对应着nginx启用长连接的解决方案。如果不启用http1.1,即使去掉了Connection: close的请求头,服务端也会返回Connection:close的请求头断开连接。

至于nginx的错误日志中现实的connect failed,根据报错数量与时间判断,就是nginx返回502响应的请求。为了进行验证,我找到了502响应请求对应的X-Request-Id,通过Ctrl+f全局搜索‘分组详情’里对应的X-Request-Id,发现该X-Request-Id值只出现了一次,说明nginx并没有向后端服务器发送http请求,原因正是连接建立失败。

连接建立失败的原因是客户端因为没有收到服务端发送的ack,所以重发了三次syn包,然后就收到了服务端的RST响应。至于服务端为什么没有返回ack,我认为应该是因为服务器的半连接队列满了(这块没有验证,可以自行扩大服务器半连接队列长度进行验证)。

防止半连接队列满就需要减少连接数量,开启长连接。这也就是为什么开启长连接后不再返回502 bad getaway。

至于k6显示i/o timeout,正如最开始所说,抓包显示nginx返回了connection:close请求头,解决方案就是不要把keepalive_timeout设置为0。

相关文章:

  • Redis项目:秒杀业务(优化)
  • 知识蒸馏:让大模型“瘦身”的魔法
  • LiteratureReading:[2016] Enriching Word Vectors with Subword Information
  • Mac:Maven 下载+安装+环境配置(详细讲解)
  • 过往记录系列 篇四:年报月行情历史梳理
  • std::expected
  • 深度学习 第4章 数值计算和 Deepseek 的实践
  • 【初学者】怎样学习、使用与研究算法?
  • 阅读《Vue.js设计与实现》 -- 02
  • 【Notepad】Notepad优化笔记AutoHotkey语法高亮\设置替换默认的notepad程序\设置主题\增加返回上一个编辑地方插件
  • Android 12系统源码_系统启动(一)init进程
  • 配置阿里云yum源
  • 算法模型从入门到起飞系列——深度优先遍历(DFS)
  • 数据无忧:自动备份策略全解析
  • Java 集合框架
  • 基于FPGA的DDS连续FFT 仿真验证
  • Ubuntu Qt: no service found for - “org.qt-project.qt.mediaplayer“
  • 第14周-Seq2Seq模型-NLP
  • 新型教材≠免设计课程
  • yt-dlp工具下载视频使用方法
  • 解读|特朗普“助攻”下加拿大自由党“惨胜”,卡尼仍需克服“特鲁多阴影”
  • 探索演艺产业新路径,2万观众走进音乐科技融创节
  • 今年一季度全国社会物流总额达91万亿元,工业品比重超八成
  • 新剧|反谍大剧《绝密较量》央一开播,张鲁一高圆圆主演
  • 国家发改委回应美加征关税:典型的单边主义霸凌做法
  • 大家聊中国式现代化|周冯琦:转角见美,让“绿意”触手可及