Netty 出现 Connection reset by peer 异常的几个原因
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty 出现 Connection reset by peer 异常的几个原因相关的知识,希望对你有一定的参考价值。
参考技术A 最近使用 netty 过程中发现了几个比较细节的 Connection reset by peer 异常,做个笔记。这个场景出现在用 Jedis ping 检测的场景,用完直接 close,服务端稳定出现 Connection reset by peer。
tcpdump 一下就很容易定位到问题所在,客户端收到 PONG 响应后直接发了一个 RST 包给服务端:
查看 Jedis 的源码发现 socket 有个比较特殊的配置 socket.setSoLinger(true, 0) 。
先看一下 man7/socket.7 的解释:
坦白说不是很明白啥意思。。。
最终在 stackoverflow 上找到一个比较容易理解的解释:
简而言之,设置 SO_LINGER(0) 可以不进行四次挥手直接关闭 TCP 连接,在协议交互上就是直接发 RST 包,这样的好处是可以避免长时间处于 TIME_WAIT 状态,当然 TIME_WAIT 存在也是有原因的,大部分评论都不建议这样配置。
这个场景有点儿微妙,首先得理解一下 tcp 的两个队列。
这篇文章讲得比较清楚: SYN packet handling in the wild
accept 队列满通常是由于 netty boss 线程处理慢,特别是在容器化之后,服务刚启动的时候很容易出现 CPU 受限。
为了模拟这个现象,我写了个示例程序 shichaoyuan/netty-backlog-test ,设置 SO_BACKLOG 为 1,并且在 accept 第一个连接后设置 autoRead 为 false,也就是让 boss 线程不再继续 accept 连接。
启动第一个 Client,可以正常连接,发送 PING,接收 PONG。
启动第二个 Client,也可以正常连接,但是没有收到 PONG:
可见这个连接创建成功了,已经在 Accept Queue 里了,但是进程没有 accept,所以没有与进程绑定。
启动第三个 Client,也可以正常连接,也没有收到 PONG:
与第二个连接一样。
启动第四个 Client,也可以正常连接,但是在发送 PING 后出现 Connection reset by peer:
这个连接在服务端并没有进入 accept queue,处于 SYN_RECV 状态,并且很快就消失了(因为 accept queue 已经满了,无法转入 ESTABLISHED 状态)。
抓包看一下:
从客户端视角来看连接确实是建成功了,有一个比较特殊的地方在三次握手之后,服务端又向客户端发送了一个 [S.],客户端回复了一个 [.],这个交互看起来不影响连接。
服务端后来销毁了连接,而客户端还认为连接是 ESTABLISHED 的,发送 PING 消息,服务端自然得回复一个 RST。
PS:我在 Windows 10 的 WSL2 中实验这种场景是建连接超时,可能不同的操作系统或 linux 版本对这个交互的过程处理不同,在此不进行进一步测试了。
以上,这个故事告诉我们判断连接是否可用,建成功之后应该发个心跳包测试一下。
以上是关于Netty 出现 Connection reset by peer 异常的几个原因的主要内容,如果未能解决你的问题,请参考以下文章
在控制台中出现错误:无法加载资源:net::ERR_CONNECTION_RESET
mac环境下往码云提交代码出现ex_exchange_identification: read: Connection reset by peer Connection reset by 180.97
mac环境下往码云提交代码出现ex_exchange_identification: read: Connection reset by peer Connection reset by 180.97
mac环境下往码云提交代码出现ex_exchange_identification: read: Connection reset by peer Connection reset by 180.97