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 */
根据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 */
相关文章推荐
- 选定虚拟主机 性能凸显优势
- 修改一行代码提升 Postgres 性能 100 倍
- redis的hGetAll函数的性能问题(记Redis那坑人的HGETALL)
- 推荐Sql server一些常见性能问题的解决方法
- SQL Server误区30日谈 第9天 数据库文件收缩不会影响性能
- 和表值函数连接引发的性能问题分析
- SQLServer 2000 升级到 SQLServer 2008 性能之需要注意的地方之一
- 数据库性能优化三:程序操作优化提升性能
- VBS中的字符串连接的性能问题
- TCP版backshell的VBS脚本代码
- mysql 性能的检查和调优方法
- 数据库性能优化二:数据库表优化提升性能
- SQL语句性能优化(续)
- SQL语句优化提高数据库性能
- 如何用分表存储来提高性能 推荐
- ASP中使用FileSystemObject时提高性能的方法
- 如何改进javascript代码的性能
- JavaScript脚本性能优化注意事项
- 使用Function.apply()的参数数组化来提高 JavaScript程序性能的技巧
- JQuery Tips(4) 一些关于提高JQuery性能的Tips