最近我在 Linux 启动序列中遇到了另一个有趣的问题,这个问题有一个规避方法,但不是解决方案。它开始得非常出乎意料。
我当时正在写几篇文章,同时更新我的个人系列书籍《使用和管理 Linux:从零到系统管理员》。我打开了四个 LibreOffice Writer 实例来做这些事情。我运行了三个 VirtualBox 虚拟机来测试我正在写的一些内容。我还打开了 LibreOffice Impress 来处理一个不相关的演示文稿。我喜欢听音乐,所以我打开了 Firefox 中的几个标签页,其中一个打开了 Pandora,我选择的音乐流媒体服务。我打开了多个 Bash shell,使用 Konsole,其中有许多标签页,其中一个标签页运行着 Alpine 文本模式电子邮件客户端。然后还有 Thunar 文件管理器中的各种标签页。
所以当时我有很多事情要做。就像我现在写这篇文章一样。
症状
当我在使用这些打开的会话时,我注意到在等待系统将文档写入 M.3 SSD 时,速度明显减慢,这个过程应该非常快。我还注意到音乐断断续续,每隔几分钟就会完全中断。总体性能普遍较差。我开始认为 Fedora 出现了严重问题。
我当时正在使用的主工作站有 64GB 内存和一颗 Intel Core i9 Extreme 处理器,具有 16 个内核和超线程(32 个 CPU),使用我配置的超频可以以高达 4.1 GHz 的速度运行。所以我不应该遇到任何速度减慢的情况——或者我当时是这么认为的。
确定问题
我很快就找到了问题,因为我之前在内存少得多的系统上遇到过类似的症状。这个问题看起来像是由于页面交换导致的延迟。但为什么呢?
我从我常用的问题确定工具 htop 开始。它显示系统正在为程序使用 13.6GB 的内存,而大部分剩余的 RAM 都在缓存和缓冲区中。它还显示正在积极进行交换,并且大约有 253MB 的数据存储在交换分区中。
Date & Time: 2022-08-12 10:53:08
Uptime: 2 days, 23:47:15
Tasks: 200, 1559 thr, 371 kthr; 4 running
Load average: 3.97 3.05 2.08
Disk IO: 202.6% read: 687M write: 188K
Network: rx: 0KiB/s tx: 0KiB/s (0/0 packets)
Systemd: running (0/662 failed) (0/7912 jobs)
Mem[|||||||##*@@@@@@@@@@@@@@@@@@@@@@@@@@ 13.6G/62.5G]
Swp[||# 253M/18.0G]
但这意味着我仍然有大量的剩余内存,系统可以直接用于程序和数据,并且可以从缓存和缓冲区中恢复更多内存。那么为什么这个系统还要进行交换呢?
我记得在我的一个 Red Hat 培训课程 中听到过关于“swappiness”因子的内容。但那是很久以前的事了。我搜索了一些关于“swappiness”的内容,以了解内核设置 vm.swappiness。
此内核参数的默认设置为 60。这个数字是一个抽象值,表示内核尝试交换的积极程度。与常见的但错误的理解(包括我在修改本文之前的理解)相反,这个数字并不代表 RAM 的百分比。vm.swappiness 的值在一个公式中使用,该公式确定 Linux 内核执行交换的多个方面。
根据我的在线阅读,我发现对于许多具有大量 RAM 的 Linux 系统,10% 是 vm.swappiness 的更好值。我检查了我系统上当前的 swappiness 设置,它被设置为默认值。
# sysctl vm.swappiness
vm.swappiness = 60
是时候更改这个内核设置了。
修复问题
我不会深入探讨细节,但最重要的是,以下任一命令以 root 身份运行,都可以在运行中的 Linux 计算机上立即完成这项工作,无需重启。
# sysctl -w vm.swappiness=10
您也可以使用以下命令执行相同的操作。
# echo 10 > /proc/vm/swappiness
Tecmint 有一篇关于设置内核参数的优秀文章。
这两个命令都会更改 /proc
文件系统中的实时内核设置。运行任一命令后,您应该运行 sysctl vm.swappiness
命令来验证内核设置是否已更改。
但这些命令仅更改当前运行系统的 swappiness 值。重启会将值恢复为默认值。我需要确保此更改在重启后仍然有效。
但首先,是失败
为了永久更改内核 vm.swappiness 变量,我使用了我之前的文章 如何在 Linux 上禁用 IPv6 中描述的步骤,将以下行添加到 /etc/default/grub
文件的末尾
GRUB_CMDLINE_LINUX="vm.swappiness=1"
然后,我以 root 身份运行 grub2-mkconfig
命令来重建 /boot/grub2/grub.cfg
文件。但是,使用虚拟机和真实硬件进行的测试表明,它不起作用,并且 swappiness 值没有改变。所以我尝试了另一种方法。
以及成功
由于启动时的这次失败,我在《如何在 Linux 上禁用 IPv6》文章中描述的失败,以及由于遇到这两次失败而探索的其他启动问题,我断定这是一个 Linux 启动时序问题。换句话说,一些必需的服务,其中一个可能是网络本身,没有启动并运行,这阻止了这些内核选项更改被提交到 /proc
文件系统,或者它们被提交后在服务启动时被覆盖。
我可以将所有这些都添加到新文件 /etc/sysctl.d/local-sysctl.conf
中,并包含以下内容,其中包括我所有的本地内核选项更改,从而使它们像应该的那样工作
###############################################
# local-sysctl.conf #
# #
# Local kernel option settings. #
# Install this file in the /etc/sysctl.d #
# directory. #
# #
# Use the command: #
# sysctl -p /etc/sysctl.d/local-sysctl.conf #
# to activate. #
# #
###############################################
###############################################
# Local Network settings #
# Specifically to disable IPV6 #
###############################################
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
###############################################
# Virtual Memory #
###############################################
# Set swappiness
vm.swappiness = 1
然后,我运行了以下命令,该命令仅激活指定文件中的内核选项
# sysctl -p /etc/sysctl.d/local-sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
vm.swappiness = 13
这是一种比我在关于禁用 IPv6 的文章中使用的更具针对性的设置内核选项的方法。
报告错误
在撰写本文时,对于此问题的根本原因(无论原因是什么)还没有真正的修复方法。在提供修复程序之前,有一种临时规避该问题的方法。我使用了我为测试创建的 /etc/sysctl.d/local-sysctl.conf
文件,并添加了一个 systemd 服务,使其在启动序列结束时运行,等待几秒钟,然后对该新文件运行 sysctl
。有关如何执行此操作的详细信息,请参阅《如何在 Linux 上禁用 IPv6》文章。
在尝试禁用 IPv6 时,我已经使用 Red Hat 的 Bugzilla 将此问题报告为 bug 2103517。我将这些新信息添加到该 bug 中,以确保内核开发人员可以使用我的最新发现。
您可以点击 链接查看错误报告。您无需帐户即可查看错误报告。
最后的想法
在实验以了解我能多好地重现症状以及许多其他症状之后,我确定 vm.swappiness 设置 60 对于许多大内存 Linux 系统来说过于激进。如果没有比我自己的计算机更多的数据点,我只能初步得出结论,具有大量 RAM 但使用频率不高的系统是此问题的主要受害者。
解决本地内核选项设置不起作用问题的直接方法是在启动后设置它们。我实现的自动化是如何使用 systemd 替换旧的 SystemV 启动文件 rc.local
的一个很好的例子。
此错误以前未被报告。我花了几天时间进行实验,以验证本地设置的内核选项在启动时未被设置或保留的普遍问题在多个物理和虚拟系统上很容易重现。在那个时候,我觉得报告这个错误以确保它得到修复很重要。报告它是我回馈 Linux 社区的另一种方式。
评论已关闭。