Linux 软路由网络吞吐优化设置

作者:Sender  来源:WaveCN.com  发布日期:2022-02-25  最后修改日期:2022-02-26

  如果使用CentOS 等 Linux操作系统、X86服务器作为软路由,网络吞吐设置是需要进行一些必需的优化设置,因为系统的默认设置并不是为了这种用途而设计。

article banner

笔者:国际认证信息系统审计师、软考系统分析师

  本文基于CentOS 7,最终实现的效果是终端数量高峰在350台左右,并发连接数14000条,路由能力仅受限于出口带宽,内网路由无丢包。暂未有条件试验更多的终端数量。

 

  相关设置编写为系统启动后的初始化脚本,通过/etc/rc.d/rc.local来调用。需要说一下的是CentOS 7中,rc.local是通过systemd,作为一个一次性运行对的服务来调用的。因此,需要通过:

# systemctl enable rc-local
# chmod +x /etc/rc.d/rc.local

  去启用。

 

  下面介绍优化设置。

 

  1. 常量定义

  定义所有的网络界面,比如em1 em2是主板上的端口,而p1p1~p1p4是附加的4端口网卡

INTERFACES="lo em1 em2 p1p1 p1p2 p1p3 p1p4"

 

  定义并发连接数设置。

  CONNTRACK 跟踪并且记录连接状态。Linux 核心对网络栈的每一个数据包均通过记录连接项去确定数据包所归属的数据流。

CONNTRACK_MAX="262144"
HASHSIZE="65536"

 

  2. TCP/IP基本设置

  这些设置也可能已经是系统的默认设置。重复设置并无问题,反而是确保会被设置。

 

  启用IP转发

echo 1 > /proc/sys/net/ipv4/ip_forward

 

  明确地禁止ECN

if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
  echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi

 

  防范SYN Flood攻击

echo "1" > /proc/sys/net/ipv4/tcp_syncookies

 

  某些路由器违反了RFC1122定义,会对ICMP广播帧发送虚假的响应。此类违反情况正常情况下会被作为内核警告而记录下来。通过设置为1(一般是默认值),内核就不会进行记录,从而避免日志文件泛滥。

echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses 

 

  调整ARP超时时间

echo 300 > /proc/sys/net/ipv4/neigh/default/base_reachable_time
echo 600 > /proc/sys/net/ipv4/neigh/default/gc_stale_time

 

  扩大ARP表。存在于ARP高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。

echo 1024 > /proc/sys/net/ipv4/neigh/default/gc_thresh1

 

  保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。 

echo 2048 > /proc/sys/net/ipv4/neigh/default/gc_thresh2

 

  保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是1024。

echo 4096 > /proc/sys/net/ipv4/neigh/default/gc_thresh3

 

  设置TCP连接超时。 默认值600秒,太长了。

echo 180 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
echo 180 > /proc/sys/net/netfilter/nf_conntrack_generic_timeout

 

  扩充接收队列

echo 4096 > /proc/sys/net/core/netdev_max_backlog
echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2048 > /proc/sys/net/core/somaxconn

 

  扩充缓冲区

echo 16777216 > /proc/sys/net/core/rmem_max
echo 16777216 > /proc/sys/net/core/wmem_max
echo "4096 87380 16777216" > /proc/sys/net/ipv4/tcp_rmem
echo "4096 65536 16777216" > /proc/sys/net/ipv4/tcp_wmem

 

  3. 增加并发连接处理能力

  修改ip_conntrack_max和hashsize的值。

echo $HASHSIZE > /sys/module/nf_conntrack/parameters/hashsize
echo $CONNTRACK_MAX > /proc/sys/net/nf_conntrack_max

  以上2句其实可以被/etc/modprobe.d/nf_conntrack.conf的配置取代

 

  要计算Conntrack模块需要占用的内存数量,可以按如下的方法:

size_of_mem_used_by_conntrack = CONNTRACK_MAX * sizeof(struct ip_conntrack) + HASHSIZE * sizeof(struct list_head)

 

  但是,sizeof(struct ip_conntrack) 会因为内核版本、系统架构、编译设置等等因素而不同。如果要准确获得这个值,需要观察内核日志信息中,ip_conntrack初始化时的信息。比如,对于CentOS 5.2 64位版本,sizeof(struct ip_conntrack) 是304字节。然后,sizeof(struct list_head) = 2 * 指针字节数,如果是64位系统,指针占8个字节。因此,conntrack所使用的内存 = CONNTRACK_MAX * 304 + HASHSIZE * 8 (字节),代入本文例子:262144和65536,计算得到即 80216064 字节,76.5M内存。

 

  如果定义的数量太大,比如CONNTRACK_MAX=1048576,会导致操作系统使用vmalloc来分配内存。而vmalloc分配的内存不是核心内存,可能会产生内存交换、物理地址不连续、强制对齐到内存页等问题。从而影响性能。

 

  本文不讨论Linux核心对内存的分配使用机制,有兴趣可以参考:

https://www.kernel.org/doc/html/latest/vm/index.html

https://hammertux.github.io/slab-allocator

 

  4. 对网络界面设置

  禁止所有网络界面的spoofing,优化网卡发送接收队列长度。

for x in ${INTERFACES}
do
  echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
  ethtool -G ${x} rx 2047 tx 511
  ip link set dev ${x} txqueuelen 2047
done

  或者可以进一步考虑,把这个脚本调整为通过 ethtool -g em1 这样的命令获取可以设置的最大值(即命令参数中的2047、511等值)去设置。不过一般情况下,手工获取一次然后修改设置到这个脚本,也就足够了。

 

  最后汇总一下无注释脚本如下:

#!/bin/sh

INTERFACES="lo em1 em2 p1p1 p1p2 p1p3 p1p4"
CONNTRACK_MAX="262144"
HASHSIZE="65536"

echo 1 > /proc/sys/net/ipv4/ip_forward
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
  echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
echo "1" > /proc/sys/net/ipv4/tcp_syncookies
echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses 
echo 300 > /proc/sys/net/ipv4/neigh/default/base_reachable_time
echo 600 > /proc/sys/net/ipv4/neigh/default/gc_stale_time
echo 1024 > /proc/sys/net/ipv4/neigh/default/gc_thresh1
echo 2048 > /proc/sys/net/ipv4/neigh/default/gc_thresh2
echo 4096 > /proc/sys/net/ipv4/neigh/default/gc_thresh3   
echo 180 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
echo 180 > /proc/sys/net/netfilter/nf_conntrack_generic_timeout
echo 4096 > /proc/sys/net/core/netdev_max_backlog
echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2048 > /proc/sys/net/core/somaxconn
echo 16777216 > /proc/sys/net/core/rmem_max
echo 16777216 > /proc/sys/net/core/wmem_max
echo "4096 87380 16777216" > /proc/sys/net/ipv4/tcp_rmem
echo "4096 65536 16777216" > /proc/sys/net/ipv4/tcp_wmem
echo $HASHSIZE > /sys/module/nf_conntrack/parameters/hashsize
echo $CONNTRACK_MAX > /proc/sys/net/nf_conntrack_max
for x in ${INTERFACES}
do
  echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
  ethtool -G ${x} rx 2047 tx 511
  ip link set dev ${x} txqueuelen 2047
done

 

  带注释脚本如下:

#!/bin/sh

# 1. 常量定义
# 定义所有的网络界面,比如em1 em2是主板上的端口,而p1p1~p1p4是附加的4端口网卡
INTERFACES="lo em1 em2 p1p1 p1p2 p1p3 p1p4"

# 定义并发连接数设置。
# CONNTRACK 跟踪并且记录连接状态。Linux 核心对网络栈的每一个数据包均通过记录连接项去确定数据包所归属的数据流。
CONNTRACK_MAX="262144"
HASHSIZE="65536"

# 2. TCP/IP基本设置
# 这些设置也可能已经是系统的默认设置。重复设置并无问题,反而是确保会被设置。

# 启用IP转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# 显式禁止ECN
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
  echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi

# 防范SYN Flood攻击
echo "1" > /proc/sys/net/ipv4/tcp_syncookies

# 某些路由器违反了RFC1122定义,会对ICMP广播帧发送虚假的响应。
# 此类违反情况正常情况下会被作为内核警告而记录下来。
# 通过设置为1(一般是默认值),内核就不会进行记录,从而避免日志文件泛滥。
echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses 

# 调整ARP超时时间
echo 300 > /proc/sys/net/ipv4/neigh/default/base_reachable_time
echo 600 > /proc/sys/net/ipv4/neigh/default/gc_stale_time
# 扩大ARP表。这个是第二层的事情。
# 存在于ARP高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。
echo 1024 > /proc/sys/net/ipv4/neigh/default/gc_thresh1
# 保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。 
echo 2048 > /proc/sys/net/ipv4/neigh/default/gc_thresh2
# 保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是1024。
echo 4096 > /proc/sys/net/ipv4/neigh/default/gc_thresh3   

# 设置TCP连接超时。
echo 180 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
# 默认值600秒,太长
echo 180 > /proc/sys/net/netfilter/nf_conntrack_generic_timeout

# 扩充接收队列
echo 4096 > /proc/sys/net/core/netdev_max_backlog
echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2048 > /proc/sys/net/core/somaxconn

# 扩充缓冲区
echo 16777216 > /proc/sys/net/core/rmem_max
echo 16777216 > /proc/sys/net/core/wmem_max
echo "4096 87380 16777216" > /proc/sys/net/ipv4/tcp_rmem
echo "4096 65536 16777216" > /proc/sys/net/ipv4/tcp_wmem

# 3. 增加并发连接处理能力
# 修改ip_conntrack_max和hashsize的值。
echo $HASHSIZE > /sys/module/nf_conntrack/parameters/hashsize
echo $CONNTRACK_MAX > /proc/sys/net/nf_conntrack_max
# 以上2句其实可以被/etc/modprobe.d/nf_conntrack.conf的配置取代

# 注意:conntrack所使用的内存(字节数)size_of_mem_used_by_conntrack = CONNTRACK_MAX * sizeof(struct ip_conntrack) + HASHSIZE * sizeof(struct list_head)
# 但是,sizeof(struct ip_conntrack) 会因为内核版本、系统架构、编译设置等等因素而不同。
# 如果要准确获得这个值,需要观察内核日志信息中,ip_conntrack初始化时的信息。
# 比如,对于CentOS 5.2 64位版本,sizeof(struct ip_conntrack) 是304字节。
# 然后,sizeof(struct list_head) = 2 * 指针字节数,如果是64位系统,指针占8个字节
# 因此,conntrack所使用的内存 = CONNTRACK_MAX * 304 + HASHSIZE * 8 (字节).
# 按本例子的262144和65536,即 80216064 字节,76.5M内存。

# 如果定义的数量太大,比如1048576,会导致操作系统使用vmalloc来分配内存。而vmalloc分配的内存不是核心内存,可能会产生内存交换、物理地址不连续、强制对齐到内存页等问题。从而影响性能。
# 本文不讨论Linux核心对内存的分配使用机制,有兴趣可以参考:
# https://www.kernel.org/doc/html/latest/vm/index.html
# https://hammertux.github.io/slab-allocator

# 4. 对网络界面设置

for x in ${INTERFACES}
do
  # 禁止所有网络界面的spoofing
  echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
    # 优化网卡发送接收队列长度
    # 可以进一步考虑,把这个脚本调整为通过 ethtool -g em1 这样的命令获取可以设置的最大值(即命令参数中的2047、511等值)去设置。不过一般情况下,手工获取一次然后修改设置到这个脚本,也就足够了。
  ethtool -G ${x} rx 2047 tx 511
  ip link set dev ${x} txqueuelen 2047
done

本栏目相关
  •  2013-09-04 Windows Server 2008 重命名域和域控制器
  •  2015-05-11 解决Windows Server 2008 R2域控制器显示无法连接到Internet
  •  2010-01-25 Linux 下的分区调整工具GParted实战
  •  2009-04-17 如何在Seamonkey上安装VMWare Server 2.0的客户机Console
  •  2020-02-27 服务器热加硬盘、热转RAID模式,配合LINUX卷操作实现不重启服务器完成扩容
  •  2008-04-17 万恶的UAC功能增加了许多麻烦
  •  2022-02-24 如何安装使用 Broadcom RAID卡命令行管理工具 StorCLI(或称PercCLI)?
  •  2022-03-01 关于 SystemRescueCD 的使用技巧连载(网络篇)
  •  2022-02-25 Linux 软路由网络吞吐优化设置
  • 微信订阅号二维码

    本页网址二维码:

    本栏目热门内容
  • Acrobat虚拟PDF打印机执行打印时挂起,解决办法竟然...
  • LINKSYS交换机登录WEB界面显示不正确的解决方法
  • 又一次RAID 5阵列故障记录
  • 解决VMware vSphere ESXi 5.0 Update 1 中虚机不能...
  • 修改CentOS发行信息以绕过Dell服务器BIOS更新和DSET...
  • 解决虚拟化运行的 Windows Server 2003 标准版出现...
  • Windows Server 2008 重命名域和域控制器
  • Intel Nehalem CPU Errata 导致 VMWare ESXi(vSpher...
  • 一次很精神的电脑组装过程记录(但不是自己的电脑)...
  • 解决MySQL Cluster 备份总是失败,提示文件已存在的...
  • MegaCli安装及使用杂记
  • 解决WSUS显示客户端不全的问题
  • 解决 VMWare vSphere 6 客户端无法修改用户密码
  • 解决Windows Server 2008 R2域控制器显示无法连接到...
  • 本站服务器RAID 5阵列双硬盘失效挽救记录
  • 网站数据库从MySQL 5.0升级到5.6的记录
  • 解决MariaDB使用Percona XtraBackup增量备份出错
  • DELL PowerEdge 820 报CPU3 INTERNAL ERROR 的解决...
  • Linux 下的分区调整工具GParted实战
  • 修改arpwatch使通知邮件主题显示IP地址
  • 程序员漫画:如何用8种不同的编程语言去解救公主
  • 解决很好用的多合一即时通信软件pidgin的崩溃问题
  • 解决Samba WINS服务的错误解释问题
  • 使用 GParted 进行虚拟机硬盘分区调整操作
  • 解决Squid代理HTTP时在浏览器出现Content Encoding ...
  • 用Delphi编写使用到ADO的DLL的一些问题
  • 网站简单改版
  • 索尼系列手提电脑备份失败,出现700错误的解决办法
  • Dell R900服务器 BMC firmware incompatible with C...
  • 更多...