连接被对端重置(connection reset by peer)的定位与修复
客户端报 read: connection reset by peer、Connection reset by peer、ECONNRESET,Go 程序还可能看到 unexpected EOF,写操作则可能报 broken pipe。它和 Connection refused、连接超时都不同:refused 是目标端口没有监听或被明确拒绝,超时是数据包被静默丢弃,而 RST 表示对端或中间设备主动发送了重置包。
RST 可能发生在 TLS 握手、请求发送、等待响应或空闲连接复用时。定位的关键不是只看报错文本,而是确认“谁发的 RST、发生在哪个阶段、当时连接处于什么状态”。
先复现并观察连接状态:
curl -v --no-keepalive https://<host>/
curl -v https://<host>/ https://<host>/ https://<host>/
ss -tin state established '( dport = :<port> or sport = :<port> )'
抓包确认 RST 的来源和阶段:
tcpdump -ni any -vvv 'host <host> and port <port>'
nstat -az | grep -i -E 'reset|abort|overflow|drop'
journalctl -u <service> --since '30 min ago'
dmesg -T | tail -50
Kubernetes 场景同时看副本重启和端点变化:
kubectl get pod -n <ns> -o wide
kubectl describe pod <pod> -n <ns>
kubectl logs <pod> -n <ns> --previous
kubectl get endpointslice -n <ns> -o wide
kubectl get events -n <ns> --sort-by=.lastTimestamp | tail -30
NAT 或负载均衡场景检查会话表:
conntrack -S
sysctl net.netfilter.nf_conntrack_tcp_timeout_established
sysctl net.ipv4.tcp_abort_on_overflow
tcpdump 里看 RST 的源地址:源是服务端,说明服务进程、内核队列或服务端防火墙主动重置;源是客户端,则可能是客户端超时放弃、连接池关闭或客户端侧设备拦截。如果单次新建连接正常、连续请求或等待一段时间后失败,重点查连接复用和超时;如果每次建连都失败,重点查协议、端口和中间设备。抓包时同时记录两端时间,避免时钟偏差造成误判。
tcp_abort_on_overflow=1 时内核直接回 RST;为 0 时通常表现为丢包和超时。REJECT --reject-with tcp-reset,或云防火墙会话超时后重置连接。preStop 或优雅关闭不完整。broken pipe,随后连接被重置。SO_LINGER 为 0,或关闭连接前丢弃接收缓冲区,主动发送 RST 而不是正常 FIN。ss 对齐时间线,确认 RST 是服务端、客户端还是中间设备发出,再决定排查方向。--previous 日志;修复崩溃原因,并补齐优雅关闭。ListenOverflows、ListenDrops 和 SYN 重传,调整 somaxconn、tcp_max_syn_backlog 以及应用的 accept 并发。DROP 或 REJECT;健康检查、长连接端口要显式放行。preStop 等待、设置合理的 terminationGracePeriodSeconds,并让就绪探针在关闭前先失败;长连接客户端仍要能重连。SO_LINGER 0 或在 close 前丢弃接收缓冲区;正常情况下应使用 FIN 优雅关闭,让在途数据完成。tcp_abort_on_overflow 打开;它只是把静默丢包变成重置,可能掩盖真正的容量问题。合上页面,先回答,再展开对照。
connection reset by peer 与 connection refused、连接超时的本质区别是什么?refused 表示目标端口没有监听或被明确拒绝;超时表示数据包被静默丢弃或路径不通。tcpdump -vvv 看 RST 的源地址、TCP 标志和时间点,结合 ss -tin 的队列/重传状态、nstat 计数以及服务端日志,判断是握手、请求、响应还是空闲阶段。
小程序版
微信扫码,随时查命令