高流量大并发Linux TCP性能调优

高流量大并发Linux TCP性能调优

CDN是如何运作的?

实在主要是手内里的跑openvpn服务器。由于并没有明文禁p2p(哎……想想那么多流量似乎不跑点p2p也跑不完),以是造成有的时刻若是有对照多人跑BT的话,会造成VPN速率急剧下降。

本文所面临的情形为:

  高并发数

  高延迟高丢包(典型的美国服务器)

  值得注重的是,由于openvz的VPS权限对照低,能够修改的地方对照少,以是使用openvz的VPS作VPN服务器是异常不推荐的。

  我们通过修改 /etc/sysctl.conf 来到达调整的目的,注重修改完以后记得使用:

  sysctl -p

  来使修改生效。

  首先,针对高并发数,我们需要提高一些linux的默认限制:

  fs.file-max = 51200

  #提高整个系统的文件限制

  net.ipv4.tcp_syncookies = 1

  #示意开启SYN Cookies。当泛起SYN守候行列溢出时,启用cookies来处置,可提防少量SYN攻击,默以为0,示意关闭;

  net.ipv4.tcp_tw_reuse = 1

  #示意开启重用。允许将TIME-WAIT sockets重新用于新的TCP毗邻,默以为0,示意关闭;

  net.ipv4.tcp_tw_recycle = 0

  #示意开启TCP毗邻中TIME-WAIT sockets的快速接纳,默以为0,示意关闭;

  #为了对NAT装备更友好,建议设置为0。

  net.ipv4.tcp_fin_timeout = 30

  #修改系統默认的 TIMEOUT 时间。

  net.ipv4.tcp_keepalive_time = 1200

  #示意当keepalive起用的时刻,TCP发送keepalive新闻的频度。缺省是2小时,改为20分钟。

  net.ipv4.ip_local_port_range = 10000 65000 #示意用于向外毗邻的端口局限。缺省情形下很小:32768到61000,改为10000到65000。(注重:这里不要将最低值设的太低,否则可能会占用掉正常的端口!)

  net.ipv4.tcp_max_syn_backlog = 8192

  #示意SYN行列的长度,默以为1024,加大行列长度为8192,可以容纳更多守候毗邻的网络毗邻数。

  net.ipv4.tcp_max_tw_buckets = 5000

  #示意系统同时保持TIME_WAIT的最大数目,若是跨越这个数字,TIME_WAIT将马上被消灭并打印忠告信息。

  #分外的,对于内核版本新于**3.7.1**的,我们可以开启tcp_fastopen:

  net.ipv4.tcp_fastopen = 3

  其次,针对大流量高丢包高延迟的情形,我们通过增大缓存来提高 TCP 性能,自己看E文注释吧……感受我翻译出来种种味道纰谬 = =:

 

高流量大并发Linux TCP性能调优

 

这内里涉及到一个 TCP 拥塞算法的问题,你可以用下面的下令查看本机提供的拥塞算法控制模块:

  sysctl net.ipv4.tcp_available_congestion_control

  若是没有下文提到的htcp,hybla算法,你可以实验通过modprobe启用模块:

  /sbin/modprobe tcp_htcp

  /sbin/modprobe tcp_hybla

  对于几种算法的剖析,详情可以参考下: TCP拥塞控制算法 优缺点 适用环境 性能剖析 ,然则这内里没有涉及到专门为卫星通讯设计的拥塞控制算法:Hybla。凭据列位大神的实验,我们发现Hybla算法正好是最适合美国服务器的 TCP 拥塞算法,而对于日本服务器,小我私家想当然的以为htcp算法应该可以比默认的cubic算法到达更好的效果。然则由于htcp算法正好没有编入我们所使用的VPS中,以是没办法测试

  #设置 TCP 拥塞算法为 hybla

  net.ipv4.tcp_congestion_control=hybla

Tcp性能调优 解决Tcp长延时

凭据Tcp的理论盘算,Tcp最佳状态下传输是流水并行的,传输时间即是传输数据耗时+TTL,即千兆网卡的环境下

传输1MB数据需要: 1000ms/100MB*1MB+TTL=10ms+TTL,同机房传输1MB耗时10毫秒,跨机房理论耗时14毫秒

传输4MB数据需要: 1000ms/100MB*4MB+TTL=40ms+TTL,同机房传输4MB需要耗时40毫秒,跨机房理论耗时44毫秒

在我的生产环境,同机房的两个机械之间ping耗时0.15毫秒;两个机械之间读1MB数据和4MB的数据延时极端不稳定,在10毫秒~300毫秒之间颠簸。

另外一个跨机房使用了专线的环境,两台机械之间ping耗时4毫秒,但两个机械之间读1MB数据和4MB的数据延时也极端不稳定,在40毫秒~500毫秒之间颠簸。

这个征象看起来就像:网卡压力小时性能差,网卡压力大时性能反而好。

一最先怀疑是网卡驱动有问题,

通过修改网卡驱动参数,关闭NAPI功效,同机房的传输延时有所提升,详细的操作:Disable掉NAPI功效 ,即更改 ethtool -C ethx rx-usecs 0 ,但这个方案有缺点:使得cpu中断请求变多。

另外一个方案:修改tcp的初始化拥塞窗口,强制将初始化拥塞窗口设置为3,即: ip route | while read p; do ip route change $p initcwnd 3;done

这两种方案可以将同机房的读延时至于理论盘算水平。

但这两种方案,都无法解决跨机房的长延时问题。进一步追踪如下:

我们测试的延时高,是由于没有享受Tcp高速通道阶段甚至一直处于Tcp慢启动阶段。

 

我做了下面5步实验,详细历程如下:

 

STEP1】 最最先的测试代码:

每次请求确立一个Tcp毗邻,读完4MB数据后关闭毗邻,测试的效果:平均延时174毫秒:每次都新建毗邻,都要履历慢启动阶段甚至还没享受高速阶段就竣事了,以是延时高。

 

STEP2】 改善后的测试代码:

只确立一个Tcp毗邻,Client每隔10秒钟从Server读4MB数据,测试效果:平均延时102毫秒。

改善后延时还异常高,经由考察拥塞窗口发现每次读的时刻拥塞窗口被重置,从一个较小值增添,tcp又从慢启动阶段最先了。

 

STEP3】改善后的测试代码+设置net.ipv4.tcp_slow_start_after_idle=0:

只确立一个Tcp毗邻,Client每隔10秒钟从Server读4MB数据,测试效果:平均延时43毫秒。

net.ipv4.tcp_slow_start_after_idle设置为0,一个tcp毗邻在空闲后不进入slow start阶段,即每次收发数据都直接使用高速通道,平均延时43毫秒,跟盘算的理论时间一致。

 

STEP4】我们线上的营业使用了Sofa-Rpc网络框架,这个网络框架复用了Socket毗邻,每个EndPoint只打开一个Tcp毗邻。

我使用Sofa-Rpc写了一个简朴的测试代码,Client每隔10秒钟Rpc挪用从Server读4MB数据,

即:Sofa-Rpc只确立一个Tcp毗邻+未设置net.ipv4.tcp_slow_start_after_idle(默以为1),测试效果:延时高,跟理论耗时差距较大:transbuf设置为32KB时,平均延时93毫秒。

 

STEP5】

Sofa-Rpc只确立一个Tcp毗邻+设置net.ipv4.tcp_slow_start_after_idle为0,测试效果: transbuf设置为1KB时,平均延时124毫秒;transbuf设置为32KB时,平均延时61毫秒;transbuf设置为4MB时,平均延时55毫秒

使用Sofa-Rpc网络框架,在默认1KB的transbuf时延时124毫秒,不符合预期;

使用Sofa-Rpc网络框架,设置为32KB的transbuf到达较理想的延时61毫秒。32KB跟Sofa-Rpc官方最新版本推荐的transbuf值一致。

 

结论:

延时高是由于Tcp传输没享受高速通道阶段造成的,

1】需要克制Tcp空闲后慢启动 :设置net.ipv4.tcp_slow_start_after_idle = 0

2】只管复用Tcp socket毗邻,保持一直处于高速通道阶段

3】我们使用的Sofa-Rpc网络框架,需要把Transbuf设置为32KB以上

 

另附linux-2.6.32.71内核对tcp idle的界说:

 

从内核代码153行可见在idle时间icsk_rto后需要执行tcp_cwnd_restart()进入慢启动阶段,

网络交换机的简单知识

Icsk_rto赋值为TCP_TIMEOUT_INIT,其界说为

#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value */

linux内核Tcp性能调优

1. fs.file-max

最大可以打开的文件形貌符数目,注重是整个系统。

在服务器中,我们知道每建立一个毗邻,系统就会打开一个文件形貌符,以是,文件形貌符打开的最大数目也决议了我们的最大毗邻数

select在高并发情形下被取代的缘故原由也是文件形貌符打开的最大值,虽然它可以修改但一样平常不建议这么做,详情可见unp select部门。

2.net.ipv4.tcp_max_syn_backlog

Tcp syn行列的最大长度,在举行系统挪用connect时会发生Tcp的三次握手,server内核会为Tcp维护两个行列,Syn行列和Accept行列,Syn行列是指存放完成第一次握手的毗邻,Accept行列是存放完成整个Tcp三次握手的毗邻,修改net.ipv4.tcp_max_syn_backlog使之增大可以接受更多的网络毗邻。

注重此参数过大可能遭遇到Syn flood攻击,即对方发送多个Syn报文端填充满Syn行列,使server无法继续接受其他毗邻

可参考此文http://tech.uc.cn/?p=1790

我们看下 man 手册上是若何说的:

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for com‐ pletely established sockets waiting to be accepted, instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored. See tcp(7) for more information. If the backlog argument is greater than the value in /proc/sys/net/core/somaxconn, then it is silently truncated to that value; the default value in this file is 128. In kernels before 2.4.25, this limit was a hard coded value, SOMAXCONN, with the value 128.

自 Linux 内核 2.2 版本以后,backlog 为已完成毗邻行列的最大值,未完成毗邻行列巨细以 /proc/sys/net/ipv4/tcp_max_syn_backlog 确定,然则已毗邻行列巨细受 SOMAXCONN 限制,为 min(backlog, SOMAXCONN)

3.net.ipv4.tcp_syncookies

修改此参数可以有用的提防上面所说的syn flood攻击

原理:在Tcp服务器收到Tcp Syn包并返回Tcp Syn+ack包时,不专门分配一个数据区,而是凭据这个Syn包盘算出一个cookie值。在收到Tcp ack包时,Tcp服务器在凭据谁人cookie值检查这个Tcp ack包的正当性。若是正当,再分配专门的数据区举行处置未来的TCP毗邻。

默以为0,1示意开启

4.net.ipv4.tcp_keepalive_time

Tcp keepalive心跳包机制,用于检测毗邻是否已断开,我们可以修改默认时间来中断心跳包发送的频率。

keepalive一样平常是服务器对客户端举行发送查看客户端是否在线,由于服务器为客户端分配一定的资源,然则Tcp 的keepalive机制很有争议,由于它们可花费一定的带宽。

Tcp keepalive详情见Tcp/ip详解卷1 第23章

5.net.ipv4.tcp_tw_reuse

我的上一篇文章中写到了time_wait状态,大量处于time_wait状态是很浪费资源的,它们占用server的形貌符等。

修改此参数,允许重用处于time_wait的socket。

默以为0,1示意开启

6.net.ipv4.tcp_tw_recycle

也是针对time_wait状态的,该参数示意快速接纳处于time_wait的socket。

默以为0,1示意开启

7.net.ipv4.tcp_fin_timeout

修改time_wait状的存在时间,默认的2MSL

注重:time_wait存在且生计时间为2MSL是有缘故原由的,见我上一篇博客为什么会有time_wait状态的存在,以是修改它有一定的风险,照样凭据详细的情形来剖析。

8.net.ipv4.tcp_max_tw_buckets

所允许存在time_wait状态的最大数值,跨越则马上被清晰而且忠告。

9.net.ipv4.ip_local_port_range

示意对外毗邻的端口局限。

10.somaxconn

前面说了Syn行列的最大长度限制,somaxconn参数决议Accept行列长度,在listen函数挪用时backlog参数即决议Accept行列的长度,该参数太小也会限制最大并发毗邻数,由于同一时间完成3次握手的毗邻数目太小,server处置毗邻速率也就越慢。服务器端挪用accept函数现实上就是从已毗邻Accept行列中取走完成三次握手的毗邻。

Accept行列和Syn行列是listen函数完成建立维护的。

/proc/sys/net/core/somaxconn修改

上面每一个参数实在都够写一篇文章来剖析了,这里我只是概述下部门参数,注重在修改Tcp参数时我们一定要凭据自己的现实需求以及测试效果来决议。

 

问题形貌

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

1.间歇性得泛起client向server确立毗邻三次握手已经完成,但server的selector没有响应到这毗邻。

2.出问题的时间点,会同时有许多毗邻泛起这个问题。

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

4.程序刚启动的时刻必会泛起一些,之后会间歇性泛起。

 

剖析问题

正常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" 去看行列的溢出统计数据:

频频看了几回之后发现这个overflowed 一直在增添,那么可以明确的是server上全毗邻行列一定溢出了。

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

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握手历程中建毗邻的流程和行列

 

高流量大并发Linux TCP性能调优

 

如上图所示,这里有两个行列:syns queue(半毗邻行列);accept queue(全毗邻行列)。

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

第三步的时刻server收到client的ack,若是这时全毗邻行列没满,那么从半毗邻行列拿出这个毗邻的信息放入到全毗邻行列中,否则按tcp_abort_on_overflow指示的执行。

这时若是全毗邻行列满了而且tcp_abort_on_overflow是0的话,server过一段时间再次发送syn+ack给client(也就是重新走握手的第二步),若是client超时守候对照短,client就很容易异常了。

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

 

高流量大并发Linux TCP性能调优

 

若是TCP毗邻行列溢出,有哪些指标可以看呢?

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

netstat -s

 

高流量大并发Linux TCP性能调优

 

好比上面看到的 667399 times ,示意全毗邻行列溢出的次数,隔几秒钟执行下,若是这个数字一直在增添的话一定全毗邻行列偶然满了。

ss 下令

 

高流量大并发Linux TCP性能调优

 

上面看到的第二列Send-Q 值是50,示意第三列的listen端口上的全毗邻行列最大为50,第一列Recv-Q为全毗邻行列当前使用了若干。

全毗邻行列的巨细取决于:min(backlog, somaxconn) . backlog是在socket建立的时刻传入的,somaxconn是一个os级别的系统参数。

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

我对网络IO的理解

分享到 :
CDN是若何运作的?
2020-06-27 下一篇
相关推荐

发表评论

登录... 后才能评论