手上一台虚拟机,内存 1G。最近 Debian 发布了新版本 12 bookworm,顺手将系统升级到了最新。升级后遇到了两个问题,一个是总内存变小,另一个是开机时间长达 2 分多钟,记录下排查过程。
如果你想要升级的话,建议升级之前先看看官方的发行说明以及其中的从 Debian 11(bullseye)升级章节的内容。
升级后总内存变小
升级前的机器看起来是这样的:
1 | free -h |
升级后一开始检查情况的时候一切正常,直到顺手输入 free -h
想要检查一下内存使用情况的时候,看到的是如下情况:
1 | free -h |
本就不富余的总可用内存更显得捉襟见肘,总可用内存仅剩下 800M。这就令人十分费解,按理来说升级上来的系统,所有的配置基本上都是保持不变的,不应该出现这么重大的变化。此外总内存减少了 163M,这对于一台 1G 内存的机器着实是有点多。
既然是不可用的内存减少了,怀疑的方向就是内核是不是保留了更多的内存导致的。
1 | kernel 6.1 |
从 dmesg
中内存相关的信息来看,reserved
的部分从 93916K 增长到了 267060K,比较像是减少的部分,搜索相关信息得到:
Reserved 内存主要包括 initrd、初始化代码 init、内核代码及数据(内核数据是动态变化的,这里所说的是引导阶段截至 mem_init 为止所产生的数据,包括存放页描述符 struct page 的 mem_map[] 数组等)。注:initrd 和初始化代码 init 在引导完成之后会被释放掉,所以最终的可用内存会比 dmesg 显示的 available 更多一点。
由于这边说引导完成后会有部分内存被释放掉,也不确定释放的量,就暂且不再往下研究。
既然可能是内核相关的,就先试试安装不同版本的内核进行测试:
系统版本 | 内核版本 | 总内存 |
---|---|---|
Debian 11 | 5.10 | 963M |
Debian 11 | 6.1 | 800M |
Debian 12 | 5.10 | 963M |
Debian 12 | 6.1 | 800M |
从测试结果来看,和系统版本无关,和内核版本相关。那就先检查一下内存参数看看,参数在升级前后没有变化:
1 | BOOT_IMAGE=/boot/vmlinuz-5.10.0-23-amd64 root=UUID=412ea946-3c1f-4322-b5b6-a1c729be1634 ro vga=792 console=tty0 console=ttyS0,115200n8 net.ifnames=0 noibrs crashkernel=0M-1G:0M,1G-4G:160M,4G-8G:192M,8G-128G:384M,128G-:512M crash_kexec_post_notifiers iommu=pt nvme_core.io_timeout=4294967295 nvme_core.admin_timeout=4294967295 quiet |
其中一个参数比较可疑:crashkernel=0M-1G:0M,1G-4G:160M,4G-8G:192M,8G-128G:384M,128G-:512M
。
crashkernel 用来配置 Kexec 启动的第二个 kernel(crash kernel),即用来捕获第一个 kernel crash dump 的 kernel 的大小和位置。
这个参数中值得注意的是配置了 1G-4G:160M
,这个和升级后减少的内存量 163M 比较接近,同时机器的 1G 内存正好卡在 0M-1G
和 1G-2G
中间的临界点,有可能是内核哪里做了调整导致变化,那就顺着 crashkernel 这个线索继续往下看。
新起一台虚拟机,安装 debian 11.7,内核版本 5.10,将 crashkernel 参数分别设置为 0M-1G:0M,1G-2G:160M
和 0M-2G
,重启后观察,总可用内存确实减少了约 160M。
查看 kernel 的文档,crashkernel 在 kdump 部分:
Extended crashkernel syntax
For example:
crashkernel=512M-2G:64M,2G-:128M
This would mean:
- if the RAM is smaller than 512M, then don’t reserve anything (this is the “rescue” case)
- if the RAM size is between 512M and 2G (exclusive), then reserve 64M
- if the RAM size is larger than 2G, then reserve 128M
从内核配置的文档来看,取值范围含低值不含高值,1G 内存的机器按照前文的配置的话应该落到 1G-2G:160M
范围内,但实际看起来落到了 0M-1G:0M
区间从而没有保留内存。
既然这样,就去内核代码库去看看,搜索 crashkernel,时间介于 5.x 和 6.x 内核版本之间,发现这么一个提交:
kdump: round up the total memory size to 128M for crashkernel reservation
在这里似乎一切都说得通了:
When specifying crashkernel=1G-2G:128M, if we have a 1G memory machine, we get total size 1023M from firmware.
Then it will not fall into 1G-2G,thus no memory reserved.
User will never know this, it is hard to let user know the exact total value in kernel.
当指定 crashkernel=1G-2G:128M 时,如果我们有一台 1G 内存的机器,我们将从固件中获取到总内存大小 1023M。
那么它就不会落入 1G-2G 的范围内,因此没有内存被保留。
用户永远不会知道这一点,很难让用户知道内核中确切的总内存值。
引入的解决办法:
One way is to use dmi/smbios to get physical memory size, but it’s not reliable as well.
According to Prarit hardware vendors sometimes screw this up.
Thus round up total size to 128M to work around this problem.
一个获取物理内存大小的办法是使用 dmi/smbios,但它根本不可靠。
据 Prarit 说硬件厂商有时候会把这搞砸。
因此在总大小上再加 128M 来绕过这个问题。
这个补丁被添加进了 v5.19-rc2,而 debian 11 和 12 使用的 5.10 和 6.1 版本内核刚好是在这个版本前和后,同时 1G 内存卡在配置的分界处,同时由于内存小,160M 的内存减少才让人注意到这点差异,这么多因素才促成了这么个发现。
所以解决办法就是:按需调整你的 crashkernel 内核参数设置。
升级后开机时间变长
升级后开机时间变长,长达 2 分多钟才能进入系统。查看具体开机时间和分析:
1 | systemd-analyze time |
发现是 systemd-networkd-wait-online
这个服务一直等到默认超时 120 秒后才进入系统。
当前机器上并未使用 networkd
,同时所有接口也都是 unmanage
状态,按理不应该会有超时。
搜索找到相关 issue,确定是个 bug:
systemd-networkd-wait-online waits undefinitely if no networkd managed interfaces #25813
debian 12 中 systemd 版本是 252.6-1,这个问题在 253 版本中修复:
systemd-networkd-wait-online exits successfully when all interfaces are ready or unmanaged. Previously, if neither ‘–any’ nor ‘–interface=’ options were used, at least one interface had to be in configured state. This change allows the case where systemd-networkd is enabled, but no interfaces are configured, to be handled gracefully. It may occur in particular when a different network manager is also enabled and used.
systemd-networkd-wait-online 在所有接口就绪或未被管理时成功退出。之前如果没有使用“–any”或“–interface=”选项的话,至少需要有一个接口得是已配置状态才退出。
这个更改更优雅地处理 systemd-networkd 启用,但没有接口被配置的状态。这尤其可能发生在不同的网络管理器被启用或使用的情况下。
更新到 253 版本的 systemd
进行测试,开机时间恢复正常:
1 | systemd-analyze time |