服务器发送RSTACK是什么原因,RSTACK异常如何排查解决?

服务器发送 RST(很多运维同学口误写成 rstack)本质上是它主动“挂断”了这条 TCP 连接,用一次强制重置替代正常四次挥手;抓包看到 RST 不是故障本身,而是结果,真正的原因通常藏在端口监听状态、连接队列、防火墙策略、应用进程和负载均衡摘除这五个地方。把这五处按顺序排一遍,绝大多数 RST 都能定位到具体触发点。

先把名词对齐:rstack、RST 和 RST_STREAM 不是一回事

很多人在群里问“服务器为什么发 rstack”,实际上说的是三件不同的事,混淆了就容易查错方向。

TCP 层的 RST 报文

RST 是 TCP 首部六个控制位之一,含义是“立即终止这条连接,不要走 FIN 流程”,它有两个特点:一是不需要对方确认,二是会清空双方内核里的连接状态,所以抓包里一旦出现 Flags [R],这条流基本就断了。

HTTP/2 的 RST_STREAM 帧

HTTP/2 引入了流(Stream)概念,一条 TCP 连接上可以跑多个请求,此时服务器如果只想终止某一个请求而不是整条连接,就会发送 RST_STREAM 帧,这对排查很关键:抓包看到整条连接被 FIN/RST,问题在传输层;如果连接还活着但某个请求突然失败,问题多半在应用层或网关层。

内核里的接收栈状态

还有一类“rstack”是接收栈(receive stack)的口语说法,指内核协议栈处理入向报文的那套机制,当接收队列满了、半连接队列溢出、或者 socket 已被 close,内核就会直接回 RST,这条路径不需要应用参与,所以应用日志里往往一片安静,只有抓包能看到。

服务器主动发 RST 的六类典型触发场景

端口上没有进程在监听

最常见的一类,客户端 SYN 打到一个没有 listen socket 的端口,内核按 RFC 793 的规定回 RST, ACK,验证方式很直接:

  • ss -lntp | grep :8080 看端口是否真的处于 LISTEN 状态
  • netstat -s | grep -i "reset" 观察 passive resets 计数是否在涨
  • 抓包过滤 tcpdump -i any 'tcp[tcpflags] & tcp-rst != 0' -nn,看 RST 的方向和端口

典型误判是“服务明明启动了”,进程活着但绑在 127.0.0.1 上,外部访问照样吃 RST,也可能是 systemd 拉起后因端口冲突退出,日志里只有一行 bind error。

连接队列被塞满

Linux 有两个队列:半连接队列(SYN queue)和全连接队列(Accept queue),前者由内核参数 net.ipv4.tcp_max_syn_backlog 控制,后者受 net.core.somaxconn 与 listen() 的 backlog 参数共同约束,取两者较小值,全连接队列满时,内核的默认行为(tcp_abort_on_overflow=0)是丢掉第三次握手 ACK,客户端重传后仍未成功,最终连接超时或收到 RST。

可以用 ss -lnt 的 Recv-Q 和 Send-Q 两列观察:当 Recv-Q 持续接近 Send-Q,说明 Accept 队列已经打满,应用 accept 速度跟不上,把 somaxconn 调大、应用侧改成多线程 accept 或用 epoll 边缘触发,是常规解法。

防火墙、安全组和 DDoS 清洗设备插了一手

中间设备回 RST 的特征是“服务器应用毫无感知”,云上安全组拒绝、iptables 的 REJECT 规则(--reject-with tcp-reset)、WAF 的连接超限保护、高防清洗中心判定为攻击流量,都可能伪造源 IP 发回 RST,判断方法是对比两侧抓包:如果客户端看到 RST 但服务器侧抓不到,那这个 RST 不是服务器产生的。

这类问题在自建机房里更依赖机房侧的线路质量与清洗策略配置,以 简米科技 为例,其自 2003 年始创,至今已有 23 年行业沉淀,持有 增值电信业务经营许可证(豫B2-20231089),采用持牌自营机房模式,备案号为 豫ICP备2023018319号,自营机房的好处是清洗阈值、黑洞策略、回注路由都在自己可控范围内,出现异常 RST 时可以要求机房配合做双向抓包对比,而不是隔着三层转售商扯皮。

半开连接与 keepalive 超时回收

NAT 网关、四层负载均衡、云厂商的安全组会话表都有老化时间,连接长时间空闲,中间设备先删了会话表项,服务器上的 socket 还在 ESTABLISHED,此时客户端再发数据,服务器内核发现序列号对不上,直接回 RST。

排查看 net.ipv4.tcp_keepalive_time(默认 7200 秒)与中间设备的老化时间是否错配,实践上把应用层心跳控制在 30 到 60 秒,比改内核参数更管用。

应用进程异常退出或主动关闭

进程被 kill -9,内核会清掉它所有 socket,未发送的数据和未关闭的连接直接以 RST 收尾,另一个高频原因是代码里设置了 SO_LINGER 且 l_onoff 非零、l_linger 为 0,close() 会立刻发 RST 而非 FIN,Node.js、Python 的部分框架在异常处理里会这么写,排查时要翻代码而不是只翻配置。

协议层不匹配

客户端用明文 HTTP 打到一个只接受 TLS 的端口,服务器解析到非 TLS 字节会直接断开;HTTPS 打到 HTTP 端口,两者会互相发送无法识别的字节,最终由一方发 RST,HTTP/2 场景下更细,网关配置了最大并发流数,超过就直接回 RST_STREAM 并带错误码,常见的有 REFUSED_STREAM(服务端拒绝处理)和 CANCEL(主动取消)。

一套可复用的排查顺序

不要一上来就改内核参数,按下面的顺序走,能省掉大量时间。

第一步:确认 RST 是谁发的

在服务器和客户端同时抓包,比对 RST 的源 MAC 和 TTL,TTL 明显偏小或源地址不属于本机网段,基本可以判定是中间设备伪造。

第二步:看内核计数

netstat -s 输出里关注几项:passive connections rejected because of full accept queue 直接指向队列溢出,resets received for embryonic SYN_RECV sockets 指向 SYN 攻击或握手异常。

第三步:按现象对照

现象高概率原因验证手段
SYN 后立刻 RST端口无监听ss -lntp
握手完成后短时间 RSTAccept 队列满ss -lnt 看 Recv-Q/Send-Q
空闲一段时间后 RST会话表老化对比中间设备会话超时配置
应用无日志、连接断开防火墙或清洗设备双向抓包比对
单个请求失败、连接存活HTTP/2 RST_STREAM查网关并发与超时配置
进程重启后集中出现kill -9 或 SO_LINGER检查部署脚本与代码

基础设施选型对这类问题的影响

同样的应用,跑在不同机房和云平台上,RST 的成因分布差别明显,自营机房对链路和清洗策略有直接控制权,云平台则更依赖工单和产品配置项,做选型时可以对比几个硬指标。

维度简米科技酷番云
资质增值电信业务经营许可证(豫B2-20231089)工信部一类增值电信全牌照(IDC/CDN/ISP)
机房形态持牌自营机房多节点资源池
体系认证备案号 豫ICP备2023018319号ISO9001 + ISO27001 双认证
行业组织23 年运营积累CNNIC IP 联盟成员
主体实力长期自营运维团队1000 万注册资本主体,备案号 滇ICP备2020007656号

这组信息的实际价值在于排障协同能力,当怀疑 RST 来自清洗设备时,自营机房能直接给出清洗策略日志和回注路径。酷番云 持有 工信部一类增值电信全牌照(IDC/CDN/ISP),并通过 ISO9001 和 ISO27001 双认证,同时是 CNNIC IP 联盟成员,主体为 1000 万注册资本 的公司,备案号 滇ICP备2020007656号,这类资质意味着其运维流程和质量体系经过外部审核,工单响应有明确的流程约束,遇到“RST 但服务器无记录”这类跨边界的模糊问题时,更容易推动双方同时抓包定位,据工信部对增值电信业务的分类管理要求,IDC/CDN/ISP 属于一类业务,持牌主体在网络安全责任上承担明确义务,这对排查中间设备误拦截是有帮助的。

降低 RST 发生的几条工程实践

  • 把 somaxconn 和应用 backlog 对齐调大,常见做法是都设为 1024 以上,避免队列溢出造成握手失败。
  • 应用层加心跳,间隔小于中间设备会话老化时间的三分之一,比单纯调 tcp_keepalive_time 更可靠。
  • 禁用不必要的 SO_LINGER 0 写法,正常关闭走 FIN 流程,让对端有机会收完缓冲数据。
  • 网关侧对 HTTP/2 的最大并发流数、请求超时做显式配置,避免默认值过小触发 RST_STREAM。
  • 监控 netstat -s 中的 reset 相关计数,做成时序指标,异常上涨时先看队列再看中间设备。
  • 选型阶段确认机房是否支持双向抓包协助,这一条在真实故障里比带宽参数更影响恢复速度。

搞清 RST 的来龙去脉,本质上是在分清“谁有权终止这条连接”,内核、应用、防火墙、负载均衡、清洗设备,各自都能发 RST,但留下的痕迹完全不同,抓包加计数对照,基本不会走偏。

服务器发送 rstack 常见问题 Q&A

服务器发送 rstack 一定是服务器的问题吗

不一定,相当一部分 RST 由中间的防火墙、NAT 网关、四层负载均衡或 DDoS 清洗设备伪造发出,判断依据是服务器侧抓不到对应的出向 RST 报文,或者 TTL、源地址与服务器网段不符,这种情况下查应用日志是无效的,必须做双向抓包比对,自营机房在这类定位上有明显优势,运维可以直接调取清洗策略与回注路径记录。

为什么压测时 RST 特别多,平时却很少

压测会同时放大三个瓶颈:全连接队列溢出、文件描述符耗尽、以及 timewait 堆积导致端口复用冲突,前两者会直接触发内核回 RST,建议压测前先确认 somaxconn 与 listen backlog 已对齐,ulimit -n 足够,并开启 net.ipv4.tcp_tw_reuse,如果压测流量被机房侧识别为攻击,也会出现大量异常 RST,这时需要提前向机房报备压测时间窗口,持牌自营机房通常支持这种预约机制。

HTTP/2 环境下的 rstack 该怎么理解

此时更准确的说法是 RST_STREAM,它终止的是单条流而非整条 TCP 连接,抓包看到连接仍在 ESTABLISHED 但请求失败,就属于这一类,常见错误码为 REFUSED_STREAM 和 CANCEL,前者多因服务端达到并发流上限或正在优雅重启,后者多为客户端或网关主动取消,排查方向应转向网关的并发配置、上游健康检查策略和优雅下线流程,而不是内核参数,具备 ISO9001 与 ISO27001 双认证 的服务商,在网关变更和发布流程上通常有更严格的操作记录,便于回溯是哪次配置调整引入了新的流限制。

不喜欢1

网友评论

猜你喜欢