`

转:TCP 三次握手原理,你真的理解吗?

 
阅读更多

最近,阿里中间件小哥哥蛰剑碰到一个问题——client端连接服务器总是抛异常。在反复定位分析、并查阅各种资料文章搞懂后,他发现没有文章把这两个队列以及怎么观察他们的指标说清楚。

因此,蛰剑写下这篇文章,希望借此能把这个问题说清楚。欢迎大家一起交流探讨。

问题描述

场景:JAVA的client和server,使用socket通信。server使用NIO。

1.间歇性得出现client向server建立连接三次握手已经完成,但server的selector没有响应到这连接。

2.出问题的时间点,会同时有很多连接出现这个问题。

3.selector没有销毁重建,一直用的都是一个。

4.程序刚启动的时候必会出现一些,之后会间歇性出现。

分析问题

正常TCP建连接三次握手过程:

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

  • 第一步:client 发送 syn 到server 发起握手;
  • 第二步:server 收到 syn后回复syn+ack给client;
  • 第三步:client 收到syn+ack后,回复server一个ack表示收到了server的syn+ack(此时client的56911端口的连接已经是established)。

从问题的描述来看,有点像TCP建连接的时候全连接队列(accept队列,后面具体讲)满了,尤其是症状2、4. 为了证明是这个原因,马上通过 netstat -s | egrep "listen" 去看队列的溢出统计数据:

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

反复看了几次之后发现这个overflowed 一直在增加,那么可以明确的是server上全连接队列一定溢出了。

接着查看溢出后,OS怎么处理:

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

tcp_abort_on_overflow 为0表示如果三次握手第三步的时候全连接队列满了那么server扔掉client 发过来的ack(在server端认为连接还没建立起来)

为了证明客户端应用代码的异常跟全连接队列满有关系,我先把tcp_abort_on_overflow修改成 1,1表示第三步的时候如果全连接队列满了,server发送一个reset包给client,表示废掉这个握手过程和这个连接(本来在server端这个连接就还没建立起来)。

接着测试,这时在客户端异常中可以看到很多connection reset by peer的错误,到此证明客户端错误是这个原因导致的(逻辑严谨、快速证明问题的关键点所在)。

于是开发同学翻看java 源代码发现socket 默认的backlog(这个值控制全连接队列的大小,后面再详述)是50,于是改大重新跑,经过12个小时以上的压测,这个错误一次都没出现了,同时观察到 overflowed 也不再增加了。

到此问题解决,简单来说TCP三次握手后有个accept队列,进到这个队列才能从Listen变成accept,默认backlog 值是50,很容易就满了。满了之后握手第三步的时候server就忽略了client发过来的ack包(隔一段时间server重发握手第二步的syn+ack包给client),如果这个连接一直排不上队就异常了。

但是不能只是满足问题的解决,而是要去复盘解决过程,中间涉及到了哪些知识点是我所缺失或者理解不到位的;这个问题除了上面的异常信息表现出来之外,还有没有更明确地指征来查看和确认这个问题。

深入理解TCP握手过程中建连接的流程和队列

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

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

三次握手中,在第一步server收到client的syn后,把这个连接信息放到半连接队列中,同时回复syn+ack给client(第二步);

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

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

这时如果全连接队列满了并且tcp_abort_on_overflow是0的话,server过一段时间再次发送syn+ack给client(也就是重新走握手的第二步),如果client超时等待比较短,client就很容易异常了。

在我们的os中retry 第二步的默认次数是2(centos默认是5次):

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

如果TCP连接队列溢出,有哪些指标可以看呢?

上述解决过程有点绕,听起来懵,那么下次再出现类似问题有什么更快更明确的手段来确认这个问题呢?(通过具体的、感性的东西来强化我们对知识点的理解和吸收。)

netstat -s

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

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

ss 命令

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

上面看到的第二列Send-Q 值是50,表示第三列的listen端口上的全连接队列最大为50,第一列Recv-Q为全连接队列当前使用了多少。

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

这个时候可以跟我们的代码建立联系了,比如Java创建ServerSocket的时候会让你传入backlog的值:

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

(来自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 数。

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

netstat -tn 看到的 Recv-Q 跟全连接半连接没有关系,这里特意拿出来说一下是因为容易跟 ss -lnt 的 Recv-Q 搞混淆,顺便建立知识体系,巩固相关知识点 。

比如如下netstat -t 看到的Recv-Q有大量数据堆积,那么一般是CPU处理不过来导致的:

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

上面是通过一些具体的工具、指标来认识全连接队列(工程效率的手段)。

实践验证一下上面的理解

把java中backlog改成10(越小越容易溢出),继续跑压力,这个时候client又开始报异常了,然后在server上通过 ss 命令观察到:

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

按照前面的理解,这个时候我们能看到3306这个端口上的服务全连接队列最大是10,但是现在有11个在队列中和等待进队列的,肯定有一个连接进不去队列要overflow掉,同时也确实能看到overflow的值在不断地增大。

Tomcat和Nginx中的Accept队列参数

Tomcat默认短连接,backlog(Tomcat里面的术语是Accept count)Ali-tomcat默认是200, Apache Tomcat默认100。

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

Nginx默认是511

阿里巴巴技术团队出品:TCP 三次握手原理,你真的理解吗?

 

因为Nginx是多进程模式,所以看到了多个8085,也就是多个进程都监听同一个端口以尽量避免上下文切换来提升性能

总结

全连接队列、半连接队列溢出这种问题很容易被忽视,但是又很关键,特别是对于一些短连接应用(比如Nginx、PHP,当然他们也是支持长连接的)更容易爆发。 一旦溢出,从cpu、线程状态看起来都比较正常,但是压力上不去,在client看来rt也比较高(rt=网络+排队+真正服务时间),但是从server日志记录的真正服务时间来看rt又很短。

jdk、netty等一些框架默认backlog比较小,可能有些情况下导致性能上不去。

希望通过本文能够帮大家理解TCP连接过程中的半连接队列和全连接队列的概念、原理和作用,更关键的是有哪些指标可以明确看到这些问题(工程效率帮助强化对理论的理解)。

另外每个具体问题都是最好学习的机会,光看书理解肯定是不够深刻的,请珍惜每个具体问题,碰到后能够把来龙去脉弄清楚,每个问题都是你对具体知识点通关的好机会。

最后提出相关问题给大家思考

  1. 全连接队列满了会影响半连接队列吗?
  2. netstat -s看到的overflowed和ignored的数值有什么联系吗?
  3. 如果client走完了TCP握手的第三步,在client看来连接已经建立好了,但是server上的对应连接实际没有准备好,这个时候如果client发数据给server,server会怎么处理呢?(有同学说会reset,你觉得呢?)
分享到:
评论

相关推荐

    Wireshark入门 tcp三次握手

    通过使用Wireshark观察TCP三次握手的过程,我们可以更直观地了解TCP连接建立的基本原理及其背后的细节。这对于深入理解TCP/IP协议栈的工作机制,以及在网络故障排查时快速定位问题具有重要意义。 此外,Wireshark还...

    wireshark抓包分析tcp三次握手四次挥手

    在TCP/IP通信中,TCP连接的建立和关闭过程分别称为三次握手和四次挥手,这两个过程对于理解TCP连接的工作原理至关重要。 首先,我们来详细讲解TCP的三次握手过程: 1. **第一次握手**:客户端(Client)发送一个...

    TCP协议三次握手过程分析

    #### 二、三次握手原理及过程 三次握手机制是TCP建立连接的过程,其目的是为了确保通信双方都准备好接收数据。整个过程分为三个步骤: 1. **第一次握手**:客户端(主机A)向服务器(主机B)发送一个SYN...

    wireshark抓包分析tcp三次握手四次挥手详解及网络命令

    通过对Wireshark抓包分析TCP三次握手四次挥手的详细了解,我们可以更深入地理解TCP/IP协议的工作原理,这对于网络故障排查、性能优化等方面都有着重要的意义。此外,掌握Wireshark这样的工具也是提高网络技能不可或...

    TCP三次握手及原理

    #### 二、TCP三次握手原理 TCP三次握手是指建立一个TCP连接时,需要客户端和服务端总共发送三个包以确认连接的建立。这三个步骤是: 1. **第一次握手**:客户端发送连接请求报文段(SYN报文),此时客户端处于`SYN...

    TCP三次握手和四次挥手面试题详解.pdf

    TCP三次握手和四次挥手是互联网中最重要的基础知识点之一,尤其在面试中,它们是检验应聘者是否具备扎实网络基础知识的常用问题。面试官通常会考察应聘者对这些过程的理解程度,以及能否准确描述其细节。以下是关于...

    TCP协议书籍(三次握手原理)

    **三次握手** 是TCP连接建立过程中不可或缺的步骤,它确保了两个主机之间可以正确建立连接。具体过程如下: 1. **SYN(同步序列编号)**:客户端首先发送一个带有SYN标志的数据段,其中包含一个随机生成的序列号A。...

    wireshark tcp三次握手

    标题中的“wireshark tcp三次握手”指的是使用Wireshark这一网络封包分析软件来观察和理解TCP(传输控制协议)的三次握手过程。在TCP/IP通信协议中,三次握手是一种建立连接的方法,确保双方都能正常通信。在这个...

    案例测试TCP的三次握手和四次挥手过程

    可以通过编写C语言的服务器端程序和C#的客户端程序来模拟TCP的连接和断开过程,同时使用Wireshark这样的网络抓包工具,可以直观地观察到三次握手和四次挥手的网络交互细节,这对于理解TCP协议的工作原理非常有帮助。...

    TCP三次握手四次挥手

    ### TCP三次握手与四次挥手详解 #### 一、TCP协议简介 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在计算机网络中,TCP用于在应用程序之间提供...

    Python网络编程之TCP三次握手

    1. 基本要求:理解三次握手、四次挥手过程及序号变化。 2. 设计语言:Python、C/C++。 3. 原理:利用 TCP 报文中的 SYN、SYN+ACK、ACK 报文与服务器某程序(例如端口 80、端口 23)建立 TCP 连接,然后向服务器发送...

    TCP/IP的三次握手建立连接(带图释)

    在TCP/IP的连接建立过程中,三次握手是至关重要的步骤。这一过程确保了双方都能正确接收和理解彼此的连接请求,从而建立起可靠的通信链路。下面详细解析三次握手的过程: 1. **第一次握手**:客户端(如图中的...

    四、TCP 三次握手1

    理解TCP的三次握手对于网络编程和系统管理员来说至关重要,它有助于排查网络连接问题,优化系统性能,以及理解网络通信的底层原理。在面试中,这是经常会被问到的基础知识,也是网络协议分析和故障诊断的基础。

    tcp_connect.rar_connect_linux tcp_connect_tcp_tcp 三次握手_三次握手

    通过阅读和理解“tcp_connect.c”代码,你可以了解到如何在实际应用中实现TCP的三次握手过程,这对于网络编程和系统级开发的初学者来说是非常有价值的实践。 总的来说,这个资源为学习TCP连接和Linux网络编程提供了...

    TCP IP 三次握手及状态变迁图

    标题:“TCP IP 三次握手及状态变迁图” 描述:“介绍TCP IP连接时的三次握手和断开时的四次挥手...以上解析了TCP/IP三次握手和四次挥手的原理,以及关键的套接字函数和注意事项,为理解TCP/IP协议提供了深入的视角。

    tcp三次握手四次挥手

    ### TCP三次握手与四次挥手详解 #### 一、TCP协议概述 TCP(Transmission Control Protocol,传输控制协议)是互联网中最关键...通过这些示例代码,我们可以更直观地理解TCP三次握手与四次挥手的工作原理及其重要性。

    传输协议TCP三次握手

    TCP三次握手是TCP连接建立过程中不可或缺的步骤,确保了双方都能正确理解彼此的连接请求,避免了网络中的失效连接请求和数据包乱序等问题。 在TCP三次握手过程中,主要有以下三个阶段: 1. 第一次握手:客户端发送...

    三次握手协议的原理及实现

    【三次握手协议的原理及实现】 TCP/IP协议是互联网通信的基础,其中TCP(Transmission Control Protocol)传输控制协议是其核心部分,提供了可靠的、面向连接的数据传输服务。TCP通过三次握手来建立连接,确保数据...

    网络协议,TCP三次握手,四次挥手

    这个过程被称为“三次握手”。第一次握手,客户端发送一个SYN同步包给服务器;第二次握手,服务器回应一个SYN+ACK包,同时自己也发送一个SYN包;第三次握手,客户端再发送一个ACK包,确认服务器的SYN。这样就建立了...

Global site tag (gtag.js) - Google Analytics