内存相同页合并(Kernel Same-page Merging, KSM)

KVM hypervisor使用内核相同内存页合并(Kernel Same-page Merging, KSM)功能,再不同的KVM guest虚拟机中共享相同内存页。这些共享页面通常是 公共库 (common libraries) 或者其他相同的高使用率数据。KSM通过避免内存重复来实现更高的虚拟机密度。

共享内存的概念在现代操作系统中非常常见。例如,的那个一个程序第一次启动时,它就和父程序共享它的所有内存。当子程序或父程序试图修改内存时,内核会分配一个新的内存区域,复制原始内容并允许程序修改此新区域。这种技术称为写时复制(copy on write)。

KSM是一个Linux功能,它反向使用了这个概念。KSM使用内核检查两个或者更多的已经运行的程序,并比校它们的内存。如果任何内存区域或者页面相同,则KSM会将多个相同的内存页面减少为一个页面,随后该页面会标记为写时复制。如果内存页面的内容被guest虚拟机修改,则会为该guest创建一个新的页面。

这个功能对于KVM虚拟化非常有用。当guest虚拟机启动时,它只从主机 qemu-kvm 进程继承内存。guest运行以后,如果guest操作系统相同或者相同的应用程序,则共享guest操作系统影像的内容。KSM允许KVM请求共享这些相同的guest内存区域。

KSM提供增强的内存速度和利用率。使用KSM时,通过将过程数据存储在高速缓存或主内存中,可以减少KVM guest的缓存未命中,从而提高某些应用程序和操作系统的性能。其次,共享内存减少了guest的整体内存使用,从而允许更高的密度和更高的资源利用率。

KSM使用要点

  • 在使用KSM时候应避免跨节点内存合并(避免 NUMA架构 影响):

设置 /sys/kernel/mm/ksm/merge_across_nodes0 可避免跨NUMA节点合并页面

页可以通过 virsh node-memory-tune --shm-merge-across-nodes 0 完成上述设置

  • Red Hat Enterprise Linux 7上,KSM时NUMA aware的,这样它在合并内存页面时会考虑NUMA的局限性,从而防止页面移动到远程节点导致性能下降

  • 在大量跨节点合并之后,内核内存记账统计信息可能会互相矛盾,因此在KSM daemon合并大量内存后,numad可能会变混乱

  • 如果系统有大量可用内存,则建议不要使用KVM: 关闭和禁用KSM守护进程能够获得更高的性能

  • 即使不考虑KSM,也要确保有足够交换大小以用于提交的RAM

KSM配置

Red Hat Enterprise Linux使用两种不同的方式来控制KSM:

  • ksm 服务启动和停止来控制KSM内核线程

  • ksmtuned 服务控制和调整 ksm 服务,动态管理同一页面合并。 ksmtuned 启动 ksm 服务,然后当不再需要内存共享时, ksmtuned 会停止 ksm 服务。当新的guest虚拟机创建或销毁, ksmtuned 必须使用 retune 来来运行 ksmtuned

KSM服务

Red Hat在 qemu-kvm 软件包中包含了 ksm 服务。当 ksm 没有启动时,KSM(Kernel same-page merging)只共享2000个内存页。这个默认设置只能提供悠闲地内存节约。

当启动 ksm 服务时,KSM将共享主机系统内存的一半,也就是说启动 ksm 服务,能够让KSM共享更多内存

备注

我的实践是在 Apple ARM架构芯片M1 Pro Macbook Pro 2022笔记本上,也就是 Arch Linux ARM操作系统上,通过 Arch Linux AUR 安装:

yay -S ksmtuned-git

安装后,系统就增加了 ksmksmtuned 这两个服务,即可进行下一步配置

  • 启动 ksm 服务:

    systemctl start ksm
    
  • 激活 ksm 服务:

    systemctl enable ksm
    

KSM Tuning服务

ksmtuned 服务通过循环和调整 ksm 来微调内核同页合并(KSM)配置。当创建或销毁guest虚拟机时, ksmtuned 服务会收到 libvirt 的通知。 ksmtuned 服务没有选项。

  • 启动 ksmtuned 和激活:

    systemctl start ksmtuned
    systemctl enable ksmtuned
    

ksmtned 服务可以使用 retune 参数来调整,该参数指示 ksmtuned 手动运行调整功能。

/etc/ksmtuned.conf 文件是 ksmtuned 服务的配置文集阿,以下时默认的 ksmtuned.conf :

/etc/ksmtuned.conf 调整 ksmtuned 服务
Configuration file for ksmtuned.
# How long ksmtuned should sleep between tuning adjustments
# KSM_MONITOR_INTERVAL=60

# Millisecond sleep between ksm scans for 16Gb server.
# Smaller servers sleep more, bigger sleep less.
# KSM_SLEEP_MSEC=10

# KSM_NPAGES_BOOST - is added to the `npages` value, when `free memory` is less than `thres`.
# KSM_NPAGES_BOOST=300

# KSM_NPAGES_DECAY - is the value given is subtracted to the `npages` value, when `free memory` is greater than `thres`.
# KSM_NPAGES_DECAY=-50

# KSM_NPAGES_MIN - is the lower limit for the `npages` value.
# KSM_NPAGES_MIN=64

# KSM_NPAGES_MAX - is the upper limit for the `npages` value.
# KSM_NPAGES_MAX=1250

# KSM_THRES_COEF - is the RAM percentage to be calculated in parameter `thres`.
# KSM_THRES_COEF=20

# KSM_THRES_CONST - If this is a low memory system, and the `thres` value is less than `KSM_THRES_CONST`, then reset `thres` value to `KSM_THRES_CONST` value.
# KSM_THRES_CONST=2048

# uncomment the following to enable ksmtuned debug information
# LOGFILE=/var/log/ksmtuned
# DEBUG=1

/etc/ksmtuned.conf 文件中, npages 设置 ksmd 守护进程编程非活动状态之前, ksm 将扫描多少页。这个值也将在 /sys/kernel/mm/ksm/pages_to_scan 文件中设置。

KSM_THRES_CONST 值表示用作激活 ksm 的阀值的可用内存量,如果发生以下任一情况,则 ksmd 将被激活:

  • 可用内存量低于 KSM_THRES_CONST 中设置的阀值

  • 提交的内存量加上阀值 KSM_THRES_CONST 超过内存总量

/etc/ksmtuned.conf 文件中设置的值对应于系统内核 /sys/kernel/mm/ksm/ 目录下配置文件:

full_scans
max_page_sharing
pages_shared
pages_sharing
pages_to_scan
pages_unshared
pages_volatile
run
sleep_millisecs
stable_node_chains
stable_node_chains_prune_millisecs
stable_node_dups
use_zero_pages

上述这些值可以使用 virsh node-memory-tune 命令来调整,例如:

virsh node-memory-tune --shm-pages-to-scan number

如果 /etc/ksmtuned.conf 配置了 DEBUG=1 ,则上述调整命令会记录到 /var/log/ksmtuned 日志文件

关闭KSM

内核同页合并(KSM)的性能开销可能对于某些环境或者主机系统太大了,而且KSM还可能引入侧通道,这些侧通道可能被用来在guest之间泄露信息。所以如果有安全要求,可以针对每个guest禁用KSM。

可以通过停止 ksmtunedksm 服务来停用KSM:

systemctl stop ksmtuned
systemctl stop ksm
systemctl disable ksm
systemctl disable ksmtuned

当 KSM 被禁用时,在停用 KSM 之前共享的任何内存页面仍然共享。 要删除系统中的所有 PageKSM,请使用以下命令:

echo 2 >/sys/kernel/mm/ksm/run

此时, khugepaged 守护进程可以在KVM guest虚拟机的物理内存上重建透明大页。使用:

echo 0 >/sys/kernel/mm/ksm/run

会停止KSM,但是不会取消共享所有先前创建的 KSM 页面(这与 #systemctl stop ksmtuned 命令相同)。

参考