Linux TCP性能调优

Eave 2017.04.07

一、优化Linux内核参数

vim /etc/sysctl.conf

在末尾增加以下内容

# ====================================================
# 内核参数优化配置
# 适用场景:高并发网络服务(网关/Nginx/消息队列等)
# ====================================================

## 指定内核针对内存分配的策略
# 0、表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程
# 1、表示内核允许分配所有的物理内存,而不管当前的内存状态如何
# 2、表示内核允许分配超过所有物理内存和交换空间总和的内存
# 建议:数据库类服务可设为 2 以获得更可预测的行为
vm.overcommit_memory = 0


## TCP连接设置
# 表示SYN队列的长度,默认为1024,加大队列长度,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_syn_backlog = 65536

# 每一个端口最大的监听队列的长度
net.core.somaxconn = 65535

# 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1


## TCP重试次数
# 在内核放弃建立连接之前发送SYN 包的数量
net.ipv4.tcp_syn_retries = 2

# 为了打开对端的连接,内核需要发送一个SYN 并附带一个回应前面一个SYN 的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK 包的数量。
net.ipv4.tcp_synack_retries = 2


## TIME-WAIT优化
# 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1

# 如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2 状态的时间。
net.ipv4.tcp_fin_timeout = 30


## 缓冲区优化
# 系统套接字读默认缓冲区(字节)
net.core.rmem_default = 8388608  # 8MB

# 系统套接字读最大缓冲区(字节)
net.core.rmem_max = 67108864  # 64MB

# 系统套接字写默认缓冲区(字节)
net.core.wmem_default = 8388608  # 8MB

# 系统套接字写最大缓冲区(字节)
net.core.wmem_max = 67108864  # 64MB

# 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
# 增大此值可以减少突发流量下的丢包,推荐设置为 32768 或更高
net.core.netdev_max_backlog = 65536

# TCP 接收缓冲区(最小值、默认值、最大值,单位:字节)
# min:为TCP socket预留用于接收缓冲的最小内存数量
# default:为TCP socket预留用于接收缓冲的缺省内存数量
# max:用于TCP socket接收缓冲的内存最大值
net.ipv4.tcp_rmem = 4096 1048576 67108864  # 4KB-1MB-64MB

# TCP 发送缓冲区(最小值、默认值、最大值,单位:字节)
# min:为TCP socket预留用于发送缓冲的最小内存数量
# default:为TCP socket预留用于发送缓冲的缺省内存数量
# max:用于TCP socket发送缓冲的内存最大值
net.ipv4.tcp_wmem = 4096 1048576 67108864  # 4KB-1MB-64MB

# 确定 TCP 栈应该如何反映内存使用;每个值的单位都是内存页(通常是 4KB)。
# 注意:此参数的单位是内存页,不是字节!以下配置约为 3GB、4GB、6GB
# 格式:压力阈值(pressure) 低压阈值(low) 高压阈值(high)
# 超过 high 后新的 TCP 内存分配会被拒绝,直到降到 low 以下
# 根据服务器内存大小,可参考以下方案:
#   - 内存 8GB:  393216 524288 786432   (1.5GB / 2GB / 3GB)
#   - 内存 16GB: 786432 1048576 1572864 (3GB / 4GB / 6GB)   ← 当前配置
#   - 内存 32GB: 1572864 2097152 3145728 (6GB / 8GB / 12GB)
#   - 内存 64GB+:3145728 4194304 6291456 (12GB / 16GB / 24GB)
net.ipv4.tcp_mem = 786432 1048576 1572864  # 约3GB-4GB-6GB


## 连接管理
# 这个值表示系统所能处理不属于任何进程的socket数量,当我们需要快速建立大量连接时,就需要关注下这个值了。
net.ipv4.tcp_max_orphans = 3276800

# 用于向外连接的端口范围
net.ipv4.ip_local_port_range = 1024 65535


## TCP保持活动连接
# 在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测包的间隔,即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为7200s
net.ipv4.tcp_keepalive_time = 300

# 在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包的发送频率,默认值为75s
net.ipv4.tcp_keepalive_intvl = 30

# 在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包次数,默认值为9(次)
net.ipv4.tcp_keepalive_probes = 3


## 时间戳
# 时间戳可以避免序列号的卷绕。一个1Gbps 的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种"异常"的数据包。
# 注意:现代内核应保持开启(值为1),用于 PAWS 和精确 RTT 计算,提升网络吞吐量
# 同时,tcp_tw_reuse=1 需要依赖此参数才能生效
net.ipv4.tcp_timestamps = 1


## 其他
# 开启路由转发功能。服务器被用作路由器、VPN网关或容器宿主机
net.ipv4.ip_forward = 1

# 系统所有进程一共可以打开的文件数量 根据内存计算 = 内存大小(KB) / 10
fs.file-max = 6553500

# 每进程能拥有的最多的内存区域 256K
vm.max_map_count = 262144


## ====================================================
## 进阶优化参数(提升高并发下的网络性能)
## ====================================================

# 开启选择确认(Selective Acknowledgment)
# 允许接收方告知发送方哪些数据段丢失,避免重传整个窗口,对丢包敏感场景性能提升明显
net.ipv4.tcp_sack = 1

# 开启转发确认(Forward Acknowledgment)
# 基于 SACK 信息更精确判断网络拥塞,配合 BBR 或 CUBIC 效果更好
net.ipv4.tcp_fack = 1

# 设置默认队列规则为公平队列(fq)
# BBR 拥塞控制算法需要与 fq 配合才能发挥最佳效果
net.core.default_qdisc = fq

# 设置 TCP 拥塞控制算法为 BBR(Bottleneck Bandwidth and RTT)
# 相比传统 cubic,在高延迟/高带宽场景下吞吐量更高、排队延迟更低(如跨国、跨运营商)
net.ipv4.tcp_congestion_control = bbr

使配置立即生效

sysctl -p

二、调整最大文件描述符

vim /etc/security/limits.conf

在"# End of file"上面添加如下

# 该语句表示:每一个用户的默认打开文件数是65536
*  -  nofile  1048576

三、验证方法

# 查看 TCP 套接字接收缓冲区
ss -i dst :80 | grep rcv
# 查看 UDP 套接字接收缓冲区
ss -u -i dst :53 | grep rcv