tcp内核参数优化
内核参数
本文总结Linux内核中关于TCP协议相关的内核参数含义及其相关配置。目的是指出可能在某些情况下提高TCP网络性能的潜在内核可调参数,请确保在进行调整之前和之后进行测试以获得可测量的定量结果。
TCP状态转移图
TCP连接的任意一端,在任一时刻都处于某一状态,当前状态可以通过netstat命令查看。上图中的粗虚线表示典型的服务器端的状态转移图,粗实线表示典型客户端连接的状态转移图。
建立连接相关选项
TCP连接建立需要3次握手,对于服务器侧来说,其维护一个内部的SYNC队列,加大队列长度为可以容纳更多等待连接的网络连接数:
net.ipv4.tcp_max_syn_backlog = 131072
客户端发起SYNC连接,如果超时会进行重传,重传次数会由下列参数进行设置:
net.ipv4.tcp_syn_retries = 2
当服务器接收到客户端发送的SYNC连接请求报文后,回应SYNC+ACK报文,并等待客户端的ACK确认,如果超时会进行重传,重传次数由下列参数设置:
net.ipv4.tcp_synack_retries = 2
TCP进行相应次数的重连操作均失败的情况下,将通知应用层。
预防半连接攻击,SYN-Cookie是一种有效的机制,它的基本原理非常简单,那就是“完成三次握手前不为任何一个连接分配任何资源”,详细可参考RFC4987 TCP SYN Flooding Attacks and Common Mitigations,参考资料1对具体实现原理进行了讲解,可参考阅读。内核提供了参数,可以用于开启或关闭此项功能:
net.ipv4.tcp_syncookies = 1
关闭连接相关选项
当客户端发送FIN结束报文,并接收到服务器的ACK确认报文后,客户端将处于FIN_WAIT_2状态,并等待服务器发送结束报文段,才能转移到TIME_WAIT状态,否则它将一直停留在这个状态。客户端处在这个状态时,连接处于半连接状态,并可以继续接收服务器端发送过来的数据。连接停留在FIN_WAIT_2状态的情况可能发生在:客户端执行半关闭后,未等服务器关闭连接就强行退出。此时服务器端连接由内核来接管,被称之为孤儿连接(orphan)。Linux为了防止孤儿连接长时间存留在内核中,定义了两个内核变量:
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_fin_timeout = 5
前者定义了内核接管的最大孤儿连接数,后者指定孤儿连接在内核中生存的时间。
客户端连接在接收到服务器端端结束报文(FIN)之后,并没有直接进入CLOSED状态,而是转移到TIME_WAIT状态。在这个状态,客户端连接要等待2MSL(Maximum Segment Life, 报文段最大生存时间)长时间,才能完全关闭,标准RFC1122推荐为2分钟。
net.ipv4.tcp_max_tw_buckets = 1200000
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
其中tcp_max_tw_buckets表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息;tcp_tw_recycle表示是否开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;tcp_tw_reuse表示是否允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭。
高性能扩展选项
RFC7323 TCP Extensions for High Performance文档中详细讨论了为提高性能而对TCP选项的扩展,详细内容可以参考该文档。
net.ipv4.tcp_sack
启用或关闭选择确认(Selective Acknowledgement, SACK)选项。TCP通信时,如果某个TCP报文段丢失,则TCP模块会重传被确认的TCP报文段后续的所有报文段。这样已经正确传输的TCP报文段也可能重复发送,从而降低TCP的性能。SACK技术正是为改善这种情况而产生的,它使TCP模块只重新发送丢失的TCP报文段,不用发送所有未被确认的TCP报文段。选择性确认项用于在连接初始化时,表示是否支持SACK功能。
net.ipv4.tcp_timestamps
启用或关闭时间戳选项。该选项提供了较为准确的计算通信双方之间的回路时间(Round Trip Time)RTT的方法,从而为TCP流量控制提供重要的信息。
net.ipv4.tcp_window_scaling
启用或关闭窗口扩大因子选项。在TCP的头部中,接收通告窗口大小时用16位表示,故最大为65535字节,但实际上TCP模块允许的接收通告窗口大小远不止这个数(提高TCP通信的吞吐量)。窗口扩大因子解决了这个问题。假设TCP头部中的接收通告窗口大小是N,窗口扩大因子(移位数)是M,则TCP报文段段实际接收通告窗口是N乘于2的M次方。M的取值范围为0~14。
配置
确保下列选项都被配置为缺省值1,打开相关的配置选项。
sysctl net.ipv4.tcp_window_scaling
sysctl net.ipv4.tcp_timestamps
sysctl net.ipv4.tcp_sack
缓存
使用setsockopt()增加TCP max缓冲区大小(32MB):
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
要增加Linux自动调整TCP缓冲区限制要使用的最小,默认和最大字节数,1GE的最大值为16MB,10GE的最大值为32M或54M:
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.tcp_wmem = 4096 65536 33554432
net.ipv4.tcp_mem参数用于配置系统对TCP内存配置:
TCP Autotuning setting. “The tcp_mem variable defines how the TCP stack should behave when it comes to memory usage. … The first value specified in the tcp_mem variable tells the kernel the low threshold. Below this point, the TCP stack do not bother at all about putting any pressure on the memory usage by different TCP sockets. … The second value tells the kernel at which point to start pressuring memory usage down. … The final value tells the kernel how many memory pages it may use maximally. If this value is reached, TCP streams and packets start getting dropped until we reach a lower memory usage again. This value includes all TCP sockets currently in use.”
tcp_mem有3个参数,单位为页(4096字节):low, pressure, high
low:当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。
pressure:当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。
high:允许所有tcp sockets用于排队缓冲数据报的页面量,当内存占用超过此值,系统拒绝分配socket,后台日志输出“TCP: too many of orphaned sockets”。
一般情况下这些值是在系统启动时根据系统内存数量计算得到的。 根据当前tcp_mem最大内存页面数是1864896,当内存为(1864896*4)/1024K=7284.75M时,系统将无法为新的socket连接分配内存,即TCP连接将被拒绝。