一开始怀疑是网卡驱动有问题 ,
通过修改网卡驱动参数 , 关闭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使之增大可以接受更多的网络连接 。
推荐阅读
- 为什么水龙头的水突然小了,自来水出水量大小和水龙头有关吗
- 一个排风扇一天用多少电 排风扇耗电量大不大
- 千万级 高并发“秒杀”架构设计
- 淘宝店铺怎么提高流量和销量 淘宝新店如何提高销量
- 汽车排量大小的区别
- 空气能热水器耗电量大吗,空气能热水器要长期通电吗
- 阿里架构师教你处理高并发:2种方法,解决Redis和Mysql一致性
- 梦见被交警开罚单周公解梦 梦见被交警开罚单并发生争执
- 高并发之API接口,分布式,防刷限流,如何做?
- 如何模拟超过 5 万用户的并发访问?
