记一次压测问题定位: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连接的建立和终止

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 计算机病毒的算法,计算机病毒从算法划分为几个类型

    计算机病毒的算法,计算机病毒从算法划分为几个类型随着计算机应用的日益普及,计算机病毒也开始入侵并呈不断蔓延趋势,对计算机的正常运行造成了威胁。那么,计算机病毒从算法划分为几个类型那?就让佰佰安全网的小编和你一起去了解一下吧!计算机病毒从算法划分为以下几个类型:1、伴随型病毒,这一类病毒并不改变文件本身,它们根据算法产生EXE文件的伴随体,具有同样的名字和不同的扩展名(COM),例如:XCOPY.EXE的伴随体是XCOPY.COM。病毒把自身写入…

  • ViewStub和Gone区别[通俗易懂]

    ViewStub和Gone区别[通俗易懂]虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。   推荐的做法是使用android.view.ViewStub,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Infl

  • java map转object_json对象转map集合

    java map转object_json对象转map集合第一种方法:fastJosnimportcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;Object转MapFindArchiveDtofindArchiveDto=newFindArchiveDto();findArchiveDto.setContractStatus(“降龙”);…

  • ipsec iptables_iptables -p

    ipsec iptables_iptables -piptablesiptables[-t表名]命令选项[链名][条件匹配][-j目标动作或跳转]-t表名可以省略,指定规则存放在哪个表中,默认为filter表用于存放相同功能的规则filter表:负责过滤功能能,nat表:网络地址转换功能mangle表:拆解报文做出修改并重新封装的功能raw表:关闭nat表上启用的连接追踪机制命令选项-A在…

  • SSL证书安装指引

    SSL证书安装指引https://cloud.tencent.com/document/product/400/4143下载得到的www.domain.com.zip文件,解压获得3个文件夹,分别是Apache、

  • 月神带你逻辑漏洞挖掘

    月神带你逻辑漏洞挖掘业务逻辑漏洞挖掘由于程序逻辑不严谨或逻辑太过复杂,导致一些逻辑分支不能正常处理或处理错误,统称为业务逻辑漏洞JSRC安全小课堂第125期,邀请到月神作为讲师就如何通过技术手段挖掘业务逻辑下的漏洞为大家进行分享。同时感谢小伙伴们的精彩讨论。京安小妹:业务逻辑漏洞常见发生位置?月神:要是按细节来说,每一处都可以是发生位置。每种类型的APP都有自己的常见漏洞位置。例如购买,出售,每一条协议的关键参数。京安小妹:业务逻辑漏洞的分类?月神:本文中特定值指的是指当系…

发表回复

您的电子邮箱地址不会被公开。

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