先测量
ss -s
cat /proc/sys/fs/file-nr
nstat -az TcpExtListenOverflows TcpExtListenDropsListenOverflows 攀升意味着 accept 队列已满,内核正在丢弃已完成握手的连接。这是一个具体的问题,有具体的解决办法。大多数其他症状根本不能通过 sysctl 解决,而调整一台没有压力的机器只会把最终的故障转移到更难找到的地方。
值得保留的设置
# /etc/sysctl.d/90-connections.conf
fs.file-max = 2097152
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 32768
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_mtu_probing = 1
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbrsysctl --system
sysctl net.ipv4.tcp_congestion_control每一项的作用:
somaxconn限制 listen 积压,你的应用程序仍然必须请求它。在 nginx 中是listen ... backlog=65535;在大多数语言中,它是listen()的第二个参数。ip_local_port_range在客户端很重要。一个代理向一个目标打开出站连接,在默认端口范围内大约两万八千个就会耗尽临时端口。tcp_tw_reuse让内核重用 TIMEWAIT 套接字进行新的出站连接。安全。它的表亲 `tcptw_recycle` 在 Linux 4.12 中已被移除,任何仍然推荐它的指南都是在 2017 年之前写的。fq与bbr在长路径或有损路径上是真正的改进,在短而干净的路径上几乎没有差别。两者都在标准内核中。
连接跟踪
有状态防火墙会给每个连接一个 conntrack 条目,该表有一个上限。达到上限会丢弃数据包并向内核日志写入 nf_conntrack: table full。
sysctl net.netfilter.nf_conntrack_max net.netfilter.nf_conntrack_count如果你有内存,就提高它——每个条目花费几百字节:
net.netfilter.nf_conntrack_max = 1048576如果工作负载是无状态的公共服务,更好的答案是不去跟踪它:
table inet raw {
chain prerouting {
type filter hook prerouting priority raw;
tcp dport 443 notrack
}
}systemd 忽略的限制
/etc/security/limits.conf 适用于通过 PAM 登录。它对 systemd 启动的服务完全没有影响,这就是为什么在那里提高 nofile 并重启 nginx 不会改变任何东西。在单元上设置它:
mkdir -p /etc/systemd/system/nginx.service.d
cat > /etc/systemd/system/nginx.service.d/limits.conf <<EOF
[Service]
LimitNOFILE=1048576
EOF
systemctl daemon-reload
systemctl restart nginx对照正在运行的服务(而不是你刚刚写的文件)进行验证:
systemctl show nginx -p LimitNOFILE三件不做的事
- 不要从论坛粘贴一个五十行的 sysctl 文件。其中一半针对的是十年未发布的内核,而且有一行会悄悄破坏路径 MTU 发现。
- 不要在没有一条长的胖路径来证明其合理性的情况下提高
tcp_rmem和tcp_wmem。在一条一毫秒的路径上,更大的缓冲区只会换来延迟和内存压力。 - 不要禁用
tcp_timestamps。你会失去往返时间估计和 PAWS,换来的是一个关于性能的传言。
每次更改后,一次改一项,再次测量,并将文件留在版本控制中,以便下一个人能看到你做了什么以及为什么。