sysctl 动态修改内核的参数。修改后的参数支持在/proc/sys/目录下查看,包含一些TCP/IP堆栈和虚拟内存系统的高级选项。
介绍
- 通过配置合理的
sysctl 参数可提高系统的性能
sysctl 命令既可以读又可以写系统参数
sysctl 命令
sysctl (选项) (参数)
例子:
sysctl [-n] [-e] variable …
sysctl [-n] [-e] [-q] -w variable=value …
sysctl [-n] [-e] [-q] -p [filename]
sysctl [-n] [-e] -a
sysctl [-n] [-e] -A
选项:
-n:打印值时不打印关键字;
-e:忽略未知关键字错误;
-N:仅打印名称;
-w:当改变sysctl设置时使用此项;
-p:从配置文件“/etc/sysctl.conf”加载内核参数设置;
-a:打印当前所有可用的内核参数变量和值;
-A:以表格方式打印当前所有可用的内核参数变量和值。
参数:
- 变量=值:设置内核参数对应的值。注意等号两端不能有空格。
使用
查看系统变量
sysctl -a // 显示当前所有可用的内核参数
sysctl kernel.hostname // 读特定的内核参数,比如kernel.hostname
sysctl -a | grep hostname // 显示名称中带有“hostname”关键字的内核参数
修改系统变量
sysctl -w kernel.hostname=abc // 把hostname改为abc
简略一点:
sysctl kernel.hostname=abc // 把hostname改为abc
从配置文件加载内核参数
sysctl -p // 从配置文件sysctl.conf中加载内核参数
修改系统变量有两种方式,一种是上述修改系统变量中的命令行方式,另一种是修改sysctl.conf文件。sysctl.conf文件一般在系统的/etc目录下。在最后一行输入如下语句:
kernel.hostname=abc
然后需要执行sysctl -p指令更新修改的内核参数配置文件,使其生效。
常见参数
fs.file-max
fs.file-max 是一个 Linux 内核参数,用于定义整个系统可以同时打开的**文件句柄(File Handle,也称文件描述符 File Descriptor, FD)**的最大数量。
- 路径:
/proc/sys/fs/file-max
- 作用:设置 Linux 内核在任何给定时间可以分配给所有进程的最大文件句柄数(系统级限制)。
- 默认值:这个值通常是根据系统内存(RAM)动态计算的,在现代系统上通常设置得很高。
理解 fs.file-max 的关键在于它是系统级的全局限制,并与用户/进程级别的限制(ulimit)相互关联。
| 限制类型 |
内核参数/命令 |
作用范围 |
描述 |
| 系统级限制 |
fs.file-max |
整个系统所有进程 |
内核允许分配的文件句柄总数上限。这是所有进程打开文件数的硬性天花板。 |
| 进程/用户限制 |
ulimit -n |
单个进程或用户 |
限制单个用户或单个进程可以打开的文件句柄数量。该限制不能超过 fs.file-max 或 /proc/sys/fs/nr_open 的系统级限制。 |
文件句柄 (File Handle) 是操作系统用来跟踪进程所打开的文件、套接字(socket)、管道或其他资源的小整数。
如果系统中的应用程序(如高并发的 Web 服务器、数据库服务器、文件服务器等)需要同时处理大量的连接和文件操作,它们可能会快速消耗文件句柄。
当系统达到 fs.file-max 限制时,任何尝试打开新文件或建立新连接的进程都会失败,并报告 Too many open files 的错误,即使单个进程的 ulimit 尚未达到上限。
判断是否需要增加:
可以通过查看 /proc/sys/fs/file-nr 文件来了解当前的使用情况。该文件包含三个值:
cat /proc/sys/fs/file-nr
# 示例输出: [已分配的文件句柄数] [未使用的文件句柄数] [fs.file-max 的值]
# 3488 0 793759
如果第一个值(已分配数)接近第三个值(fs.file-max),则表示系统接近文件句柄耗尽,应考虑增加 fs.file-max 的值。
要永久提高限制,需修改 /etc/sysctl.conf 文件并执行 sysctl -p:
-
编辑配置文件 /etc/sysctl.conf:
# 示例:将系统最大文件句柄数设置为 100 万
fs.file-max = 1000000
-
应用配置:
执行命令使配置立即生效:
注意: 增加这个值会增加内核为跟踪文件句柄而保留的内存。虽然现代系统上这通常不是问题,但应根据实际需求和系统资源来设置合理的值。通常,增加 fs.file-max 之后,还需要相应地调整应用程序运行用户的 ulimit -n(打开文件数)限制,才能让应用程序真正利用到增加后的容量。
fs.inotify.max_user_instances / fs.inotify.max_user_watches
fs.inotify.max_user_instances 是一个 Linux 内核参数,用于控制 **Inotify 实例(Instance)**的数量限制。
- 路径:
/proc/sys/fs/inotify/max_user_instances
- 机制:Inotify 是 Linux 内核提供的文件系统事件监控机制。它允许应用程序监控文件或目录的创建、删除、修改等操作。
- 作用:该参数定义了每个真实用户 ID (Real User ID) 可以创建的 Inotify 实例的最大数量。
理解这个参数需要区分两个关键概念:实例(Instance) 和 监听项(Watch)。
-
Inotify 实例 (Instance)
- 对应:通过系统调用
inotify_init() 创建的一个文件描述符。
- 用途:一个应用程序(或进程)通常会创建一个或几个 Inotify 实例来接收文件系统事件。
max_user_instances 限制的就是这种文件描述符的数量。
- 默认值:在大多数 Linux 发行版中,默认值通常较低,例如 128。
-
Inotify 监听项 (Watch)
- 对应:通过系统调用
inotify_add_watch() 添加到某个实例的具体文件或目录。
- 限制:由另一个内核参数
fs.inotify.max_user_watches 控制,它限制了每个用户可以监听的文件和目录的总数量。
总结关系:
一个用户可以创建的 实例数量 被 max_user_instances 限制。每个实例可以添加多个 监听项,但所有实例的监听项总数不能超过 max_user_watches 的限制。
在以下场景中,用户可能会遇到 max_user_instances 限制不足的问题:
- 同步客户端:如 Dropbox、OneDrive 或 Nextcloud 客户端,它们通常会运行后台进程来监听本地目录的变化。
- 集成开发环境(IDE):如 VS Code 或 JetBrains IDE,它们需要监听项目文件的实时变化。
- 构建系统/热重载工具:如 Webpack、Vite、Node.js 中的 Nodemon 或其他需要自动检测代码更改并重新编译或重新加载的服务。
- 安全监控或日志管理:系统或安全工具可能需要创建多个 Inotify 实例来监控关键目录。
如果运行多个此类应用程序,或者某个应用程序本身设计为使用多个 Inotify 实例,可能会达到默认的 128 个实例限制,导致应用程序无法正常监控文件系统变化,并可能报告类似于 Too many open files 或 No space left on device (ENOSPC) 的错误。
要永久提高限制,需修改 /etc/sysctl.conf 文件并执行 sysctl -p:
-
编辑配置文件 /etc/sysctl.conf:
# 提高每个用户可创建的 inotify 实例数量
fs.inotify.max_user_instances = 1024
# (注意:通常建议同时检查和提高 max_user_watches 的值)
fs.inotify.max_user_watches = 524288
-
应用配置:
net.ipv4.conf.all.arp_ignore / net.ipv4.conf.all.arp_announce
net.ipv4.conf.all.arp_ignore 和 net.ipv4.conf.all.arp_announce 是 Linux 内核参数,用于控制系统处理 ARP(Address Resolution Protocol,地址解析协议)请求和响应的行为。它们主要在具有多网卡(Multi-homed)或配置了虚拟 IP (Virtual IP, VIP) 的服务器上发挥作用,以避免 ARP 冲突和路由混乱。
| 参数 |
控制行为 |
推荐值 (HA/LVS-DR) |
arp_ignore |
接收 ARP 请求时的响应策略 |
1 或 2 |
arp_announce |
发送 ARP 报文时的源 IP 选择策略 |
2 |
net.ipv4.conf.all.arp_ignore (处理 ARP 请求)
该参数定义了系统在接收到一个 ARP 请求时,如何响应这个请求的策略。
- 路径:
/proc/sys/net/ipv4/conf/all/arp_ignore
- 作用:控制系统是否会回复目标 IP 地址是本机地址的 ARP 请求。
可选值及其含义
| 值 |
策略 |
描述 |
| 0 (默认) |
任意接口响应 |
系统会回复所有目标 IP 地址是本机地址的 ARP 请求,即使该 IP 地址不属于接收请求的那个网络接口。 |
| 1 |
本地接口匹配 |
只有当 ARP 请求的目标 IP 地址配置在接收请求的那个网络接口上时,系统才会回复。如果 IP 配置在其他接口上,则忽略请求。 |
| 2 |
严格本地接口匹配 |
只有当 ARP 请求的目标 IP 地址配置在接收请求的那个网络接口上,并且该 IP 地址是该接口的主要地址时,才会回复。这适用于子网划分或配置了多个别名 IP 的情况。 |
| 3-8 |
(其他特殊模式) |
通常用于更复杂的场景,例如仅回复本地链路的请求等。 |
防止 ARP 欺骗或在**高可用性(HA)**集群(如 Keepalived/LVS/HAProxy 提供的 VIP)中,防止多个节点同时对 VIP 的 ARP 请求进行响应,导致网络混乱。通常在 LVS DR(直接路由)模式中,将 VIP 配置在 lo:0 接口上时,为防止内核通过物理接口(如 eth0)响应 VIP 的 ARP 请求,常将此值设为 1 或 2。
net.ipv4.conf.all.arp_announce (发送 ARP 请求/响应)
该参数定义了系统在尝试进行 ARP 广播(即发送 ARP 请求或响应)时,选择哪个源 IP 地址进行声明的策略。
- 路径:
/proc/sys/net/ipv4/conf/all/arp_announce
- 作用:控制系统如何选择 ARP 请求或响应报文中的源 IP 地址。
| 值 |
策略 |
描述 |
| 0 (默认) |
任意 IP |
允许在任何网络接口上,使用系统上的任何本地 IP 地址作为 ARP 报文的源 IP 地址。 |
| 1 |
最佳本地 IP |
尝试选择一个合适的本地 IP 地址作为源地址: 1. 优先使用与目标 IP 在同一子网的 IP 地址。 2. 如果没有同子网 IP,则退回到使用本地路由表定义的 IP。 |
| 2 |
严格本地 IP |
仅使用与 ARP 报文发送接口源 IP 地址在同一子网的 IP 地址。如果找不到,则使用该接口的主要 IP 地址作为源地址。这是最严格的模式。 |
主要用于有多块网卡或多 IP 地址的设备。
- 设为 0 可能导致系统使用错误的源 IP 发送 ARP 报文,造成连接问题。
- 在配置了 VIP 的高可用性集群中,通常会将其设置为 2,以确保 ARP 广播只宣布与发出接口相关的 IP 地址,防止 VIP 漂移(IP Migration)时,新的主节点立即被识别,而旧的节点不再干扰。
配置方式
修改参数通常是通过编辑 /etc/sysctl.conf 文件并执行 sysctl -p 命令使其生效:
# 修改所有接口的设置
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
# 此外,通常也会针对特定接口和默认配置进行设置:
# 例如:
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.eth0.arp_announce = 2
# 执行命令使配置立即生效
sysctl -p
net.ipv6.conf.all.disable_ipv6 / net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.all.disable_ipv6 和 net.ipv6.conf.default.disable_ipv6 是用于控制 Linux 内核中 IPv6 功能启用或禁用的参数。
禁用 IPv6 的主要原因包括:
- 安全加固: 某些环境中可能不使用 IPv6,禁用它可以减少潜在的攻击面。
- 兼容性或调试: 避免 IPv6 流量对仅支持 IPv4 的服务或应用程序造成干扰,或解决一些网络配置的复杂性问题。
| 参数名 |
路径 |
作用范围 |
描述 |
net.ipv6.conf.all.disable_ipv6 |
/proc/sys/net/ipv6/conf/all/disable_ipv6 |
所有网络接口 |
用于全局控制所有现有和未来网络接口上的 IPv6 功能。 |
net.ipv6.conf.default.disable_ipv6 |
/proc/sys/net/ipv6/conf/default/disable_ipv6 |
默认设置 |
用于设置系统上所有新创建的网络接口(如新添加的网卡、虚拟接口等)的默认 IPv6 状态。 |
这两个参数都接受以下值:
| 值 |
状态 |
含义 |
| 0 (默认) |
启用 (Enabled) |
IPv6 在对应接口上被激活。 |
| 1 |
禁用 (Disabled) |
IPv6 在对应接口上被禁用。 |
当修改 IPv6 禁用设置时,需要理解它们之间的关系:
default 设置影响未来接口。
all 设置通常会影响所有现有接口,但它的设置可能会被具体的接口设置(例如 net.ipv6.conf.eth0.disable_ipv6)覆盖。
- 同时设置
net.ipv6.conf.all.disable_ipv6 = 1 和 net.ipv6.conf.default.disable_ipv6 = 1 是彻底禁用 IPv6 的标准做法。这确保了当前所有接口和未来新创建的接口都禁用了 IPv6。
要永久禁用 IPv6,需编辑 /etc/sysctl.conf 文件并执行 sysctl -p:
# /etc/sysctl.conf 文件内容
# 禁用所有接口的 IPv6
net.ipv6.conf.all.disable_ipv6 = 1
# 禁用未来所有新接口的 IPv6
net.ipv6.conf.default.disable_ipv6 = 1
# 执行命令使配置立即生效
sysctl -p
注意: 对于一些较新的 Linux 发行版或内核版本,禁用 IPv6 可能需要重启系统才能完全生效,尤其是当 IPv6 功能已经深度集成到启动过程中时。
net.ipv4.conf.all.rp_filter
net.ipv4.conf.all.rp_filter 是一个 Linux 内核参数,用于控制**反向路径过滤(Reverse Path Filtering,简称 RPF)**的行为。
主要作用:
该机制旨在防止 **IP 地址欺骗(IP Spoofing)**攻击,方法是检查接收到的数据包的源地址是否合法,即系统是否会通过接收该数据包的接口将响应发送回源地址。
参数位置:
这个参数可以在 /proc/sys/net/ipv4/conf/all/rp_filter 文件中查看和修改。
all:表示对所有网络接口(interface)应用该设置。
- 除了
all 之外,还可以针对特定的网络接口进行设置,例如 net.ipv4.conf.eth0.rp_filter 或 net.ipv4.conf.default.rp_filter(对新接口的默认设置)。
可能的值及其含义(通常):
| 值 |
模式 |
描述 |
| 0 |
关闭 (No source validation) |
不进行源地址验证。数据包将照常接受。 |
| 1 |
严格模式 (Strict mode - RFC3704) |
对每个收到的数据包,检查其源地址在路由表中是否存在最佳反向路径指向该数据包进入的接口。如果不是,则丢弃该数据包。(推荐用于安全加固) |
| 2 |
松散模式 (Loose mode - RFC3704) |
对每个收到的数据包,检查其源地址是否可以通过系统上的任何接口到达(即源地址可路由)。如果不可达,则丢弃数据包。(推荐用于存在非对称路由的情况) |
详细解释:
- 严格模式 (1):要求传入数据包的源地址,其返回路径(即通过路由查找)必须与数据包进入的接口一致。这可以有效防止源地址欺骗,但可能会破坏**非对称路由(Asymmetric Routing)**环境下的合法流量(数据包从一个接口进入,但应从另一个接口传出响应)。
- 松散模式 (2):只要数据包的源地址是可路由的(即路由表中有到达该源地址的任何路径),即使该路径不经过数据包进入的接口,也会接受该数据包。这在非对称路由的环境中更加宽容。
建议:
- 在大多数标准和安全的配置中,为了防止 IP 欺骗,通常建议将
net.ipv4.conf.all.rp_filter 和 net.ipv4.conf.default.rp_filter 设置为 1(严格模式)。
- 如果在复杂的网络环境(例如负载均衡、策略路由、非对称路由)中遇到通信问题,可能需要检查并考虑将其设置为 2(松散模式)或 0(关闭),但这会降低系统的安全性。通常,在云环境中如果使用了负载均衡等服务,可能需要将相关参数设置为 0 以避免冲突。
net.ipv4.ip_forward
net.ipv4.ip_forward 是一个 Linux 内核参数,用于控制系统是否启用 **IP 转发(IP Forwarding)**功能。
-
核心介绍
- 路径:
/proc/sys/net/ipv4/ip_forward
- 作用:控制 Linux 系统是否可以充当路由器(Router)或网关(Gateway),将数据包从一个网络接口接收,并根据路由表转发到另一个网络接口。
- 默认值:在大多数 Linux 发行版中,默认值为
0 (禁用)。
-
参数值及其含义
| 值 |
状态 |
描述 |
| 0 |
禁用 (Disabled) |
系统不会转发不以本机为目的地的 IP 数据包。收到的数据包如果目的地不是本机 IP,内核会直接丢弃。(标准主机模式) |
| 1 |
启用 (Enabled) |
系统会检查收到的数据包的目的 IP 地址。如果目的 IP 不是本机 IP,系统会根据其路由表(Routing Table)尝试将数据包转发到合适的出站接口。(路由器/网关模式) |
启用 net.ipv4.ip_forward = 1 的场景通常包括:
- 路由器/网关:将 Linux 服务器用作连接两个或多个不同网络(如内网和外网)的设备。
- NAT(网络地址转换):实现 SNAT (Source NAT) 或 DNAT (Destination NAT),例如使用 iptables 实现公网 IP 共享上网。
- VPN 服务器:作为 VPN 流量的隧道端点,并负责将流量转发到内网。
- LVS/HAProxy 等负载均衡器:在某些配置模式(如 NAT 模式)下,需要启用 IP 转发。
- 容器/虚拟化环境:宿主机需要转发容器或虚拟机之间的网络流量。
要启用 IP 转发,通常需要修改配置文件 /etc/sysctl.conf,以实现永久生效:
-
编辑配置文件 /etc/sysctl.conf:
# 确保以下配置项的值为 1
net.ipv4.ip_forward = 1
-
应用配置:
执行以下命令使配置立即生效:
也可以使用 sysctl -w 或直接写入 /proc 文件来临时启用(重启后失效):
# 临时启用
echo 1 > /proc/sys/net/ipv4/ip_forward
# 或
sysctl -w net.ipv4.ip_forward=1
注意: 启用 IP 转发后,系统就具备了路由能力,因此必须配合**防火墙(如 Iptables 或 firewalld)**进行安全配置,以限制哪些流量可以被转发,防止不必要的网络访问和安全风险。
net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries 是一个 Linux 内核参数,用于控制 TCP 客户端在发送 SYN 报文后,如果未收到 SYN-ACK 报文时,进行重试的最大次数。
- 目的:
- 处理网络拥塞或暂时性故障,确保连接建立。
- 防止客户端无限期等待一个无法建立的连接。
- 默认值与影响:
- 不同的 Linux 发行版和内核版本可能有不同的默认值,但常见的值可能是 5 或 6。
- 默认为
6,链接超时时间(connect timeout) 为 127s(=2^0 + 2^1 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6)。
- 例如,在某些配置中,如果
net.ipv4.tcp_syn_retries 设置为 4:
- 在初始超时重传值为 1 秒的情况下,进行 4 次重传大约需要 15 秒,最终连接超时大约需要 31 秒。
- 计算超时时间(大致): 每次重传的超时时间会以指数形式增长(1s, 2s, 4s, 8s, …),所以重试次数越多,客户端等待连接建立的总时间就越长。
- 低值: 更快地判断目标不可达,释放资源,但可能错过网络暂时性抖动后恢复的机会。
- 高值: 增加连接建立成功的可能性,但会延长客户端等待连接超时的时间。
如何查看和修改:
注意: 另一个相关的内核参数是 net.ipv4.tcp_synack_retries,它控制的是 服务器端 在收到 SYN 包后,发送 SYN-ACK 报文并等待客户端 ACK 时,重试发送 SYN-ACK 的最大次数。tcp_syn_retries 影响的是客户端的行为。
net.ipv4.tcp_tw_recycle
tcp_tw_recycle 用于快速回收处于 TIME_WAIT 状态的 TCP 连接,但会导致 NAT 或时间不对时,出现连接建立不成功,卡在 SYN-SENT,2017 年 5 月已经从内核移除,参考
net.ipv4.tcp_keepalive_time
F&Q
Linux SYNs 包异常丢弃导致网络时断时续排查
使用 netstat 命令,查看网卡 syn/passive 的统计情况
[root@x ~]# netstat -s | grep -i syn
1523045 invalid SYN cookies received
46862 resets received for embryonic SYN_RECV sockets
1962353 SYNs to LISTEN sockets dropped
TCPSYNChallenge: 1874
TCPSynRetrans: 687620
TCPACKSkippedSynRecv: 18169
[root@x ~]# netstat -s | grep -i overflow
[root@x ~]#
[root@x ~]# netstat -s | grep -i passive
80469203 passive connection openings
1962935 passive connections rejected because of time stamp
SYNs to LISTEN sockets dropped 和 passive connections rejected because of time stamp 相差不大
将 /proc/sys/net/ipv4/tcp_tw_recycle 修改为 0,drop 情况就不发生
net.ipv4.tcp_tw_recycle = 1 表示开启 TCP 连接中 TIME-WAIT sockets 的快速回收,默认为0,表示关闭
- 修改方法如下
临时配置:
echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle
永久配置:
$ vim /etc/sysctl.conf
net.ipv4.tcp_tw_recycle = 0
生效
sysctl -p
failed to create fsnotify watcher: too many open files
超过了系统默认的 fs.inotify.max_user_instances=128,调整如下
sudo sysctl fs.inotify.max_user_instances=8192
echo fs.inotify.max_user_instances=8192| tee -a /etc/sysctl.conf && sudo sysctl -p