做特色菜的网站,网站建设行业增长率,怎么做网站8uftp,老薛主机多个域名WordPress转载自 TCP 三次握手原理#xff0c;你真的理解吗
最近#xff0c;阿里中间件小哥哥蛰剑碰到一个问题——client端连接服务器总是抛异常。在反复定位分析、并查阅各种资料文章搞懂后#xff0c;他发现没有文章把这两个队列以及怎么观察他们的指标说清楚。
因此#xff0…转载自 TCP 三次握手原理你真的理解吗
最近阿里中间件小哥哥蛰剑碰到一个问题——client端连接服务器总是抛异常。在反复定位分析、并查阅各种资料文章搞懂后他发现没有文章把这两个队列以及怎么观察他们的指标说清楚。
因此蛰剑写下这篇文章希望借此能把这个问题说清楚。欢迎大家一起交流探讨。
问题描述 场景JAVA的client和server使用socket通信。server使用NIO。 1.间歇性得出现client向server建立连接三次握手已经完成但server的selector没有响应到这连接。 2.出问题的时间点会同时有很多连接出现这个问题。 3.selector没有销毁重建一直用的都是一个。 4.程序刚启动的时候必会出现一些之后会间歇性出现。 分析问题
正常TCP建连接三次握手过程 第一步client 发送 syn 到server 发起握手 第二步server 收到 syn后回复synack给client 第三步client 收到synack后回复server一个ack表示收到了server的synack此时client的56911端口的连接已经是established。
从问题的描述来看有点像TCP建连接的时候全连接队列accept队列后面具体讲满了尤其是症状2、4. 为了证明是这个原因马上通过 netstat -s | egrep listen 去看队列的溢出统计数据 反复看了几次之后发现这个overflowed 一直在增加那么可以明确的是server上全连接队列一定溢出了。
接着查看溢出后OS怎么处理 tcp_abort_on_overflow 为0表示如果三次握手第三步的时候全连接队列满了那么server扔掉client 发过来的ack在server端认为连接还没建立起来
为了证明客户端应用代码的异常跟全连接队列满有关系我先把tcp_abort_on_overflow修改成 11表示第三步的时候如果全连接队列满了server发送一个reset包给client表示废掉这个握手过程和这个连接本来在server端这个连接就还没建立起来。
接着测试这时在客户端异常中可以看到很多connection reset by peer的错误到此证明客户端错误是这个原因导致的逻辑严谨、快速证明问题的关键点所在。
于是开发同学翻看java 源代码发现socket 默认的backlog这个值控制全连接队列的大小后面再详述是50于是改大重新跑经过12个小时以上的压测这个错误一次都没出现了同时观察到 overflowed 也不再增加了。
到此问题解决简单来说TCP三次握手后有个accept队列进到这个队列才能从Listen变成accept默认backlog 值是50很容易就满了。满了之后握手第三步的时候server就忽略了client发过来的ack包隔一段时间server重发握手第二步的synack包给client如果这个连接一直排不上队就异常了。 但是不能只是满足问题的解决而是要去复盘解决过程中间涉及到了哪些知识点是我所缺失或者理解不到位的这个问题除了上面的异常信息表现出来之外还有没有更明确地指征来查看和确认这个问题。 深入理解TCP握手过程中建连接的流程和队列 图片来源http://www.cnxct.com/something-about-phpfpm-s-backlog/
如上图所示这里有两个队列syns queue(半连接队列accept queue全连接队列。
三次握手中在第一步server收到client的syn后把这个连接信息放到半连接队列中同时回复synack给client第二步 第三步的时候server收到client的ack如果这时全连接队列没满那么从半连接队列拿出这个连接的信息放入到全连接队列中否则按tcp_abort_on_overflow指示的执行。
这时如果全连接队列满了并且tcp_abort_on_overflow是0的话server过一段时间再次发送synack给client也就是重新走握手的第二步如果client超时等待比较短client就很容易异常了。
在我们的os中retry 第二步的默认次数是2centos默认是5次 如果TCP连接队列溢出有哪些指标可以看呢
上述解决过程有点绕听起来懵那么下次再出现类似问题有什么更快更明确的手段来确认这个问题呢通过具体的、感性的东西来强化我们对知识点的理解和吸收。 netstat -s 比如上面看到的 667399 times 表示全连接队列溢出的次数隔几秒钟执行下如果这个数字一直在增加的话肯定全连接队列偶尔满了。 ss 命令 上面看到的第二列Send-Q 值是50表示第三列的listen端口上的全连接队列最大为50第一列Recv-Q为全连接队列当前使用了多少。
全连接队列的大小取决于min(backlog, somaxconn) . backlog是在socket创建的时候传入的somaxconn是一个os级别的系统参数。
这个时候可以跟我们的代码建立联系了比如Java创建ServerSocket的时候会让你传入backlog的值 来自JDK帮助文档https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html
半连接队列的大小取决于max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)不同版本的os会有些差异。 我们写代码的时候从来没有想过这个backlog或者说大多时候就没给他值那么默认就是50直接忽视了他首先这是一个知识点的盲点其次也许哪天你在哪篇文章中看到了这个参数当时有点印象但是过一阵子就忘了这是知识之间没有建立连接不是体系化的。但是如果你跟我一样首先经历了这个问题的痛苦然后在压力和痛苦的驱动自己去找为什么同时能够把为什么从代码层推理理解到OS层那么这个知识点你才算是比较好地掌握了也会成为你的知识体系在TCP或者性能方面成长自我生长的一个有力抓手。 netstat 命令
netstat跟ss命令一样也能看到Send-Q、Recv-Q这些状态信息不过如果这个连接不是Listen状态的话Recv-Q就是指收到的数据还在缓存中还没被进程读取这个值就是还没被进程读取的 bytes而 Send 则是发送队列中没有被远程主机确认的 bytes 数。 netstat -tn 看到的 Recv-Q 跟全连接半连接没有关系这里特意拿出来说一下是因为容易跟 ss -lnt 的 Recv-Q 搞混淆顺便建立知识体系巩固相关知识点 。
比如如下netstat -t 看到的Recv-Q有大量数据堆积那么一般是CPU处理不过来导致的 上面是通过一些具体的工具、指标来认识全连接队列工程效率的手段。 实践验证一下上面的理解
把java中backlog改成10越小越容易溢出继续跑压力这个时候client又开始报异常了然后在server上通过 ss 命令观察到 按照前面的理解这个时候我们能看到3306这个端口上的服务全连接队列最大是10但是现在有11个在队列中和等待进队列的肯定有一个连接进不去队列要overflow掉同时也确实能看到overflow的值在不断地增大。 Tomcat和Nginx中的Accept队列参数
Tomcat默认短连接backlogTomcat里面的术语是Accept countAli-tomcat默认是200, Apache Tomcat默认100。 Nginx默认是511 因为Nginx是多进程模式所以看到了多个8085也就是多个进程都监听同一个端口以尽量避免上下文切换来提升性能 总结
全连接队列、半连接队列溢出这种问题很容易被忽视但是又很关键特别是对于一些短连接应用比如Nginx、PHP当然他们也是支持长连接的更容易爆发。 一旦溢出从cpu、线程状态看起来都比较正常但是压力上不去在client看来rt也比较高rt网络排队真正服务时间但是从server日志记录的真正服务时间来看rt又很短。
jdk、netty等一些框架默认backlog比较小可能有些情况下导致性能上不去。
希望通过本文能够帮大家理解TCP连接过程中的半连接队列和全连接队列的概念、原理和作用更关键的是有哪些指标可以明确看到这些问题工程效率帮助强化对理论的理解。
另外每个具体问题都是最好学习的机会光看书理解肯定是不够深刻的请珍惜每个具体问题碰到后能够把来龙去脉弄清楚每个问题都是你对具体知识点通关的好机会。 最后提出相关问题给大家思考 全连接队列满了会影响半连接队列吗 netstat -s看到的overflowed和ignored的数值有什么联系吗 如果client走完了TCP握手的第三步在client看来连接已经建立好了但是server上的对应连接实际没有准备好这个时候如果client发数据给serverserver会怎么处理呢有同学说会reset你觉得呢 提出这些问题希望以这个知识点为抓手让你的知识体系开始自我生长。
参考文章
http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html
http://www.cnblogs.com/zengkefu/p/5606696.html
http://www.cnxct.com/something-about-phpfpm-s-backlog/
http://jaseywang.me/2014/07/20/tcp-queue-%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/
http://jin-yang.github.io/blog/network-synack-queue.html#
http://blog.chinaunix.net/uid-20662820-id-4154399.html