TCP性能调优实现原理及过程解析

三次握手阶段

客户端SYN包的重试次数

sysctl -w net.ipv4.tcp_syn_retries=6

相关介绍

第 1 次重试发生在 1 秒钟后,接着会以翻倍的方式在第 2、4、8、16、32 秒共做 6 次重试,最后一次重试会等待 64 秒,如果仍然没有返回 ACK,才会终止三次握手。所以,总耗时是 1+2+4+8+16+32+64=127 秒,超过 2 分钟。

服务端半连接池大小

sysctl -w net.ipv4.tcp_max_syn_backlog=16384

服务端半连接池满了以后是否开启syncookie机制

sysctl -w net.ipv4.tcp_syncookies=1

相关介绍

如果 SYN 半连接队列已满,默认会丢弃连接并不是这样,开启 syncookies 功能就可以在不使用 SYN 队列的情况下成功建立连接。

syncookies 是这么做的:服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功,如下图所示。

  • 0 表示关闭该功能;
  • 2 表示无条件开启功能;
  • 1 则表示仅当 SYN 半连接队列放不下时,再启用它。

注意:由于 syncookie 仅用于应对 SYN 泛洪攻击(攻击者恶意构造大量的 SYN 报文发送给服务器,造成 SYN 半连接队列溢出,导致正常客户端的连接无法建立),这种方式建立的连接,许多 TCP 特性都无法使用。所以,应当把 tcp_syncookies 设置为 1,仅在队列满时再启用。

服务端SYN+ACK包的重试次数

net.ipv4.tcp_synack_retries=5

相关介绍

tcp_synack_retries 的默认重试次数是 5 次,与客户端重发 SYN 类似,它的重试会经历 1、2、4、8、16 秒,最后一次重试后等待 32 秒,若仍然没有收到 ACK,才会关闭连接,故共需要等待 63 秒。

服务端全连接队列的大小

取决于min(backlog, /proc/sys/net/core/somaxconn),在linux内核2.2版本以后,listen 函数的 backlog 参数就可以设置 accept 队列的大小。

另外backlog 参数还受限于 Linux 系统级的队列长度上限,当然这个上限阈值也可以通过 somaxconn 参数修改,somaxconn是内核的参数,默认是128。

sysctl -w net.core.somaxconn=32768

四次挥手阶段

接下来我们把先关闭连接的一方叫做主动方,后关闭连接的一方叫做被动方。

四次挥手的流程:

其实四次挥手只涉及两种报文:FIN 和 ACK。FIN 就是 Finish 结束连接的意思,谁发出 FIN 报文,就表示它将不再发送任何数据,关闭这一方向的传输通道。ACK 是 Acknowledge 确认的意思,它用来通知对方:你方的发送通道已经关闭。当主动方关闭连接时,会发送 FIN 报文,此时主动方的连接状态由 ESTABLISHED 变为 FIN_WAIT1。当被动方收到 FIN 报文后,内核自动回复 ACK 报文,连接状态由 ESTABLISHED 变为 CLOSE_WAIT,顾名思义,它在等待进程调用 close 函数关闭连接。当主动方接收到这个 ACK 报文后,连接状态由 FIN_WAIT1 变为 FIN_WAIT2,主动方的发送通道就关闭了。再来看被动方的发送通道是如何关闭的。当被动方进入 CLOSE_WAIT 状态时,进程的 read 函数会返回 0,这样开发人员就会有针对性地调用 close 函数,进而触发内核发送 FIN 报文,此时被动方连接的状态变为 LAST_ACK。当主动方收到这个 FIN 报文时,内核会自动回复 ACK,同时连接的状态由 FIN_WAIT2 变为 TIME_WAIT,Linux 系统下大约 1 分钟后 TIME_WAIT 状态的连接才会彻底关闭。而被动方收到 ACK 报文后,连接就会关闭。

主动方的优化

等待ACK,FIN包的重发次数

主动方发送 FIN 报文后,连接就处于 FIN_WAIT1 状态下,该状态通常应在数十毫秒内转为 FIN_WAIT2。只有迟迟收不到对方返回的 ACK 时,才能用 netstat 命令观察到 FIN_WAIT1 状态。此时,内核会定时重发 FIN 报文,其中重发次数由 tcp_orphan_retries 参数控制(注意,orphan 虽然是孤儿的意思,该参数却不只对孤儿连接有效,事实上,它对所有 FIN_WAIT1 状态下的连接都有效),默认值是 0,特指 8 次:

net.ipv4.tcp_orphan_retries = 0

孤儿连接的数量

net.ipv4.tcp_max_orphans = 16384

相关介绍

tcp_max_orphans 定义了孤儿连接的最大数量。当进程调用 close 函数关闭连接后,该连接是在 FIN_WAIT1 状态,这个连接都与该进程无关了,它变成了孤儿连接。Linux 系统为防止孤儿连接过多,导致系统资源长期被占用,就提供了 tcp_max_orphans 参数。如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送 RST 复位报文强制关闭。

孤儿连接的定义:由进程调用close关闭的连接称为孤儿连接,另外shutdown 函数也可以关闭连接,这二者都会向对方发送 FIN 报文(shutdown 参数须传入 SHUT_WR 或者 SHUT_RDWR 才会发送 FIN),区别在于 close 调用后,哪怕对方在半关闭状态下发送的数据到达主动方,进程也无法接收。如果你用 netstat -p 命令,会发现连接对应的进程名为空(与进程无关!)。而 shutdown 函数调用后,即使连接进入了 FIN_WAIT1 或者 FIN_WAIT2 状态,它也不是孤儿连接,进程仍然可以继续接收数据。

等待FIN的时间

net.ipv4.tcp_fin_timeout = 60

相关介绍

当连接收到 ACK 进入 FIN_WAIT2 状态后,就表示主动方的发送通道已经关闭,接下来将等待对方发送 FIN 报文,关闭对方的发送通道。这时,如果连接是用 shutdown 函数关闭的,连接可以一直处于 FIN_WAIT2 状态。但对于 close 函数关闭的孤儿连接,这个状态不可以持续太久,而 tcp_fin_timeout 控制了这个状态下连接的持续时长。

TIME_WAIT相关参数

相关介绍

TIME_WAIT 是主动方四次挥手的最后一个状态。当收到被动方发来的 FIN 报文时,主动方回复 ACK,表示确认对方的发送通道已经关闭,连接随之进入 TIME_WAIT 状态,等待 60 秒后关闭。

TIME_WAIT状态最大连接数

当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历 TIME_WAIT 而直接关闭。

net.ipv4.tcp_max_tw_buckets = 5000

是否复用TIME_WAIT状态的端口

复用 TIME_WAIT 状态的端口,如果服务器会主动向上游服务器发起连接的话,就可以把 tcp_tw_reuse 参数设置为 1,它允许作为客户端的新连接,在安全条件下使用 TIME_WAIT 状态下的端口。

net.ipv4.tcp_tw_reuse = 1

当然,要想使 tcp_tw_reuse 生效,还得把 timestamps 参数设置为 1,它满足安全复用的先决条件(对方也要打开 tcp_timestamps ):

net.ipv4.tcp_timestamps = 1

老版本的 Linux 还提供了 tcp_tw_recycle 参数,它并不要求 TIME_WAIT 状态存在 60 秒,很容易导致数据错乱,不建议设置为 1。

net.ipv4.tcp_tw_recycle = 0

所以在 Linux 4.12 版本后,直接取消了这一参数。

其他配置

允许系统打开的端口范围

sysctl -w net.ipv4.ip_local_port_range=1024 65000

系统全局允许分配的最大文件句柄数

sysctl -w fs.file-max=2097152

sysctl -w fs.nr_open=2097152

echo 2097152 > /proc/sys/fs/nr_open

允许当前会话或进程打开文件句柄数

ulimit -n 1048576

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 从Linux源码看Socket(TCP)Client端的Connect的示例详解

    前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就来从Linux源码的角度看下Client端的Socket在进行Connect的时候到底做了哪些事情.由于篇幅原因,关于Server端的Accept源码讲解留给下一篇博客. (基于Linux 3.10内核) 一个最简单的Connect例子 int clientSocket; if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

  • java实现基于TCP协议网络socket编程(C/S通信)

    一.前言:TCP原理简介 首先,保证文章完整性,TCP的理论原理还是需要简介一下,略显枯燥๑乛◡乛๑. TCP(传输控制协议,Transmission Control Protocol)是一种面向连接的.可靠的.基于字节流的传输层通信协议.TCP旨在适应支持多网络应用的分层协议层次结构.也就是说,TCP是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议. 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务. 以上TCP的特点,也正是与UD

  • Python使用socket模块实现简单tcp通信

    正文开始: 服务器端代码: # 再来简单的测试,这个是服务器端 import socket import sys BUF_SIZE = 1024 ip_port = (r"127.0.0.1", 11552) my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 先拿到套接字,指定个ipv4以及流式数据包 my_socket.bind(ip_port) # 绑定 my_socket.listen(2) # 循环等

  • python如何实时获取tcpdump输出

    一.背景 今天有个小需求,要确认客户端有没有往服务端发送udp包,但为了减轻工作量,不想每次到机器上手动执行tcpdump抓包命令. 于是就写了个脚本来释放人力. 二.代码实现 整个脚本我还加了一些其他功能:时间戳.发送端IP提取,数据包分析,数据持久化等.这里都先去掉,仅记录下简单的实时获取tcpdump输出功能. 代码如下: # -*- coding: utf-8 -*- # !/usr/bin/env python # sudo tcpdump -tt -l -nn -c 5 -i enp

  • Springboot+TCP监听服务器搭建过程图解

    最近从eclipese转到idea,也从SpringMVC转到Springboot,重新搭建了一个基于Springboot的TCP监听.话不多说,直接上图. 这边是监听的文件夹,其中,EchoThread是处理上传信息的线程,SocketPool是用来存放socket的,SpringListener是随项目启动的TCP监听程序. 1.先来说说这个SpringListener 首先要做的第一点就是监听随项目启动,springboot提供了两种方案,第一种就是像这样直接继承CommandLineRu

  • Python使用socket_TCP实现小文件下载功能

    服务器 import socket # 1.创建套接字 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.绑定端口 server.bind(('127.0.0.1', 7890)) # 3.变为被动监听模式 server.listen(4) while True: # 4.等待客户端链接 s_new, addr = server.accept() print('用户[{}]已经成功连接!!'.format(addr[0]

  • Java利用TCP协议实现客户端与服务器通信(附通信源码)

    进行TCP协议网络程序的编写,关键在于ServerSocket套接字的熟练使用,TCP通信中所有的信息传输都是依托ServerSocket类的输入输出流进行的. 上一篇博客和大家分享了在网络编程中要注意的基础知识,关于IP.TCP.UDP以及端口和套接字的一些概念,想了解的小伙伴可以看我的这篇文章"盘点那些进行网络编程必须要知道的基础知识",那么今天大灰狼就来和大家分享一下如何使用TCP/IP进行网络程序的开发. TCP协议概念 先来了解一下TCP协议的基本概念. 我们知道TCP是可靠

  • Android端TCP长连接的性能优化教程分享

    前言 大家应该都知道,在Android端实现TCP长连接场景其实不多,我们最熟悉的不过推送和HTTP协议的实现(OkHttp),本文讨论的是在实现推送长连接的情况下怎么来做性能优化,下文只是我的一点拙见,有不妥之处还望指出,下面话不多说了,来一起看看详细的介绍吧. 推送长连接 可以说大部分APP是离不开推送(push)这个功能的,不过平常我们都是接入第三方SDK(极光.个推等)居多,因为要做一个推送服务,不光客户端要编写相应的Socket通信代码,服务器端更是麻烦,要处理大规模的长连接服务,消息

  • Java多线程实现TCP网络Socket编程(C/S通信)

    开篇必知必会 在前一篇<基于TCP协议网络socket编程(java实现C/S通信)>,实际存在一个问题,如果服务器端在建立连接后发送多条信息给客户端,客户端是无法全部接收的,原因在于客户端为单线程,只接受了第一条信息,剩余信息阻塞等待下一次发送.所以,这造成了客户端无法处理消息队列,每次只接收并输出一条服务器信息,出现信息不同步问题. 本篇将解决这个问题,详细记录实现java多线程通信,目标是使客户端可以一次接收服务器发送的多条信息,避免阻塞.方法是将客户端接收信息功能独立为一个线程来完成,

  • TCP性能调优实现原理及过程解析

    三次握手阶段 客户端SYN包的重试次数 sysctl -w net.ipv4.tcp_syn_retries=6 相关介绍 第 1 次重试发生在 1 秒钟后,接着会以翻倍的方式在第 2.4.8.16.32 秒共做 6 次重试,最后一次重试会等待 64 秒,如果仍然没有返回 ACK,才会终止三次握手.所以,总耗时是 1+2+4+8+16+32+64=127 秒,超过 2 分钟. 服务端半连接池大小 sysctl -w net.ipv4.tcp_max_syn_backlog=16384 服务端半连

  • JVM性能调优实现原理及配置

    1.JVM内存模型 总结:可以发现最明显的一个变化是元空间从虚拟机转移到了本地内存.默认情况下,元数据空间大小仅受限于本地内存, 这意味着以后不会因为永久代大小不够而抛出OOM异常了. jdk1.8以前,HotSpot VM将class和类的jar包数据存储在PermGen里, PermGen大小是固定的,而且项目之间无法公用公有的class,所以很容易碰到OOM异常.改成MateSpace后, 各个项目会共享同样的class空间.比如多个项目都引用了apache-common包, 在MateS

  • web性能优化之javascript性能调优

    JavaScript 是一个比较完善的前端开发语言,在现今的 web 开发中应用非常广泛,尤其是对 Web 2.0 的应用.随着 Web 2.0 越来越流行的今天,我们会发现:在我们的 web 应用项目中,会有大量的 JavaScript 代码,并且以后会越来越多.JavaScript 作为一个解释执行的语言,以及它的单线程机制,决定了性能问题是 JavaScript 的软肋,也是 web 软件工程师们在写 JavaScript 需要高度重视的一个问题,尤其是针对 Web 2.0 的应用.绝大多

  • Java性能调优概述

    程序性能的主要表现点: 执行速度:程序的反映是否迅速,响应时间是否足够短 内存分配:内存分配是否合理,是否过多地消耗内存或者存在内存泄漏 启动时间:程序从运行到可以正常处理业务需要花费多少时间 负载承受能力:当系统压力上升时,系统的执行速度.响应时间的上升曲线是否平缓 衡量程序性能的主要指标: 执行时间:程序从运行到结束所使用的时间 CPU时间:函数或者线程占用CPU的时间 内存分配:程序在运行时占用内容的空间 磁盘吞吐量:描述I/O的使用情况 网络吞吐量:描述网络的使用情况 响应时间:系统对用

  • JVM性能调优实战:让你的IntelliJ Idea纵享丝滑

    本文已被Github仓库收录 https://github.com/silently9527/JavaCore 前言 在前面整理了一篇关于JVM故障诊断和处理工具,考虑到大部分的Java程序员都使用的是IntelliJ Idea,本篇就使用工具来实战演练对IntelliJ Idea运行速度调优 调优前的运行状态 原始配置内容 要查询idea原始配置文件的路径可以在VisualVM中的概述中查看 原始配置内容: -XX:ReservedCodeCacheSize=240m -XX:+UseComp

  • SQL Server性能调优之缓存

    在执行任何查询时,SQL Server都会将数据读取到内存,数据使用之后,不会立即释放,而是会缓存在内存Buffer中,当再次执行相同的查询时,如果所需数据全部缓存在内存中,那么SQL Server不会产生Disk IO操作,立即返回查询结果,这是SQL Server的性能优化机制. 一,主要的内存消费者(Memory Consumer) 1,数据缓存(Data Cache) Data Cache是存储数据页(Data Page)的缓冲区,当SQL Server需要读取数据文件(File)中的数

  • AngularJS进行性能调优的7个建议

    AnglarJS作为一款优秀的Web框架,可大大简化前端开发的负担.近日Sebastian Fröstl在一篇博文<AngularJS Performance Tuning for Long Lists>中表示AnglarJS在处理包含复杂数据结构的大型列表时,其运行速度会非常慢.他在文中同时分享了解决方案.下面为该文的译文. AnglarJS很棒,但当处理包含复杂数据结构的大型列表时,其运行速度就会非常慢.这是我们将核心管理页面迁移到AngularJS过程中遇到的问题.这些页面在显示500行

  • .NET性能调优之一:ANTS Performance Profiler的使用介绍

    在使用.NET进行快速地上手与开发出应用程序后,接下来面临的问题可能就是程序性能调优方面的问题,而性能调优有时候会涉及方方面面的问题,如程序宿主系统.数据库.网络环境等等,而当程序异常庞大复杂的时候,性能调优将变得更加无从下手. 本系列文章主要会介绍一些.NET性能调优的工具.Web性能优化的规则(如YSlow)及方法等等内容.成文前最不希望看到的就是园子里不间断的"哪个语言好,哪个语言性能高"的争论,不多说,真正的明白人都应该知道这样的争论有没有意义,希望我们能从实际性能优化的角度去

  • 10个MySQL性能调优的方法

    MYSQL 应该是最流行了 WEB 后端数据库.WEB 开发语言最近发展很快,PHP, Ruby, Python, Java 各有特点,虽然 NOSQL 最近越來越多的被提到,但是相信大部分架构师还是会选择 MYSQL 来做数据存储. MYSQL 如此方便和稳定,以至于我们在开发 WEB 程序的时候很少想到它.即使想到优化也是程序级别的,比如,不要写过于消耗资源的 SQL 语句.但是除此之外,在整个系统上仍然有很多可以优化的地方. 1. 选择合适的存储引擎: InnoDB 除非你的数据表使用来做

  • mysql sql语句性能调优简单实例

     mysql sql语句性能调优简单实例 在做服务器开发时,有时候对并发量有一定的要求,有时候影响速度的是某个sql语句,比如某个存储过程.现在假设服务器代码执行过程中,某个sql执行比较缓慢,那如何进行优化呢? 假如现在服务器代码执行如下sql存储过程特别缓慢: call sp_wplogin_register(1, 1, 1, '830000', '222222'); 可以按如下方法来进行调试: 1. 打开mysql profiling: 2. 然后执行需要调优的sql,我们这里执行两条sq

随机推荐