先上一张图

(图片来源:http://www.cnxct.com/something-about-phpfpm-s-backlog/)

如上图所示,这里有两个队列:syns queue(半连接队列);accept queue(全连接队列)

TCP三次握手中:

第一步,server收到client的syn后,server把这个连接信息放到半连接队列中,;

第二步,server回复syn+ack给client;

第三步,server收到client的ack,这时如果全连接队列没满,server就从半连接队列拿出这个连接的信息放入到全连接队列中,否则按net.ipv4.tcp_abort_on_overflow指示的执行。

这时如果全连接队列满了并且net.ipv4.tcp_abort_on_overflow是0的话,server过一段时间再次发送syn+ack给client,重试的次数由net.ipv4.tcp_synack_retries决定。

几个内核参数

  • net.ipv4.tcp_abort_on_overflow

    为0,表示TCP握手第三步的时候如果全连接队列满了那么server扔掉client 发过来的ack,在server端认为连接还没建立起来,server过一段时间再次发送syn+ack给client(也就是重新走握手的第二步),如果client超时等待比较短,client就很容易异常了;

    为1,表示第三步的时候如果全连接队列满了,server发送一个reset包给client,表示废掉这个握手过程和这个连接,这时在客户端异常中一般会看到connection reset by peer的错误

  • net.ipv4.tcp_synack_retries

    TCP三次握手后有个accept全连接队列,进到这个队列才能从Listen变成accept,这个队列满的话,server端如果要重发syn+ack给client,net.ipv4.tcp_synack_retries表示重试次数

  • net.ipv4.tcp_max_syn_backlog

    端口最大 backlog 内核限制,是指定所能接受SYN同步包的最大客户端数量,即半连接上限(sync queue大小),centos默认128。

    动机是在内存有限的服务器上限制/避免应用程序配置超大 backlog 值而耗尽内核内存。如果应用程序设置 backlog 大于此值,操作系统将自动将之限制到此值。

  • net.ipv4.somaxconn

    是指服务端所能accept即处理数据的最大客户端数量,即完成连接上限(accept queue大小),centos默认128

  • tcp_syncookies

    在 tcp 建立连接的 3 路握手过程中,当服务端收到最初的 SYN 请求时,会检查应用程序的 syn_backlog 队列是否已满。若已满,通常行为是丢弃此 SYN 包。若未满,会再检查应用程序的 backlog 队列是否已满。若已满并且系统根据历史记录判断该应用程序不会较快消耗连接时,则丢弃此 SYN 包。如果启用 tcp_syncookies 则在检查到 syn_backlog 队列已满时,不丢弃该 SYN 包,而改用 syncookie 技术进行 3 路握手。

    警告:使用 syncookie 进行握手时,因为该技术挪用了 tcp_options 字段空间,会强制关闭 tcp 高级流控技术而退化成原始 tcp 模式。此模式会导致 封包 丢失时 对端 要等待 MSL 时间来发现丢包事件并重试,以及关闭连接时 TIME_WAIT 状态保持 2MSL 时间。该技术应该仅用于保护 syn_flood 攻击。如果在正常服务器环境中服务器负载较重导致 syn_backlog 和 backlog 队列满时,应优化 服务端应用程序 的 负载能力,加大应用程序 backlog 值。不过,所幸该参数是自动值,仅在 syn_backlog 队列满时才会触发 (在队列恢复可用时此行为关闭)。

    NOTE 1:

    服务端应用程序设置端口 backlog 值,内核理论上将允许该端口最大同时接收 2*backlog 个并发连接”请求”(不含已被应用程序接管的连接) —— 分别存放在 syn_backlog 和 backlog 队列 —— 每个队列的长度为 backlog 值。syn_backlog 队列存储 SYN_ACK 状态的连接,backlog 则存储 ESTABLISHED 状态但尚未被应用程序接管的连接。

    NOTE 2:

    syn_backlog 队列实际上是个 hash 表,并且 hash 表大小为 2 的次方。所以实际 syn_backlog 的队列长度要 略大于 应用程序设置的 backlog 值 —— 取对应 2 的次方值。

    NOTE 3:

    当 backlog 值较小,而高峰期并发连接请求超高时,tcp 建立连接的 三路握手 网络时延将成为瓶颈 —— 并发连接超高时,syn_backlog 队列将被充满而导致 can’t connect 错误。此时,再提高服务端应用程序的吞吐能力已不起作用,因为连接尚未建立,服务端应用程序并不能接管和处理这些连接 —— 而是需要加大 backlog 值 (syn_backlog 队列长度) 来缓解此问题。

    NOTE 4:

    启用 syncookie 虽然也可以解决超高并发时的 can’t connect 问题,但会导致 TIME_WAIT 状态 fallback 为保持 2MSL 时间,高峰期时会导致客户端无可复用连接而无法连接服务器 (tcp 连接复用是基于 <src_ip, src_port, dst_ip, dst_port> 四元组值必须不相同,就访问同一个目标服务器而言,<src_ip, dst_ip, dst_port> 三元组值不变,所以此时可用的连接数限制为仅 src_port 所允许数目,这里处于 TIME_WAIT 状态的相同 src_port 连接不可复用。Linux 系统甚至更严格,只使用了 <src_ip, src_port, dst_ip> 三元组…)。故不建议依赖 syncookie。

如何判断TCP连接队列溢出

  • netstat -s
[root@ ~]# netstat  -s | grep -i 'listen'
180239 times the listen queue of a socket overflowed
180239 SYNs to LISTEN sockets ignored

180239 times ,表示全连接队列溢出的次数,隔几秒钟执行下,如果这个数字一直在增加的话肯定全连接队列偶尔满了。

如何查看TCP连接队大小

  • ss
[root@pt_zabbix_121.14.58.91 ~]# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 *:1701 *:*
LISTEN 0 128 127.0.0.1:9000 *:*

Send-Q:表示Local Address:Port 所监听的socket的全连接队列最大值

Recv-Q:表示该全连接队列当前使用了多少

全连接队列的大小取决于:min(backlog, net.ipv4.somaxconn), backlog是在socket创建的时候传入的,net.ipv4.somaxconn是一个os级别的系统参数。

用Python写个socket监听在8088端口:

>>> import socket
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sock.bind(('localhost',8088))
>>> sock.listen(5)

观察一下:

[root@ ~]# ss -lnt | grep 8088
LISTEN 0 5 127.0.0.1:8088 *:* 9319/python
[root@ ~]# sysctl -a | grep somaxconn
net.core.somaxconn = 262144

因此可以发现,somaxconn全局决定了全连接队列的大小,而程序的实际大小由 backlog决定。

参考

https://blog.csdn.net/alitech2017/article/details/80922902

http://www.cnxct.com/something-about-phpfpm-s-backlog/

https://blog.csdn.net/raintungli/article/details/37913765

TCP三次握手过程中涉及的队列知识的学习的更多相关文章

  1. Java网络编程学习A轮_02_抓包分析TCP三次握手过程

    参考资料: https://huoding.com/2013/11/21/299 https://hpbn.co/building-blocks-of-tcp/#three-way-handshake ...

  2. tcp三次握手过程

    TCP握手协议 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接.第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确 ...

  3. TCP 三次握手过程详解

    TCP(Transmission Control Protocol) 传输控制协议 TCP:面向连接的,可靠的,基于字节流的传输层通信协议 TCP(传输层)位于IP层(网络层)之上,应用层之下,不同的 ...

  4. 三报文握手而不是三次握手 wireshark 封包详细信息 (Packet Details Pane) wireshark与对应的OSI七层模型 TCP包的具体内容 分析TCP三次握手过程

    总结: 1.tcp报文非数据部分4*6字节 2.RFC 973 <计算机网络> 谢希仁 three way (three message) handshake 只是一次握手 同步位SYN. ...

  5. 【转】TCP三次握手过程

    写的非常明白:http://www.cnblogs.com/rootq/articles/1377355.html TCP协议三次握手过程分析 TCP(Transmission Control Pro ...

  6. connect & send 在三次握手过程中的有趣问题

    一.问题回顾 面试的时候被问到的问题,原问题是: 1:写一下socket网络编程服务端和客户端常用的函数. 2:如果服务端在listen之后没有accept,那客户端的connect会返回吗?为什么? ...

  7. TCP三次握手过程和四次释放

    TCP是面向连接的协议 客户端发送 SYN包,和随机数SEQ.此时客户端是SYN_SENT状态. 服务器返回SYN+ACK,和随机数SEQ, rwnd是告诉客户端我可以接收多少字节.此时服务器端是SY ...

  8. 从TCP三次握手说起--浅析TCP协议中的疑难杂症(1)

    版权声明:本文由黄日成原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/73 来源:腾云阁 https://www.qclou ...

  9. TCP三次握手和连接关闭过程详解

    1.建立连接协议(三次握手) (1)客户端发送一个带SYN标志的TCP报文到服务器.这是三次握手过程中的报文1. (2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和S ...

随机推荐

  1. 123457123457#1#-----com.threeapp.circlerunner01----儿童旋转跑酷游戏

    com.threeapp.circlerunner01----儿童旋转跑酷游戏

  2. Python检查数组元素是否存在类似PHPisset()方法

    Python检查数组元素是否存在类似PHP isset()方法 sset方法来检查数组元素是否存在,在Python中无对应函数,在Python中一般可以通过异常来处理数组元素不存在的情况,而无须事先检 ...

  3. LeetCode_141. Linked List Cycle

    141. Linked List Cycle Easy Given a linked list, determine if it has a cycle in it. To represent a c ...

  4. Core Data 的使用

    一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在Mac OS X 10.5Leopard及以 ...

  5. 比较SSO协议: WS-Fed, SAML, and OAuth

    真实比喻 在我们获得技术之前,让我们用完全非技术性的东西来解决这个问题.作为工程师,我们非常注重将事情分解为组件和流程.这有助于我们了解事情,以便我们可以排除故障或构建复杂的系统.当你去机场登机时,你 ...

  6. 使用ASP.NET Core支持GraphQL( restful 配套)

    https://github.com/graphql-dotnet https://github.com/graphql GraphQL简介 官网:https://graphql.cn/code/ 下 ...

  7. 添加zookeeper到服务,并设置开机启动

    一.先安装jdk jdk 路径为/usr/local/java 二.再安装zookeeper zk路径为/use/local/zookeeper 三.创建zookeeper脚本 cd /etc/rc. ...

  8. PHP实现无限极分类的两种方式,递归和引用

    面试的时候被问到无限极分类的设计和实现,比较常见的做法是在建表的时候,增加一个PID字段用来区别自己所属的分类 $array = array( array('id' => 1, 'pid' =& ...

  9. JS获取URL参数中文乱码解决

    var param = window.location.search; var paramArray = parseParams(param); var selectV = decodeURI(par ...

  10. 机器学习_第三季_Series

    这一节没讲啥技术知识, 我就简单的罗列一下, 与numpy相似 1. 导入csv文件 import pandas as pdfandango = pd.read_csv("fandango_ ...