Shadowsocks 服务端系统网络性能优化的原则

  • 在一开始,能不优化的都不优化
  • 可以在以后的使用中逐步测试、改进和增加优化选项

为什么对优化持谨慎的态度?因为我们把多个优化选项放在同一个文件中,如果带来了某方面的副作用,给测试、排查带来了困难

最大队大小优化

在通过TCP / UDP层处理数据之前,系统会将数据放入内核队列中。 net.core.netdev_max_backlog 值指定在传递到上层之前要放入队列的最大数据包数。 对于高网络负载,默认值是不够的,因此简单地增加此值可以解决内核导致的性能损失问题。 要查看默认值,请将sysctl与$ sysctl net.core.netdev_max_backlog一起使用。 默认值为1000,将其增加到3000以上将足以阻止数据包在10Gbps(或更多)网络中被丢弃

$ sysctl net.core.netdev_max_backlog
sysctl net.core.netdev_max_backlog = 1000

sudo vi /etc/sysctl.d/98-network-custom.conf
net.core.netdev_max_backlog = 4096

另一个类似的设置是 net.ipv4.tcp_max_syn_backlog 记住的连接请求的最大数量,但仍未收到来自连接客户端的确认。 对于内存超过128 MB的系统,默认值为1024,对于低内存计算机,默认值为128。 如果服务器过载,请尝试增加此数量

$ sysctl net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_max_syn_backlog = 128

sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_max_syn_backlog = 4096

最大挂起连接数优化

应用程序可以在处理一个连接之前指定要放入队列的最大待处理请求数。 当此值达到最大值时,进一步的连接开始退出。 对于发布大量连接的Web服务器等应用程序,此值必须很高才能使这些连接正常工作

$ sysctl net.core.somaxconn
net.core.somaxconn = 128

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.core.somaxconn = 4096

TCP FIN超时优化

在TCP连接中,双方必须独立关闭连接。 Linux TCP发送FIN数据包以关闭连接并等待FINACK直到定义超时值

$ sysctl net.ipv4.tcp_fin_timeout
sysctl net.ipv4.tcp_fin_timeout = 60

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_fin_timeout = 30

默认值(60)非常高,可以减少到20或30以使TCP关闭连接并释放资源以进行另一个连接

重用 TIME_WAIT 状态的套接字进行新连接

根据Linux文档,您应该使用TCP_TW_REUSE 标志允许重新使用TIME_WAIT状态的套接字进行新连接

在处理必须处理TIME_WAIT状态下的许多短TCP连接的Web服务器时,这似乎是一个不错的选择

$ sysctl net.ipv4.tcp_tw_reuse
net.ipv4.tcp_tw_reuse = 0

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_tw_reuse = 1

tcp_keepalive_time 优化

TCP连接由两个套接字组成,每个套接字在连接的两端。 当一方想要终止连接时,它会发送另一方确认的RST数据包并关闭其套接字

然而,在此之前,双方将无限期地保持其套接字开放。 这使得一方可能有意或由于某些错误而关闭其插座,而无需通过RST通知另一端。 为了检测此场景并关闭过时连接,使用TCP Keep Alive处理

有三个可配置属性可确定Keep-Alives的属性。 在Linux上他们是1:

  • tcp_keepalive_time

    默认7200秒

  • tcp_keepalive_probes

    默认9

  • tcp_keepalive_intvl

    默认75秒

这个过程是这样的:

  • 客户端打开TCP连接
  • 如果tcp_keepalive_time秒的连接是静默的,则发送一个空的ACK数据包
  • 服务器是否使用自己的相应ACK进行响应?
    • 没有
      • 等待tcp_keepalive_intvl秒,然后发送另一个ACK
      • 重复,直到已发送的ACK探测数等于tcp_keepalive_probes
      • 如果此时未收到响应,请发送RST并终止连接
    • 是:返回第2步

默认情况下,在大多数操作系统上启用了此处理过程,因此一旦另一端无响应2小时11分钟(7200秒+ 75 * 9秒),则会定期移除死TCP连接

$ sysctl net.ipv4.tcp_keepalive_time
net.ipv4.tcp_keepalive_time = 7200

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_keepalive_time = 1200

启用智能MTU黑洞检测优化

一旦启用,您的操作系统将尝试使用路径MTU发现机制在客户端和服务器之间找到MTU

您可以通过运行 ip a 检查接口上的MTU:

$ ip a | grep mtu
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP group default qlen 1000

什么是 MTU

MTU = Maximum Transmission Unit

当Internet上的主机想要发送一些数据时,它必须知道如何将数据分成数据包。 特别是,它需要知道数据包的最大大小。 主机可以发送的数据包的最大大小称为 Maximum Transmission Unit,最大传输单元,MTU

MTU越长,性能越好,但可靠性越差。 这是因为丢失的数据包意味着要重新传输更多数据,并且因为Internet上的许多路由器无法传输非常长的数据包

ICMP消息应该被传递给始发主机,而主机应该调整该特定连接的MTU设置。 此机制称为 Path MTU Discovery,路径MTU发现

从理论上讲,它很棒,但遗憾的是,在传送ICMP数据包时,很多事情都可能出错。 最常见的问题是由丢失ICMP数据包的防火墙配置错误引起的

路由器丢弃数据包但由于某种原因无法传递相关ICMP消息的情况称为 ICMP black hole,ICMP黑洞

当发生这种情况时,整个连接都会卡住。 发送方不断尝试重新发送丢失的数据包,而接收方仅确认传送的小数据包

RFC4821 提出了一种检测ICMP黑洞的机制,并尝试以智能方式调整路径MTU。 要在Linux类型上启用此功能,运行命令:

$ sysctl net.ipv4.tcp_mtu_probing
net.ipv4.tcp_mtu_probing = 0
$ sysctl net.ipv4.tcp_base_mss
net.ipv4.tcp_base_mss = 1024

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_mtu_probing = 1

tcp_mtu_probing,控制TCP分组化 – 层路径MTU发现。 可选三个 值:

  • 0 已禁用
  • 1 默认情况下禁用,在检测到ICMP黑洞时启用
  • 2 始终启用,使用tcp_base_mss的初始MSS

net.ipv4.tcp_base_mss 设置发现中使用的起始MSS值,如果系统默认小于1024,可改成1024:

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_base_mss = 1024

参考*:

  • https://blog.cloudflare.com/path-mtu-discovery-in-practice/

可选优化:内核缓冲区优化

查看ubuntu 18.04系统默认的套接字缓冲区大小:

$ sudo sysctl net.core.wmem_default
net.core.wmem_default = 212992
$ sysctl net.core.rmem_default
net.core.rmem_default = 212992
$ sysctl net.core.rmem_max
sysctl net.core.rmem_max = 212992
$ sysctl net.core.wmem_max
net.core.wmem_max = 212992

212992 bytes,换算成 KB,212992 / 1024 = 208 KB

这些参数显示分配给任何类型连接的默认和最大写入、读取缓冲区大小。 由于分配的空间来自RAM,因此默认值设置总是有点低。增加这一点可能会提高运行NFS等服务器的系统的性能。 将它们增加到256k / 4MB将最有效,否则您必须对这些值进行基准测试,以找到系统配置的理想值

我们把自定义网络优化都保存到/etc/sysctl.d/98-network-custom.conf

$ sudo vi /etc/sysctl.d/98-network-custom.conf

# 256 KB / 4 MB
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_max = 4194304

# Or 256 Kb / 64 MB
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864

67108864 bytes = 64 MB,这个值是比较大的,最好是测试一下,对于你的系统,这个值是否是最优值

可选优化:TCP缓冲区大小优化

查看一下系统默认值:

$ sysctl net.ipv4.tcp_rmem
net.ipv4.tcp_rmem = 4096        87380   6291456
$ sysctl net.ipv4.tcp_wmem
net.ipv4.tcp_wmem = 4096        16384   4194304

这些值是三个整数的数组,分别指定TCP读取和发送缓冲区的最小,平均和最大值

注意:值以页为单位。 要查看页面大小,请使用命令查看:

$ getconf PAGE_SIZE
4096

也就是设置的值必须是4096的倍数

TCP缓冲区最大值改成64 MB:

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 16384 67108864

或者TCP缓冲区最大值改成12 MB:

net.ipv4.tcp_rmem = 4096 87380 12582912
net.ipv4.tcp_wmem = 4096 16384 12582912

有的人推荐TCP缓冲区最大值为 4MB:

net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304

Linux 2.6 内核开始,有一个自动调整功能,可以动态调整TCP缓冲区大小,直到达到最大值。 默认情况下,此功能处于启用状态,我建议将其保持打开状态。 您可以通过运行以下命令来检查它:

$ cat /proc/sys/net/ipv4/tcp_moderate_rcvbuf
1

要在它关闭的情况下临时打开它,请使用下面给出的命令:

sysctl -w net.ipv4.tcp_moderate_rcvbuf = 1

如果您发现内核缓冲区是您的瓶颈,需要增加最大缓冲区大小,则此设置将空间分配为最大值。无需更改平均值,但必须将最大值设置为高于BDP(带宽延迟乘积)以获得最大吞吐量

BDP =带宽(B /秒)* RTT(秒),其中RTT(往返时间)可以通过ping到任何其他系统来计算,并以秒为单位查找平均时间

此项如上优化后可能造成上传文件失败或变慢,故列为可选优化

可选优化:Time Wait优化

TIME WAIT TCP套接字状态是套接字关闭但等待处理仍在网络中的数据包的状态。 参数tcp_max_tw_buckets是 TIME_WAIT 状态下的最大套接字数。 达到此数字后,系统将开始在此状态下销毁套接字

此限制仅用于防止简单的DoS攻击,您不得人为地降低限制,而是增加它(可能在增加安装的内存之后),如果网络条件需要超过默认值

$ sysctl net.ipv4.tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 4096

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.tcp_max_tw_buckets = 5000

如果遇到大量的TCP 错误,如:

__ratelimit: 33491 callbacks suppressed
TCP: time wait bucket table overflow

可以增加 net.ipv4.tcp_max_tw_buckets 的值,比如 654320,前提是拥有足够的内存

请尝试以下命令来确定您是否有来自一个地址的大量连接,或者您是否受到分布式攻击

netstat -nt | cut -c 40- | cut -d: -f1 | sort | uniq -c | sort -n netstat -nt | cut -d: -f2 | sort | uniq -c | sort -n

如果您从几个IP地址获得高数字,则更容易限制连接。 然后,您可以向 iptables 添加拒绝规则或速率限制规则,以限制从这些地址访问

经测试,优化此项可能造成上传文件至某些网站超时或错误

可选优化:IP端口范围优化

net.ipv4.ip_local_port_range 显示可用于新连接的所有端口。 如果没有空闲端口,则连接将被取消。 增加此值有助于防止此问题

如果您的Linux服务器正在打开大量传出网络连接,则需要增加本地端口范围。 默认情况下范围很小。 例如,如果squid代理服务器用完了端口,它就会受到攻击。 其他示例包括繁忙的流量网络服务器,如nginx负载平衡器,LXD vm等

我们可以加大用于新连接的端口选择范围,但是有一个风险,某个程序使用的特定端口可能被该服务器上的其他程序随机选取源端口给占用掉了,解决办法是将服务监听的特定端口以逗号分隔全部添加到ip_local_reserved_ports中

ip_local_reserved_ports 逗号分隔范围列表指定为已知第三方保留的端口应用。 自动端口不会使用这些端口 赋值(例如,当使用port调用connect()或bind()时 数字0)。 显式端口分配行为保持不变

用于输入和输出的格式是逗号分隔范围列表,例如保留端口1,2,3,4和1可以这样指定:1,2-4,10-10

写入文件后将清除以前保留的所有内容端口并使用中给出的端口更新当前列表输入

请注意 ip_local_port_range 和 ip_local_reserved_ports 设置是独立的,并且都由内核考虑确定哪些端口可用于自动端口时分配

本翻墙方案 https://github.com/softwaredownload/openwrt-fanqiang shadowsocks-libev 服务端指定监听 1098 端口,1098 应该加入到 ip_local_reserved_ports 这样ip_local_port_range 无论怎么设置都不影响 shadowsocks-libev 监听在 1098 端口

$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999
$ sysctl net.ipv4.ip_local_reserved_ports
# 默认空值

$ sudo vi /etc/sysctl.d/98-network-custom.conf
net.ipv4.ip_local_port_range = 10000 65535
net.ipv4.ip_local_reserved_ports = 1098

以上定义了TCP和UDP使用的本地端口范围选择本地端口。 第一个数字是第一个,第二个是最后一个本地端口号。 如果可能,这些数字具有不同的奇偶校验即一个偶数和一个奇数值是更好的。 默认值分别为32768和60999,或者由发行版或系统管理员设置的默认值。 在此示例中,1024 不是奇数,65535是奇数

 

无需优化

  • net.ipv4.tcp_syncookies

    Ubuntu 18.04 以下已经默认设置:

    net.ipv4.tcp_syncookies = 1
    
  • net.ipv4.tcp_tw_recycle

    在 Linux 内核 4.12 开始已经移除这个选项了,ubuntu 18.04 不需要设置此值。如果你的内核较旧,可以增加设置:

    net.ipv4.tcp_tw_recycle = 0
    

/etc/sysctl.d/98-network-custom.conf

net.core.netdev_max_backlog = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.core.somaxconn = 4096

net.ipv4.tcp_fin_timeout = 30

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_keepalive_time = 1200

net.ipv4.tcp_mtu_probing = 1

使 Linux 系统网络优化立即生效:

sudo sysctl --system

需要注意的是,上面的TCP/UDP优化只是供参考,最佳的设置需要各人自己测试才能确定,设置不当可能会有问题,比如说使上传视频到外网变慢

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。