Harvester VM OOM 问题排查

Harvester 版本:v1.3.2

问题现象:环境中的 VM 发生 OOM,对应的 virt-launcher Pod 重启。

排查过程

Kernel 中捕获到的 OOM 日志:

1
2
3
4
5
6
7
...
Mar 17 13:06:36 xxx kernel: CPU 1/KVM invoked oom-killer: gfp_mask=0xcc0(GFP_KERNEL), order=0, oom_score_adj=990
Mar 17 13:06:36 xxx kernel: Memory cgroup out of memory: Killed process 15621 (qemu-system-x86) total-vm:17962836kB, anon-rss:15698676kB, file-rss:24744kB, shmem-rss:4kB, UID:107 pgtables:31552kB oom_score_adj:990
...
Mar 20 03:00:55 xxx kernel: virt-launcher invoked oom-killer: gfp_mask=0xcc0(GFP_KERNEL), order=0, oom_score_adj=990
Mar 20 03:00:55 xxx kernel: Memory cgroup out of memory: Killed process 37685 (qemu-system-x86) total-vm:19403216kB, anon-rss:16439716kB, file-rss:24368kB, shmem-rss:4kB, UID:107 pgtables:33732kB oom_score_adj:990
...

CPU 1/KVM 是 qemu-system-x86 进程的一个线程,它向 Guest OS 模拟 vCPU。该日志表示 CPU 1/KVM 线程在执行分配内存操作的时候触发了 OOM;virt-launcher 是一个与 KubeVirt 相关的进程,运行在虚拟机 Pod 的相关 cgroup 中。该日志表示 virt-launcher 进程在分配内存时触发了 OOM。virt-launcher 也在 qemu-system-x86 进程中运行,所以 Kernel 日志中记录的触发 OOM 进程也是 qemu-system-x86

内存资源使用情况:

1
2
3
4
5
6
7
8
9
10
# Guest OS 视角
sles@xxx:~> free -g
total used free shared buff/cache available
Mem: 15 4 3 0 8 11
Swap: 0 0 0

# Host OS 视角
kubectl top pod
NAME CPU(cores) MEMORY(bytes)
virt-launcher-xxx 622m 13138Mi

从 Guest OS 的内存使用情况来看,Guest OS 有 11GiB 可用,但 buff/cache 仍有 8GiB;而 virt-launcher Pod 占用内存约为 13GiB。由此可见从 Host OS 角度来看,这些缓存仍然占用了 qemu-system-x86 进程的 cgroup 资源。

即使 Guest OS 认为它有 11GiB 可用,但 Host OS 认为 VM 仍然持有 13GiB 内存,那么就有可能触发 OOM。

Memory Overhead

在 Harvester 中,每个 VM 都运行在一个 Kubernetes Pod 内,主要进程为 qemu-system-x86。Pod 的内存分配受 Kubernetes 的 requests 和 limits 机制控制。除了 Guest OS 本身使用的内存外,Harvester 和 KubeVirt 还需要额外分配一部分内存来管理 VM 的 CPU、存储、网络等资源,这部分称为 Memory Overhead(额外内存)。

OOM 发生的原因

尽管 Harvester 采用了一定的计算公式来为 VM 预留额外内存,但在某些情况下,仍可能出现 OOM 问题,导致 qemu-system-x86 被 cgroup OOM killer 终结。

可能导致 VM OOM 的原因有:

  1. VM 运行在 Kubernetes Pod 中,受 cgroup 机制限制,所有进程 (如 virt-launcher, virtlogd, virtqemud) 共享 Pod 级别的内存配额。
  2. Harvester 默认 Reserved Memory 过低 (100Mi),不足以应对不同类型的 VM 及其操作系统。
  3. VM 在长时间运行后,Guest OS 层面看仍是较低的内存使用率,但从 Host OS 层面上看,相关进程几乎耗尽了所有资源,导致 Host OS 认为 VM 内存已经耗尽,进而触发 cgroup OOM。

Reserved Memory

为了降低 OOM 发生的概率,Harvester 引入 Reserved Memory 机制,默认 Reserved Memory 为 100Mi。该机制使用户可以手动调整 Guest OS 之外的 Total Memory Overhead,从而避免 VM 进程因 cgroup OOM 而崩溃。

如下为 Total Memory Overhead 计算公式:
Total Memory Overhead (总的额外内存) = 自动计算的 Memory Overhead (根据 VM 配置自动计算的额外内存) + Harvester Reserved Memory (预留内存)

解决方案

以下解决方案均需要重启 VM:

  1. v1.4.x 版本前,可以通过增加 Reserved Memory,提高 Total Memory Overhead 避免 OOM 发生。
  2. v1.4.x 版本开始,在 Harvester -> Settings 中可以调整 additional-guest-memory-overhead-ratio,提高 KubeVirt 计算的 Memory Overhead,减少 VM 被 OOM 杀死的概率。
  3. v1.4.x 版本前可以通过修改 CR kubevirts.kubevirt.io 添加 spec.configuration.additionalGuestMemoryOverheadRatio 配置。
  4. 移除 cgroup 内存限制,VM 可能无限制占用 Host 资源,影响其他 Pod/VM。

临时解决方案

  1. 手动释放 Guest OS 内的 buff/cache 内存,属于临时解决方案,未来仍有可能再次发生 OOM。
1
sync && echo 3 > /proc/sys/vm/drop_caches
Author

Warner Chen

Posted on

2025-03-25

Updated on

2025-03-31

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.