摘要:猜测原因是一端异常关闭了连接却没有通知对端,或者通知了对端但对端没有收到。序号请求设置了超时时间为,因此发送包。之后继续测试,没有发现丢包。序号空闲分钟后,主动发起报文,关闭连接。
一、故障
基本架构如图所示,客户端发起 http 请求给 nginx,nginx 转发请求给网关,网关再转发请求到后端微服务。
故障现象是,每隔十几分钟或者几个小时不等,客户端就会得到一个或者连续多个请求超时错误。查看 nginx 日志,对应请求返回 499;查看网关日志,没有收到对应的请求。
从日志分析,问题应该处在 nginx 或者 spring-cloud-gateway 上。
nginx 版本:1.14.2,spring-cloud 版本:Greenwich.RC2。
nginx 主要配置如下:
[root@wh-hlwzxtest1 conf]# cat nginx.conf worker_processes 8; events { use epoll; worker_connections 10240; } http { include mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; #gzip on; upstream dbg2 { server 10.201.0.27:8888; keepalive 100; } server { listen 80; server_name localhost; charset utf-8; location /dbg2/ { proxy_pass http://dbg2/; proxy_http_version 1.1; proxy_set_header Connection ""; } } }
为了提高性能,nginx 发送给网关的请求为 http 1.1,可以复用 tcp 连接。
二、排查 1、查看 tcp 连接[root@10.197.0.38 logs]# ss -n | grep 10.201.0.27:8888 tcp ESTAB 0 0 10.197.0.38:36674 10.201.0.27:8888 tcp ESTAB 0 0 10.197.0.38:40106 10.201.0.27:8888 [root@10.201.0.27 opt]# ss -n | grep 10.197.0.38 tcp ESTAB 0 0 ::ffff:10.201.0.27:8888 ::ffff:10.197.0.38:40106 tcp ESTAB 0 0 ::ffff:10.201.0.27:8888 ::ffff:10.197.0.38:39266
可以看到 nginx 和网关之间建立的 socket 连接为 (10.201.0.27:8888,10.197.0.38:40106),另外的 2 条记录就很可疑了。猜测原因是:一端异常关闭了 tcp 连接却没有通知对端,或者通知了对端但对端没有收到。
2、抓包分析先看下 nginx 的抓包数据:
序号 8403:转发 http 请求给网关;
序号 8404:在 RTT 时间内没有收到 ack 包,重发报文;
序号 8505:RTT 约等于 0.2s,tcp 重传;
序号 8506:0.4s 没收到 ack 包,tcp 重传;
序号 8507:0.8s 没收到 ack 包,tcp 重传;
序号 8509:1.6s 没收到 ack 包,tcp 重传;
...
序号8439:28.1s(128RTT)没收到 ack 包,tcp 重传。
序号 8408:请求设置了超时时间为 3s,因此发送 FIN 包。
再看下网关的抓包数据:
序号 1372:17:24:31 收到了 nginx 发过来的 ack 确认包,对应 nginx 抓包图中的序号 1348(nginx 那台服务器时间快了差不多 1 分 30 秒);
序号 4221:2 小时后,发送 tcp keep-alive 心跳报文,(从 nginx 抓包图中也可以看出这 2 小时之内该 tcp 连接空闲);
序号 4253:75s 后再次发送 tcp keep-alive 心跳;
序号 4275:75s 后再次发送心跳;
连续 9 次;
序号 4489:发送 RST 包,通过对端重置连接。
2 小时,75s, 9 次,系统默认设置。
[root@eureka2 opt]# cat /proc/sys/net/ipv4/tcp_keepalive_time 7200 [root@eureka2 opt]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl 75 [root@eureka2 opt]# cat /proc/sys/net/ipv4/tcp_keepalive_probes 9
具体这几个参数的作用,参考文章:为什么基于TCP的应用需要心跳包
3、分析通过以上抓包分析,基本确认了问题出在 nginx 上。19:25 时,网关发送 tcp keep-alive 心跳包给 nginx 那台服务器,此时那台服务器上保留着该 tcp 连接,却没有回应;22:20 时,nginx 发送 http 请求给网关,而网关已经关闭该 tcp 连接,因此没有应答。
三、解决 1、proxy_send_timeoutnginx 中与 upstream 相关的超时配置主要有如下参数,参考:Nginx的超时timeout配置详解
proxy_connect_timeout:nginx 与 upstream server 的连接超时时间;proxy_read_timeout:nginx 接收 upstream server 数据超时, 默认 60s, 如果连续的 60s 内没有收到 1 个字节, 连接关闭;
proxy_send_timeout:nginx 发送数据至 upstream server 超时, 默认 60s, 如果连续的 60s 内没有发送 1 个字节, 连接关闭。
这几个参数,都是针对 http 协议层面的。比如 proxy_send_timeout = 60s,并不是指如果 60s 没有发送 http 请求,就关闭连接;而是指发送 http 请求后,在两次 write 操作期间,如果超过 60s,就关闭连接。所以这几个参数,显然不是我们需要的。
2、upstream 模块的 keepalive_timeout 参数查看官网文档,Module ngx_http_upstream_module,
Syntax: keepalive_timeout timeout; Default: keepalive_timeout 60s; Context: upstream This directive appeared in version 1.15.3.
Sets a timeout during which an idle keepalive connection to an upstream server will stay open.
设置 tcp 连接空闲时间超过 60s 后关闭,这正是我们需要的。
为了使用该参数,升级 nginx 版本到 1.15.8,配置文件如下:
http { upstream dbg2 { server 10.201.0.27:8888; keepalive 100; keepalive_requests 30000; keepalive_timeout 300s; } ... }
设置 tcp 连接上跑了 30000 个 http 请求或者空闲 300s,那么就关闭连接。
之后继续测试,没有发现丢包。
序号 938:空闲 5 分钟后,nginx 主动发起 FIN 报文,关闭连接。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/40322.html
摘要:上面的代码中定义了一个名为的负载均衡器,里面有三个后端服务,他们是按的方式进行轮询的。在模块中,可以设置后端服务器的信息,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有表示当前的暂时不参与负载均衡。 最近在学习如何对 Nginx 进行配置,故而对 Nginx 的配置文件的结构功能有了一些新的认识。刚开始接触 Nginx 时,感觉它的配置十分高深、难以理解,需要配置什么...
阅读 909·2023-04-26 01:34
阅读 3342·2023-04-25 20:58
阅读 3200·2021-11-08 13:22
阅读 2094·2019-08-30 14:17
阅读 2502·2019-08-29 15:27
阅读 2655·2019-08-29 12:45
阅读 2965·2019-08-29 12:26
阅读 2793·2019-08-28 17:51