爱生活,爱编码,微信搜一搜【架构技术专栏】关注这个喜欢分享的地方。

本文 架构技术专栏 已收录,有各种视频、资料以及技术文章。

一、问题

今天有个小伙伴跑过来告诉我有个奇怪的问题需要协助下,问题确实也很奇怪。客户端调用RT比较高并伴随着间歇性异常Connection reset出现,而服务端CPU 、线程栈等看起来貌似都很正常,而且服务端的RT很短。

这里先说下结果:

因为TCP全连接队列太小导致的连接被丢弃,因为项目使用Spring Boot 内置的Tomcat,而默认accept-count是100,而这个参数在这里就代表了全连接队列大小。所以在请求波峰的时候全连接队列被打满导致有连接丢弃。所以我们调整server.tomcat.accept-count这个参数解决了问题。

二、半连接队列和全连接队列

好了为了知其然知其所以然,从异常信息来看可能是TCP连接出现了什么问题,其中重点就是半连接队列和全连接队列。下面就来看看什么是TCP 半连接队列和全连接队列,其为什么会出现这种奇怪的现象。

1、TCP 三次握手流程和队列

TCP三次握手时,Linux内核会维护两个队列:

  • 半连接队列,被称为SYN队列
  • 全连接队列,被称为 accept队列

老生常谈,还要从大家都熟悉TCP三次握手说起,来看一张图:

1、客户端发送SYN包,并进入SYN_SENT状态

2、服务端接收到数据包将相关信息放入半连接队列(SYN 队列),并返回SYC+ACK包给客户端。

3、服务端接收客户端ACK数据包,这时如果全连接队列(accept 队列)没满,就会从半连接队列里面将数据取出来放入全连接队列,等待应用使用,当队列已满就会跟据tcp_abort_on_overflow配置执行策略。

这里半连接队列(SYN 队列)和全连接队列(accept 队列)就是重点了。

2、全连接队列查看

当查询问题的时候,我们就需要查看全连接队列的状态。服务端我们可以使用 ss 命令进行查看,ss 命令获取数据又分为LISTEN 状态,和非LISTEN 状态。

LISTEN 状态下数据:

# -l 显示正在Listener 的socket
# -n 不解析服务名称
# -t 只显示tcp # Recv-Q 完成三次握手并等待服务端 accept() 的 TCP 全连接总数,
# Send-Q 全连接队列大小 [root@server ~]# ss -lnt |grep 6080
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 :::6080 :::*

非LISTEN 状态下数据:

# Recv-Q 已收到但未被应用进程读取的字节数
# Send-Q 已发送但未收到确认的字节数 [root@server ~]# ss -nt |grep 6080
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 433 :::6080 :::*

3、全连接队列溢出

当有大量请求进入,如果TCP全连接队列过小的话就会出现全连接队列溢出,当出现全连接队列溢出现象的时候,后续的请求就会被丢弃,就会出现服务请求数量上不去的现象。

前面提到在TCP三次握手的最后一步,当全连接队列已满就会根据tcp_abort_on_overflow策略进行处理。Linux 可通过 /proc/sys/net/ipv4/tcp_abort_on_overflow 进行配置。

  • 当tcp_abort_on_overflow=0,服务accept 队列满了,客户端发来ack,服务端直接丢弃该ACK,此时服务端处于【syn_rcvd】的状态,客户端处于【established】的状态。在该状态下会有一个定时器重传服务端 SYN/ACK 给客户端(不超过 /proc/sys/net/ipv4/tcp_synack_retries 指定的次数,Linux下默认5)。超过后,服务器不在重传,后续也不会有任何动作。如果此时客户端发送数据过来,服务端会返回RST。(这也就是我们的异常原因了)

  • 当tcp_abort_on_overflow=1,服务端accept队列满了,客户端发来ack,服务端直接返回RST通知client,表示废掉这个握手过程和这个连接,client会报connection reset by peer。

1). 当全连接队列溢出时,有哪些指标可以说明呢,我们又有哪些有效的查询手段呢?

命令查询,我们可以根据TCP 的握手特性来看:

[root@server ~] netstat -s | egrep "listen|LISTEN"
7102 times the listen queue of a socket overflowed 全连接队列溢出的次数
7102 SYNs to LISTEN sockets ignored 表示半连接队列溢出次数 710 2times表示全连接队列溢出的次数,隔几秒查询一次,如果这个数字一直在递增,说明全连接队列出现了溢出的状态
2). 配置全连接队列和半连接队列?

全连接队列大小取决于backlog 和somaxconn 的最小值,也就是 min(backlog,somaxconn)

  • somaxconn 是Linux内核参数,默认128,可通过/proc/sys/net/core/somaxconn进行配置
  • backlog是 listen(int sockfd,int backlog)函数中的参数backlog,Tomcat 默认100,Nginx 默认511.

半连接队列的长度可以通过 /proc/sys/net/ipv4/tcp_max_syn_backlog来设置.os层面,只能设一个,由所有程序共享)

3). 查看半连接状态

半连接,也就是服务端处于SYN_RECV状态的TCP连接,这种状态的都在半连接队列,因此可以使用如下命令进行计算:

#查看半连接队列
[root@server ~] netstat -natp | grep SYN_RECV | wc -l
233 #表示半连接状态的TCP连接有233个

三、总结

通过以上的知识点可以定位到这次事件的原因了,因为Spring Boot tomcat 默认的配置导致应用在启动时全连接队列只有默认的100,在流量激增的情况下导致全连接队列打满出现了第三次握手数据包被丢弃的现象。

所以总结下:

  • 1、TCP三次握手时,Linux维护了全连接和半连接两个队列
  • 2、在全连接队列满的时候丢弃策略根据tcp_abort_on_overflow的配置执行
  • 3、全连接队列大小会取Linux系统配置和应用配置中的最小值
  • 4、Linux 中的backlog 就是我们所说的全连接队列大小
  • 5、应用部署时记得检查全连接队列是否正确配置

backlog配置

  • Tomcat AbstractEndpoint默认参数是100,如果使用独立Tomcat配置了 server.xml,其实 connector 中 acceptCount 最终是 backlog的值。而使用Spring Boot内置Tomcat记得配置server.tomcat.accept-count参数,否则默认值就是
  • Nginx 配置 server{ listen 8080 default_server backlog=512}
  • Redis 配置redis.conf文件 tcp-backlog 511参数

爱生活,爱编码,微信搜一搜【架构技术专栏】关注这个喜欢分享的地方。

本文 架构技术专栏 已收录,有各种视频、资料以及技术文章。

五分钟带你读懂 TCP全连接队列(图文并茂)的更多相关文章

  1. 五分钟带你读懂 堆 —— heap(内含JavaScript代码实现!!)

    一.概念  说起堆,我们就想起了土堆,把土堆起来,当我们要用土的时候,首先用到最上面的土.类似地,堆其实是一种优先队列,按照某种优先级将数字"堆"起来,每次取得时候从堆顶取.  堆 ...

  2. 少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

    1.引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO? 在本 ...

  3. 性能分析之TCP全连接队列占满问题分析及优化过程(转载)

    前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的. 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时候, ...

  4. [TimLinux] TCP全连接队列满

    0. TCP三次握手 该图来自:TCP SOCKET中backlog参数的用途是什么? syns queue: 半连接队列 accept queue: 全连接队列 控制参数存放在文件:/proc/sy ...

  5. TCP全连接队列和半连接队列已满之后的连接建立过程抓包分析[转]

    最近项目需要做单机100万长连接与高并发的服务器,我们开发完服务器以后,通过自己搭的高速压测框架压测服务端的时候,发生了奇怪的现象,就是服务端莫名其妙的少接收了连接,造成了数据包的丢失,通过网上查资料 ...

  6. 五分钟让你读懂UML常见类图

    相信各位同学在阅读一些源码分析类文章或是设计应用架构时没少与UML类图打交道.实际上,UML类图中最常用到的元素五分钟就能掌握,经常看到UML类图但还不太熟悉的小伙伴赶紧来一起认识一下它吧:)   一 ...

  7. 黑马程序员:3分钟带你读懂C/C++学习路线

    随着互联网及互联网+深入蓬勃的发展,经过40余年的时间洗礼,C/C++俨然已成为一门贵族语言,出色的性能使之成为高级语言中的性能王者.而在今天,它又扮演着什么样重要的角色呢?请往下看: 后端服务器,移 ...

  8. 一篇带你读懂TCP之“滑动窗口”协议

    前言 你现在的努力,是为了以后有更多的选择. 在上一篇文章通过"表白"方式,让我们快速了解网络七层协议了解了网络七层协议. 接下来我们要把重心放在网络传输的可靠性上面.一起来看TC ...

  9. Python——五分钟带你弄懂迭代器与生成器,夯实代码能力

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是周一Python专题,给大家带来的是Python当中生成器和迭代器的使用. 我当初第一次学到迭代器和生成器的时候,并没有太在意,只是觉 ...

随机推荐

  1. java如何将char类型的数字转换成int型的数字,而不是Ascii

    如何把 char ‘3’ 转为 int 3, 大家应该知道,不能直接转化,那样得到是‘3’的Ascii. 如下面: public class Leet { public static void mai ...

  2. linux驱动之内核多线程(一)

    本文摘自http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545624.html Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进 ...

  3. Linux 资源监控与性能测试

    综合管理 glances 系统情况监控 vmstat 能看到上下文切换,runnable进程个数,uninterrupted进程个数 磁盘IO iostat是磁盘级别监控,iotop进程级别监控,注意 ...

  4. JVM关键字try、catch、finally、return执行过程

    关键字:jvm try catch finally return.指令 finally相当于在所有方法返回之前执行一次 finally中含有return其中finally中return会覆盖try和c ...

  5. 利用 Python 写个七夕表白神器

    今天是七夕节,相比于现代人自创的 502,不对是 520,七夕才是中国传统意义上的情人节,本文分享几个 Python 表白程序,情侣可以现学现用,单身的话也可以先收藏一下,说不定下次就用上了. 很多人 ...

  6. Unity - NGUI - 优化ScrollView的一些心的

    ScrollView是NGUI非常好用的一个内置组件,但是效率不好,当子物体过多的时候,一旦开始拖动就帧数狂掉,我目前有3个解决思路: 1. NGUI自带的Example 8 - Scroll Vie ...

  7. App性能测试前需要了解的内存原理

    这两天在研究性能中内存方面的一块,网上也零散看了挺多文章,写得很细但是感觉不够整体,所以这篇算是总结一下吧,当个复习资料. 那么这里个人分为两个大部分,第一部分应用内的内存管理,主要是oom的理解,G ...

  8. [BUUOJ记录] [GXYCTF2019]BabyUpload

    CTF三大骗局:Baby Easy Funny,本题主要考察.htaccess文件解析文件.文件类型检测绕过 打开题目给了一个上传点,上传一个php文件看看过滤规则 “后缀名不能有ph”直接禁掉了所有 ...

  9. uniapp 获取元素高度 距离顶部高度等

    let _this=this let height="" const query = uni.createSelectorQuery() query.select('#u-drop ...

  10. 【原创】经验分享:一个Content-Length引发的血案(almost....)

    前言 上周在工作中遇到一个问题,挺有意思,这里记录一下.上周在工作中遇到一个问题,挺有意思,这里记录一下.标题起的很唬人,这个问题差点引发血案,花哥还是很严谨的一个人,后面备注了almost.... ...