内存相同页合并(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_nodes
为 0
可避免跨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
安装后,系统就增加了 ksm
和 ksmtuned
这两个服务,即可进行下一步配置
启动
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
:
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。
可以通过停止 ksmtuned
和 ksm
服务来停用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 命令相同)。