Linux上TCP的几个内核参数调优( 二 )


echo 3 > /proc/sys/net/ipv4/tcp_syn_retriestcp_retries2tcp_retries2这个参数表面意思是在传输过程中tcp的重传次数 。但在某个版本之后Linux内核仅仅用这个tcp_retries2来计算超时时间,在这段时间的重传次数纯粹由RTO等环境因素决定,重传超时时间在5/15下的表现为:

Linux上TCP的几个内核参数调优

文章插图
 
如果我们在应用层设置的Socket所有ReadTimeout都很小的话(例如3s),这个内核参数调整是没有必要的 。但是,笔者经常发现有的系统,因为一两个慢的接口或者SQL,所以将ReadTimeout设的很大的情况 。
Linux上TCP的几个内核参数调优

文章插图
 
平常这种情况是没有问题的,因为慢请求频率很低,不会对系统造成什么风险 。但是,物理机突然宕机时候的情况就不一样了,由于ReadTimeOut设置的过大,导致所有落到这台宕机的机器都会在min(ReadTimeOut,(924.6s-1044.6s)(Linux默认tcp_retries2是15))后才能从read系统调用返回 。假设ReadTimeout设置了个5min,系统总线程数是200,那么只要5min内有200个请求落到宕机的server就会使A系统失去响应!
Linux上TCP的几个内核参数调优

文章插图
 
但如果将tcp_retries2设置为5,那么超时返回时间即为min(ReadTimeOut 5min,25.6-51.2s),也就是30s左右,极大的缓解了这一情况 。
echo 5 > /proc/sys/net/ipv4/tcp_retries2【Linux上TCP的几个内核参数调优】但是针对这种现象,最好要做资源上的隔离,例如线程上的隔离或者机器级的隔离 。
Linux上TCP的几个内核参数调优

文章插图
 
golang的goroutine调度模型就可以很好的解决线程资源不够的问题,但缺点是goroutine里面不能有阻塞的系统调用,不然也会和上面一样,但仅仅对于系统之间互相调用而言,都是非阻塞IO,所以golang做微服务还是非常Nice的 。当然了我大Java用纯IO事件触发编写代码也不会有问题,就是对心智负担太高-_-!
物理机突然宕机和进程宕不一样值得注意的是,物理机宕机和进程宕但内核还存在表现完全不一样 。
Linux上TCP的几个内核参数调优

文章插图
 
仅仅进程宕而内核存活,那么内核会立马发送reset给对端,从而不会卡住A系统的线程资源 。
tcp_slow_start_after_idle还有一个可能需要调整的参数是tcp_slow_start_after_idle,Linux默认是1,即开启状态 。开启这个参数后,我们的TCP拥塞窗口会在一个RTO时间空闲之后重置为初始拥塞窗口(CWND)大小,这无疑大幅的减少了长连接的优势 。对应Linux源码为:
static void tcp_event_data_sent(struct tcp_sock *tp,struct sk_buff *skb, struct sock *sk){ // 如果开启了start_after_idle,而且这次发送的时间-上次发送的时间>一个rto,就重置tcp拥塞窗口 if (sysctl_tcp_slow_start_after_idle &&(!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto))tcp_cwnd_restart(sk, __sk_dst_get(sk));}
Linux上TCP的几个内核参数调优

文章插图
 
关闭这个参数后,无疑会提高某些请求的传输速度(在带宽够的情况下) 。
echo 0 > /proc/sys/net/ipv4/tcp_slow_start_after_idle当然了,Linux启用这个参数也是有理由的,如果我们的网络情况是时刻在变化的,例如拿个手机到处移动,那么将拥塞窗口重置确实是个不错的选项 。但是就我们内网系统间调用而言,是不太必要的了 。
初始CWND大小毫无疑问,新建连接之后的初始TCP拥塞窗口大小也直接影响到我们的请求速率 。在Linux2.6.32源码中,其初始拥塞窗口是(2-4个)mss大小,对应于内网估计也就是(2.8-5.6K)(MTU 1500),这个大小对于某些大请求可能有点捉襟见肘 。在Linux 2.6.39以上或者某些RedHat维护的小版本中已经把CWND 增大到RFC 6928所规定的的10段,也就是在内网里面估计14K左右(MTU 1500) 。
Linux 新版本/* TCP initial congestion window */#define TCP_INIT_CWND10总结Linux提供了一大堆内参参数供我们进行调优,其默认设置的参数在很多情况下并不是最佳实践,所以我们需要潜心研究,找到最适合当前环境的组合 。




推荐阅读