TCP 参数调优

2014 年 7 月 25 日

net.core.rmem_max | wmem_max | rmem_default | wmem_default

这几个值分别代表了收发缓冲区的默认值和最大值. 比较推荐的参数是: default = 64k, max = 8M

net.ipv4.tcp_mem

这个的单位是page, 即4k. 三个值分别表示TCP socket在不同压力下(low, pressure, high)占用的内存, 内存使用超过high时, 网络包会被丢弃.

建议合理调大这个参数, 默认值是: 88752 118339 177504, 这个需要根据机器的实际内存调整. 如果是64G内存的机器, 可以调整为: 1M, 4M, 8M, 即对应内存 4GB, 16GB, 32GB.

net.ipv4.tcp_rmem | tcp_wmem

单位也是page, 4k. 这两个参数各自有三个值, 分表代表了收 | 发缓冲区的minimum, default和maximum.

default 参数会被net.core.rmem_default和net.core.wmem_default值覆盖, 同理maximum参数也会被net.core.rmem_max和net.core.wmem_max值覆盖.

所以这个参数调优的作用有限, 默认的minimum是4096, 即4k * 4k = 16M内存.

net.ipv4.tcp_sack | tcp_fack

sack是selective ack的缩写, 是指一种应答乱序IP报文的策略, 从而发送者只需要发送丢失的报文, 从而提高网络效率, 付出的代价是部分cpu的开销. 默认=1开启, 建议保持默认.

fack是forward ack的缩写, 开启拥塞避免和快速重传, 前提是net.ipv4.tcp_sack必须开启. 默认=1开启, 建议保持默认.

net.ipv4.tcp_max_tw_buckets

表示系统同时保持TIME_WAIT状态的socket数量, 如果超过这个值, TIME_WAIT状态的socket会被清除, 同时打印警告日志.

一般会了避免过多的告警日志, 会设置比较大的值. 默认值是180000, 可以调整为4倍即720000.

net.ipv4.tcp_max_orphans

表示没有任何handle的socket的最大数量, 通俗一点说, 即不属于任何进程的tcp socket最大数量. 超过这个数量的socket会被reset, 并同时告警.

这个参数是为了防御简单的DDOS攻击, 一般系统给的默认大多是8k或者16k, 某些防火墙会把它改成2k.

在网络特别繁忙时, 为了避免大量的告警信息, 也有将这个参数调大的, 例如256k.

建议这个参数保持默认就好.

net.core.netdev_max_backlog

当网卡接受数据包的速率, 比kernel处理来的快时, 即kernel处理跟不上包率时, cache这些数据包的队列长度.

默认值是1k, 可以适当调大到2k或者4k, 再大的意义不是很大, kernel都忙不过来了, cache再多也只能治标不治本.

net.ipv4.tcp_syn_retries | tcp_synack_retries

tcp_syn_retries, 顾名思义, 即握手时syn的最大重发次数, 默认是6. 这是一个客户端行为, 默认值是5, 在网络情况良好的情况下可以调小到 2.

tcp_synack_retries, 是指握手时server重发ack的最大次数, 默认是5. 这个值也可以设置到 2, 来提高server的效率.

net.ipv4.tcp_max_syn_backlog

在进行tcp三次握手时, server等待client最后一次ack的状态称为半连接状态, kernel会维护一个syn队列来记录之.

半连接syn队列的最大长度 = max(64, net.ipv4.tcp_max_syn_backlog). 如果超过了这个最大长度, 新的连接会被丢弃, client连接失败, 收到ECONNREFUSED.

默认值是1024, 如果是负载比较重的网络server, 可以调大至 65536, 减少client连接超时的问题, 同时避免syn-flood攻击的危险.

net.core.somaxconn

在tcp三次握手完成之后, 但是还没被accept出来之前, server会将连接加到一个队列, 这个队列称为accept队列.

accept队列的最大长度 = min(listen-backlog, net.core.sonmaxconn). 如果超过了这个值, 即发生了overflow, client连接失败, 收到ETIMEOUT.

默认值是128, 同样, 建议调大至 4096 左右. PS, 别忘了coding时, BSD socket的listen参数backlog, 也需要设置.

net.ipv4.tcp_syncookies

这个参数只有在kernel编译时加了CONFIG_SYNCOOKIES选项才能其作用: 当出现syn队列溢出时, 向对方发送syn cookie. 目的是为了防止syn-flood.

如果服务器没有受到syn-flood攻击, 而出现了syn-flood告警, 一般是因为业务繁忙而syn backlog比较小导致的, 所以这个时候要做的是调整net.ipv4.tcp_max_syn_backlog, 以及tcp_abort_on_overflow.

这个选项严重的违背了tcp协议, 不允许使用某些tcp扩展, 可能对例如SMTP转发这样的业务产生性能影响. 不过这个选项确实对syn-flood很管用.

默认的参数值是1, 开启, 推荐保持默认打开.

net.ipv4.tcp_timestamp

tcp_timestamp参数打开之后, 会给每个数据包打上时间戳, 可以提高RTT计算的性能.

默认打开为1, 推荐保持默认打开.

net.ipv4.tcp_tw_reuse | tcp_tw_recycle

tcp_tw_reuse参数开启处于TIME_WAIT状态下的socket快速重用, 用于新的tcp连接. 注意, 这和BSD socket中的SO_REUSEADDR选项不是一回事儿, 这里是socket重用, 后者是地址重用.

tcp_tw_recycle参数使处于TIME_WAIT状态的的socket被快速回收(默认是2msl时间).

这两个参数的默认都是0, 没打开. rfc上的说明: It should not be changed without advice/request of technical experts.

tcp_tw_recycle参数想要正常工作, 还依赖于tcp_timestamp选项, 它要求数据包的时间戳严格顺序. 所以在公网环境下, 如果多client在同一NAT中, 上行包的timestamp无法保证顺序, 会出现严重问题. 所以tcp_tw_recycle参数一般不建议打开, 保持默认为0.

net.ipv4.tcp_fin_timeout

tcp连接保持在FIN_WAIT_2的时间, 默认值是60, 这个参数可以适当调低: 30乃至更低都可以, 从而减少内存的消耗.

net.ipv4.tcp_keepalive_time

当keepalive选项开启时, tcp连接的超时时间, 默认是7200. 为了提高效率及更高的安全性, 可以调整这个参数到 1800.

但是业务不应该只依赖于tcp的超时机制, 特别是长连接的业务, 应该保证自己的心跳超时机制, 来防止恶意空连接.

net.ipv4.tcp_window_scaling

这个参数表示滑动窗口的大小是否可变. 高速网络下, 滑动窗口的动态调节, 可以提高数据传输的能力.

默认为1, 建议保持默认开启.

调整参数tips

上面的参数都在/proc/sys/net目录下, 可以打开查看默认值.

编辑/ect/sysctl.conf配置参数, /sbin/sysctl -p 启用.

如果直接修改参数, 系统重启之后会恢复成default.

参考文章

  1. Lessons learned tuning TCP and Nginx in EC2