sysctl

出自 ArchWiki

sysctl 是一个用于在运行时检查和更改内核参数的工具。 sysctl 在 procfs 中实现,procfs 是位于 /proc/ 的虚拟进程文件系统。

安装

procps-ng 软件包应该已经安装,因为它是一个base 元软件包的依赖项。

配置

sysctl 预加载/配置文件可以在 /etc/sysctl.d/99-sysctl.conf 创建。对于 systemd/etc/sysctl.d//usr/lib/sysctl.d/ 是内核 sysctl 参数的 drop-in 目录。命名和源目录决定了处理顺序,这很重要,因为最后处理的参数可能会覆盖较早的参数。例如,/usr/lib/sysctl.d/50-default.conf 中的参数将被 /etc/sysctl.d/50-default.conf 和稍后从两个目录处理的任何配置文件中的相同参数覆盖。

要手动加载所有配置文件,执行

# sysctl --system 

这也将输出应用的层级结构。也可以使用以下命令显式加载单个参数文件

# sysctl --load=filename.conf

有关更多信息,请参阅 the new configuration files,更具体地说是 sysctl.d(5)

可用的参数是 /proc/sys/ 下列出的参数。例如,kernel.sysrq 参数指的是文件系统上的 /proc/sys/kernel/sysrq 文件。 sysctl --all 命令可以用来显示所有当前可用的值。

注意: 如果您安装了内核文档(linux-docs),您可以在 /usr/lib/modules/$(uname -r)/build/Documentation/admin-guide/sysctl/ 中找到关于 sysctl 设置的详细信息。在线版本请参考本文的 #参见 部分。强烈建议在更改 sysctl 设置之前阅读这些文档。

可以通过文件操作或使用 sysctl(8) 实用程序来更改设置。例如,要临时启用 magic SysRq key

# sysctl kernel.sysrq=1

# echo "1" > /proc/sys/kernel/sysrq 

有关 kernel.sysrq 的详细信息,请参阅 Linux 内核文档

要在重启之间保留更改,请在 /etc/sysctl.d/99-sysctl.conf/etc/sysctl.d/ 中的另一个适用的参数文件中添加或修改相应的行。

提示: 某些可以应用的参数可能取决于内核模块,而内核模块又可能未加载。例如,/proc/sys/net/bridge/* 中的参数取决于 br_netfilter 模块。如果它在运行时(或重启后)未加载,则这些参数将静默地不被应用。请参阅 内核模块

安全

另请参阅 Security#内核加固,以及本文的其余部分。

网络

提升性能

增加接收队列的大小。

接收到的帧将在从网卡上的环形缓冲区取出后存储在这个队列中。

对于高速网卡,增加这个值可能有助于防止丢包

net.core.netdev_max_backlog = 16384
注意: 在像 SIP 路由器这样的实时应用中,这个选项需要高速 CPU,否则队列中的数据将会过时。

增加最大连接数

内核将接受的最大连接数上限(默认为 4096)

net.core.somaxconn = 8192
警告: 增加这个值可能只会在高负载的服务器上提高性能,并可能导致处理速度缓慢(例如,单线程阻塞服务器)或工作线程/进程数量不足 [1]

增加分配给网络接口的内存

本文或章节需要扩充。

原因: 解释每个选项的单位是什么(字节、千字节还是内存页?) (在 Talk:Sysctl 中讨论)

本文或章节的factual accuracy存在争议。

原因: 本节似乎受 Cloudflare 博客文章的启发,但 Red Hat 的 tuned profile 建议甚至更小的值,并声称“这似乎只在 40Gb 速度下才必要”。因此,这些设置对于普通硬件似乎没有用。(在 Talk:Sysctl 中讨论)

Linux 网络堆栈的默认配置不适用于跨 WAN 链路的高速大文件传输(即处理更多的网络数据包),设置正确的值可以节省内存资源

net.core.rmem_default = 1048576
net.core.rmem_max = 16777216
net.core.wmem_default = 1048576
net.core.wmem_max = 16777216
net.core.optmem_max = 65536
net.ipv4.tcp_rmem = 4096 1048576 2097152
net.ipv4.tcp_wmem = 4096 65536 16777216

也可以增加默认的 4096 UDP 限制

net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192

有关更多信息和推荐值,请参阅以下来源

启用 TCP Fast Open

本文或章节需要扩充。

原因: 提及“默认启用所有监听器以支持 Fast Open,而无需显式的 TCP_FASTOPEN 套接字选项”的选项,即值 1027 (0x1+0x2+0x400)。 (在 Talk:Sysctl#TCP Fast Open 中讨论)

TCP Fast Open 是传输控制协议 (TCP) 的扩展,通过允许在发送方的初始 TCP SYN 期间交换数据来帮助减少网络延迟 [2]。使用值 3 而不是默认值 1 允许 TCP Fast Open 用于传入和传出连接

net.ipv4.tcp_fastopen = 3

调整待处理连接处理

tcp_max_syn_backlog 是待处理连接“等待确认”的最大队列长度。

在发生 synflood DOS 攻击时,这个队列会很快被填满,此时 TCP SYN cookies 将会启动,允许您的系统继续响应合法的流量,并允许您访问以阻止恶意 IP。

如果服务器在高峰时段遭受过载,您可能需要稍微增加这个值

net.ipv4.tcp_max_syn_backlog = 8192

tcp_max_tw_buckets 是 TIME_WAIT 状态下套接字的最大数量。

达到这个数字后,系统将开始销毁处于此状态的套接字。

增加此值以防止简单的 DOS 攻击

net.ipv4.tcp_max_tw_buckets = 2000000

tcp_tw_reuse 设置 TCP 是否应该为新的传出连接重用 TIME-WAIT 状态下的现有连接,如果新时间戳严格大于先前连接记录的最新时间戳。

默认值为 2,表示仅对环回连接启用。您可以将其设置为 1 以对所有连接启用,这有助于避免耗尽可用的网络套接字

net.ipv4.tcp_tw_reuse = 1

指定在强制关闭套接字之前等待最终 FIN 数据包的秒数。这严格来说违反了 TCP 规范,但为了防止拒绝服务攻击是必需的。在 Linux 2.2 中,默认值为 180 [3]

net.ipv4.tcp_fin_timeout = 10

tcp_slow_start_after_idle 设置 TCP 是否应该仅对新连接以默认窗口大小启动,还是也对已空闲时间过长的现有连接以默认窗口大小启动。

此设置会降低持久性单连接性能,可以将其关闭

net.ipv4.tcp_slow_start_after_idle = 0

更改 TCP keepalive 参数

TCP keepalive 是一种 TCP 连接机制,有助于确定另一端是否已停止响应。 TCP 将在空闲一段时间后多次向网络对等方发送包含空数据的 keepalive 探测包。如果对等方没有响应,套接字将自动关闭。默认情况下,TCP keepalive 进程等待两个小时(7200 秒)的套接字活动,然后发送第一个 keepalive 探测包,然后每 75 秒重新发送一次。只要存在正在进行的和活动的 TCP/IP 套接字通信,就不需要 keepalive 数据包。

注意: 使用以下设置,您的应用程序将在 120 秒后(60 秒 + 10 秒 + 10 秒 + 10 秒 + 10 秒 + 10 秒 + 10 秒)检测到死 TCP 连接。
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6

启用 MTU 探测

最大传输单元 (MTU) 越长,性能越好,但可靠性越差。

这是因为丢失的数据包意味着更多的数据需要重新传输,并且因为 Internet 上的许多路由器无法传递非常长的数据包

net.ipv4.tcp_mtu_probing = 1

有关更多信息,请参阅 https://blog.cloudflare.com/path-mtu-discovery-in-practice/

TCP 时间戳

警告: TCP 时间戳可防止(在千兆速度下)序列号回绕和 TCP 中实现的往返时间计算。不建议关闭 TCP 时间戳,因为它可能会导致安全风险 [4]

禁用时间戳生成将减少峰值,并可能在千兆网络上提高性能

net.ipv4.tcp_timestamps = 0

TCP 选择性确认

TCP 选择性确认 (TCP SACK) 由布尔值 tcp_sack 控制,允许接收方提供有关丢失段的更多详细信息给发送方,从而减少重传量。这在​​高延迟网络上很有用,但在高速 LAN 上禁用它可以提高吞吐量。如果您不发送 SACK,也请禁用 tcp_dsack,您当然不想发送重复项!前向确认在 SACK 之上工作,如果禁用 SACK,它也将被禁用。 [5]

net.ipv4.tcp_sack = 1

启用 BBR

BBR 拥塞控制算法可以帮助互联网流量实现更高的带宽和更低的延迟。首先,加载 tcp_bbr 模块。

注意: BBR GitHub 说,“这不是 Google 官方产品。”
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr

增加临时端口范围

本文或章节的factual accuracy存在争议。

原因: 这种更改如何提高性能? (在 Talk:Sysctl#talk:sysctl#net.ipv4.ip_local_port_range 中讨论)

Wikipedia:临时端口 通常被传输控制协议 (TCP)、用户数据报协议 (UDP) 或流控制传输协议 (SCTP) 用作客户端 - 服务器通信的客户端端的端口分配。

net.ipv4.ip_local_port_range = 30000 65535

TCP/IP 协议栈加固

以下指定了一组参数,用于加强内核的 IPv4 协议的网络安全选项以及存在等效项的 IPv6 相关参数。

对于某些用例,例如将系统用作 路由器,其他参数也可能有用或必要。

TCP SYN Cookie 保护

有助于防止 SYN 洪水攻击。仅在达到 net.ipv4.tcp_max_syn_backlog 时启动。更多详情请见,例如,[6]。截至 linux 5.10,默认情况下已设置。

net.ipv4.tcp_syncookies = 1

TCP rfc1337

本文或章节的factual accuracy存在争议。

原因: 这似乎不是 TCP 标准的一部分?描述可能不准确。 [7] (在 Talk:Sysctl#net.ipv4.tcp_rfc1337 中讨论)

防止 tcp time-wait 刺杀危害,丢弃 time-wait 状态下套接字的 RST 数据包。在 Linux 之外没有得到广泛支持,但符合 RFC

net.ipv4.tcp_rfc1337 = 1

反向路径过滤

通过启用反向路径过滤,内核将对从机器上所有接口接收的数据包进行源验证。这可以防止攻击者使用 IP 欺骗方法进行攻击。

内核的默认值为 0(无源验证),但 systemd 发布了 /usr/lib/sysctl.d/50-default.conf,它将 net.ipv4.conf.all.rp_filter 设置为 2(宽松模式)[8]

以下命令将反向路径过滤机制设置为值 1(严格模式)

net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1

net.ipv4.conf.default.*net.ipv4.conf.interface.*net.ipv4.conf.all.* 的关系和行为在 ip-sysctl.html 中进行了解释。

记录火星包

火星包是一个 IP 数据包,它指定了互联网号码分配机构 (IANA) 保留用于特殊用途的源地址或目标地址。 有关更多详细信息,请参阅 保留 IP 地址

通常,火星包和不可路由的数据包可能被用于危险目的。记录这些数据包以供进一步检查可能很有用 [9]

net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.all.log_martians = 1
注意: 这可能会用大量信息填满您的日志,建议仅在测试时启用此功能。

禁用 ICMP 重定向

背景信息请见 什么是 ICMP 重定向?应该阻止它们吗?

禁用 ICMP 重定向接受

net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

在非路由器上禁用 ICMP 重定向发送

net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

忽略 ICMP 回显请求

禁用 ICMP 回显(又名 ping)请求

net.ipv4.icmp_echo_ignore_all = 1
net.ipv6.icmp.echo_ignore_all = 1
注意: 请注意,这可能会导致监控工具和/或依赖 ICMP 回显响应的应用程序出现问题。

其他

允许非特权用户创建 IPPROTO_ICMP 套接字

本文或章节已过时。

原因: /usr/lib/sysctl.d/50-default.confnet.ipv4.ping_group_range 设置为 0 2147483647。(在 Talk:Sysctl 中讨论)

IPPROTO_ICMP(icmp(7))套接字类型增加了发送 ICMP_ECHO 消息和接收相应的 ICMP_ECHOREPLY 消息的可能性,而无需打开 raw(7) 套接字,该操作需要 CAP_NET_RAW capability 或具有适当特权所有者的 SUID 位。 这些 ICMP_ECHO 消息由 ping 应用程序发送,因此除了 ICMP Echo 套接字之外,IPPROTO_ICMP 套接字也称为 ping 套接字。

ping_group_range 确定允许其用户创建 IPPROTO_ICMP 套接字的组的 GID 范围。 此外,CAP_NET_RAW capability 的所有者也被允许创建 IPPROTO_ICMP 套接字。 默认情况下,此范围为 1 0,这意味着除了 root 用户外,任何人都不能创建 IPPROTO_ICMP 套接字。 为了利用此设置,当前使用原始套接字的程序需要移植为使用 IPPROTO_ICMP 套接字。 例如,QEMU 对 SLIRP(又名用户模式网络)使用 IPPROTO_ICMP,因此允许运行 QEMU 的用户创建 IPPROTO_ICMP 套接字意味着可以从访客操作系统 ping。

要仅允许 GID 为 100 的组成员用户创建 IPPROTO_ICMP 套接字

net.ipv4.ping_group_range = 100 100

要允许系统中所有用户创建 IPPROTO_ICMP 套接字

net.ipv4.ping_group_range = 0 65535

虚拟内存

有几个关键参数可以调整 Linux 内核虚拟内存子系统的操作以及将脏数据写出到磁盘的操作。 有关更多信息,请参阅官方 Linux 内核文档。 例如

  • vm.dirty_ratio = 10
包含可用内存(包含空闲页和可回收页)总量的百分比,该百分比表示生成磁盘写入的进程将自身开始写出脏数据的页数。
  • vm.dirty_background_ratio = 5
包含可用内存(包含空闲页和可回收页)总量的百分比,该百分比表示后台内核刷新线程将开始写出脏数据的页数。

正如参数的注释中所述,在设置这些值时需要考虑 RAM 总量。 例如,通过简化,采用已安装的系统 RAM 而不是可用内存

警告
  • 较高的比率值可能会提高性能,但也会增加数据丢失的风险。
  • 将此值设置为 0 可能会导致磁盘延迟增加和峰值。

有关更多信息,请参阅 https://lonesysadmin.net/2013/12/22/better-linux-disk-caching-performance-vm-dirty_ratio/

  • 共识是,如果 RAM 为 1 GB(因此 10% 为 100 MB),则将 vm.dirty_ratio 设置为 RAM 的 10% 是一个合理的数值。 但是,如果机器具有更多的 RAM,例如 16 GB(10% 为 1.6 GB),则该百分比可能会不成比例,因为它在机械硬盘上会变成几秒钟的回写。 在这种情况下,更合理的数值可能是 3(16 GB 的 3% 大约是 491 MB)。
  • 类似地,将 vm.dirty_background_ratio 设置为 5 对于小内存值可能很好,但同样,请考虑并根据特定系统上的 RAM 量进行调整。

VFS 缓存

降低虚拟文件系统 (VFS) 缓存参数值可能会提高系统响应速度

  • vm.vfs_cache_pressure = 50
该值控制内核回收用于目录和 inode 对象缓存(VFS 缓存)的内存的趋势。 从默认值 100 降低它会使内核不太倾向于回收 VFS 缓存(不要将其设置为 0,这可能会导致内存不足的情况)。

MDADM

请参阅 RAID#更改同步速度限制

故障排除

系统周期性小卡顿

将脏字节设置为足够小的值(例如 4M)

vm.dirty_background_bytes = 4194304
vm.dirty_bytes = 4194304
注意: dirty_background_bytesdirty_bytes 参数是 dirty_background_ratiodirty_ratio 的对应参数(如#虚拟内存中所见)。 一次只能指定其中一个参数。

参见