您的位置:首页 > 理论基础 > 计算机网络

Tcp性能调优 解决Tcp长延时

2016-04-06 23:11 351 查看
背景:

根据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   */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息