记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST

记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST问题描述这两天用Go做一个比较简单的task:后端有HTTPServer和TCPServer。客户端通过http接入到HTTPServer,HTTPServer通过RPC将请求发送到TCPServer,所有的业务逻辑都由TCPServer处理。压测:自己的mac电脑(CPU:Inteli7,4核,2.7GHz。内存:16G),硬件够用。客户端用Go编写,1个goruntine启…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

问题描述

    这两天用Go做一个比较简单的task:后端有HTTPServer和TCPServer。客户端通过http接入到HTTPServer,HTTPServer通过RPC将请求发送到TCPServer,所有的业务逻辑都由TCPServer处理。

    压测:自己的mac电脑(CPU:Intel i7, 4核,2.7GHz。内存:16G),硬件够用。客户端用Go编写,1个goruntine启动一个HTTPClient往HTTPServer发送http请求。每个HTTPClient限定为一个HTTP长链接。

    问题:压到400个HTTPClient,出现一些错误提示“read: connection reset by peer”。

问题定位以及原因

“connection reset by peer”的含义是往对端写数据的时候,对端提示已经关闭了连接。一般往一个已经被关闭的socket写会提示这个错误。但是通过log分析,服务端没有应用层面的close,客户端也没有应用层面的write。抓包发现客户端建立TCP完成3次握手后,服务端立刻就回了RST。如下图:

记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST

这个抓包很好的反应了压测中的现象:错误提示connection reset by peer,但是应用层并没有任何的读写,TCP三次握手后服务端直接通过RST关闭了连接。RST的情况见的多,这种情况着实没有遇到过。最后N次baidu google,终于找到答案。

TCP三次握手后服务端直接RST的真相

内核中处理TCP连接时维护着两个队列:SYN队列和ACCEPT队列,在建立连接过程中,服务端内核的处理过程如下:

  • (1)客户端使用connect调用向服务端发起TCP连接,服务端内核将此连接信息放入SYN队列,返回SYN-ACK
  • (2)服务端内核收到客户端的ACK后,将此连接从SYN队列中取出,放入ACCEPT队列
  • (3)服务端应用层调用accept函数将连接从ACCEPT队列中取出

上述抓包说明,3次握手已经完成。但是应用层accept并没有返回,说明问题出在ACCEPT队列中。那么什么情况下,内核TCP协议栈会在三次握手完成后发RST呢?原因就是ACCEPT队列满了,上述(2)中,服务端内核收到客户端的ACK后将连接放入ACCEPT队列失败,就有可能回RST拒绝连接。

进一步来看Linux协议栈的一些逻辑:SYN队列和ACCEPT队列的长度是有限制的,SYN队列长度由内核参数tcp_max_syn_backlog决定,ACCEPT队列长度可以在调用listen(backlog)通过backlog,但总最大值受到内核参数somaxconn(/proc/sys/net/core/somaxconn)限制。若SYN队列满了,新的SYN包会被直接丢弃。若ACCEPT队列满了,建立成功的连接不会从SYN队列中移除,同时也不会拒绝新的连接,这会加剧SYN队列的增长,最终会导致SYN队列的溢出。当ACCEPT队列溢出之后,只要打开tcp_abort_on_overflow内核参数(默认为0,关闭),建立连接后直接回RST,拒绝连接(可以通过/proc/net/netstat中ListenOverflows和ListenDrops查看拒绝的数目)

所以真相找到了:就是ACCEPT队列溢出了导致TCP三次握手后服务端发送RST

回到我的压测环境,mac电脑的内核是unix,所以以上的一些参数别说调整了,有些找都找不到在哪。但是somaxconn这个倒是找到了:

记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST

而我压测的时候起400个goruntine,同时跟服务端建立HTTP连接,可能导致了服务端的ACCEPT队列溢出。这里之所以用可能,是因为并没有找到证据,只是理论上分析。但是验证这个问题简单:修改一下内核参数somaxconn。但是不想在mac电脑上搞了,于是将建立HTTP连接的速度放慢,20ms一个。果然,错误消失了,400个、800个、2000个client,都OK。

总结

  1. 理论还是很重要的。特别是遇到网络层面的疑难杂症,一定要结合理论,根据现象去推导。
  2. 没有头绪的时候,就抓包吧。
  3. 不要在mac上搞压测这种事,测试尽量跟线上保持一样的环境

参考

TCP连接的建立和终止

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/187093.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 用FastJson将JSON字符串转Json[通俗易懂]

    用FastJson将JSON字符串转Json[通俗易懂]一、导入jar<!–fastjson–><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.1.15</version></dependency>二、Fas

    2022年9月27日
    0
  • ping命令和tracert命令的作用_ping命令有哪些

    ping命令和tracert命令的作用_ping命令有哪些本文只是总结了两个常用的网络命令的实现原理和一点使用经验说明。这些东西通常都分布在各种书籍或者文章中的,我勤快那么一点点,总结一下,再加上我的一点理解和使用经验,方便大家了解。这些也是很基础的东西,没什么高深的。Ping这个应该大家都会用的吧,最主要的就是检测目标主机是不是可连通。Ping程序实际就是发送一个ICMP回显请求报文(就是请求别人收到这个报文之后回显)给目的主机,并等待回显的ICM…

    2022年9月24日
    0
  • linux嵌入式系统的缺点,arm嵌入式主板的优缺点

    嵌入式主板是嵌入在设备里面做控制、数据处理使用的CPU板,常见的有两类,即基于X86的嵌入式主板和基于RISC的ARM嵌入式主板。今天我们就来认识arm嵌入式主板,arm嵌入式主板就是一个嵌入在设备里面做控制、数据处理使用的CPU板。一般作为工控主板使用。ARM处理器是一种16/32位的嵌入式RISC微处理器,具有低成本、高性能、低功耗的特点。ARM9系列微处理器具有以下特点:支持32位ARM…

    2022年4月9日
    84
  • J2EE究竟是什么?「建议收藏」

    J2EE究竟是什么?「建议收藏」J2EE(即Java2平台企业版)是由Sun公司主持推出的一项中间件技术。从CORBA、IDL到面向消息的系统,中间件技术已经走过了很长的一段路程,如今J2EE作为中间件技术史上的一块具有决定意义的里程碑,正受到业界越来越广泛的重视和采纳。J2EE,一方面有着一套相当庞大的标准体系和数个不同版本,另一方面,由于市场上应用服务器品种多样,各家开发商使用的术语又不尽相同,因此,围绕着J2EE,常

    2025年6月6日
    0
  • freemarker 将后台传来的为“Tue Jan 06 16:00:50 CST 1970” 日期格式,格式化为yyyy-MM-dd HH:mm:ss

    freemarker 将后台传来的为“Tue Jan 06 16:00:50 CST 1970” 日期格式,格式化为yyyy-MM-dd HH:mm:ssfreemarker 将后台传来的为“Tue Jan 06 16:00:50 CST 1970” 日期格式,格式化为yyyy-MM-dd HH:mm:ss

    2022年4月23日
    62
  • UI标签库专题十三:JEECG智能开发平台 ckfinder(ckfinder插件标签)

    UI标签库专题十三:JEECG智能开发平台 ckfinder(ckfinder插件标签)

    2021年12月3日
    42

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号