Linux高并发内核调优
故事背景:某台VPN服务器在会话并发高峰期时出现低延迟+大量丢包现象,通过扩容增配+监控分析,已排除硬件性能和网络瓶颈问题,故深入排查
现象分析
故障出现时性能指标显示正常,且通过硬件增配和网络扩容手段,并无明显改善
故障复现:
会话数小于某一阈值时,延迟正常,丢包率<1%
会话数超过某一阈值时,故障复现,延迟正常,丢包率陡增至30%
定位问题
延迟正常但丢包率增加,推测是TCP连接被ACK RESET,阻断连接联想到文件描述符限制,通过查看文件描述符和limit限制,发现端倪
# 每建立一个TCP连接,操作系统就得分配一个文件描述符,linux 对可打开的文件描述符的数量分别作了三个方面的限制。 # 系统默认限制1024,这里是在部署VPN服务时手动调整到了一百万 [root@SSHVL26 ~]# cat /proc/sys/fs/file-max # 系统限制 1000000 [root@SSHVL26 ~]# cat /proc/sys/fs/nr_open # 进程限制 1000000 [root@SSHVL26 ~]# ulimit -n # 用户限制 1000000 [root@SSHVL26 ~]# lsof |grep -i vpnserver |wc -l # 当前vpn进程文件描述符连接数 1118963 # 可以明显看到文件描述符已经到达瓶颈甚至超出限制(至于为什么会超出限制暂时先不深究)
内核调优
编辑
/etc/sysctl.conf
,sysctl -p
应用更改:# 指定系统中所有进程可以打开的文件描述符的最大数量 fs.file-max = 6469558 # 指定系统中文件描述符(file descriptor)的最大数量 fs.nr_open = 6469558 # 启用SYN cookies,用于防范SYN洪水攻击 net.ipv4.tcp_syncookies = 1 # 允许将TIME-WAIT状态的套接字重新用于新的连接 net.ipv4.tcp_tw_reuse = 1 # 控制是否启用TCP连接的TIME-WAIT快速回收功能,已被弃用 net.ipv4.tcp_tw_recycle = 0 # 指定了TCP连接中最后一个ACK之后等待套接字关闭的时间 net.ipv4.tcp_fin_timeout = 30 # 设置了TCP保活(keepalive)探测的时间间隔,单位为秒 net.ipv4.tcp_keepalive_time = 1200 # 设置了系统内核中用于存储TIME-WAIT套接字的最大数量 net.ipv4.tcp_max_tw_buckets = 5000 # 启用TCP Fast Open功能,并设置了服务器支持TFO的连接队列的最大长度 net.ipv4.tcp_fastopen = 3 # 指定了本地端口范围,用于分配本地端口号 net.ipv4.ip_local_port_range = 10240 65535 # 设置了TCP接收缓冲区的最大大小 net.core.rmem_max=16777216 # 设置了TCP发送缓冲区的最大大小 net.core.wmem_max=16777216 # 设置了TCP接收缓冲区的最小值、默认值和最大值 net.ipv4.tcp_rmem=4096 87380 16777216 # 设置了TCP发送缓冲区的最小值、默认值和最大值 net.ipv4.tcp_wmem=4096 65536 16777216 # 启用TCP连接的TIME-WAIT快速回收功能,已被弃用 net.ipv4.tcp_tw_recycle = 1 # 禁用TCP时间戳选项,可以提高系统的安全性 net.ipv4.tcp_timestamps = 0 # 禁用TCP窗口扩大选项,也可以提高系统的安全性 net.ipv4.tcp_window_scaling = 0 # 禁用TCP选择确认选项,也可以提高系统的安全性 net.ipv4.tcp_sack = 0 # 设置了网络设备队列的最大长度,用于存储尚未被处理的数据包 net.core.netdev_max_backlog = 30000 # 禁用TCP性能监控,可提高性能 net.ipv4.tcp_no_metrics_save=1 #net.core.somaxconn = 262144 # 注释掉,这是设置TCP连接队列的最大长度的参数,通常不建议修改它 # 禁用SYN cookies,可根据实际需求调整 net.ipv4.tcp_syncookies = 0 # 设置了TCP最大孤儿连接数,用于处理在连接建立阶段客户端突然关闭的情况 net.ipv4.tcp_max_orphans = 262144 # 设置了TCP SYN队列的最大长度,用于存储未完成的半连接请求 net.ipv4.tcp_max_syn_backlog = 262144 # 设置了TCP SYNACK数据包的重传次数 net.ipv4.tcp_synack_retries = 2 # 设置了TCP SYN数据包的重传次数 net.ipv4.tcp_syn_retries = 2
文件描述符修改后,还需要修改limit限制
/etc/security/limits.conf
,当前会话注销重新登录后生效(注意:limit限制不能大于fs.file-max和fs.nr_open限制,否则SSH和TTY会无法登录)
* soft nofile 6469558 * hard nofile 6469558
检查各项配置
[root@SSHVL26 ~]# cat /proc/sys/fs/file-max 6469558 [root@SSHVL26 ~]# cat /proc/sys/fs/nr_open 6469558 [root@SSHVL26 ~]# ulimit -n 6469558
重新登录,重启VPN进程,观察连接数和故障复现情况
[root@SSHVL26 ~]# cat /proc/{$PID}/limits Max open files 6469558 6469558 files [root@SSHVL26 ~]# lsof |wc -l 1963070 # 文件描述符连接已突破限制
检查故障情况,此时丢包率稳定在<1%,VPN高并发故障排除。
关于Limit
/etc/security/limits.conf
限制仅针对会话创建进程,系统service进程不受控制,因此如果是通过systemctl之类启动的服务,还是会被默认限制到1024,此时可以通过修改/etc/systemd/system.conf
和/etc/systemd/user.conf
解除限制,重启系统后生效DefaultLimitNOFILE=6553560 DefaultLimitNPROC=6553560