ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Harvester 节点 KSM 内存合并支持:Ksmtuned 控制器设计全解析

Harvester 节点 KSM 内存合并支持:Ksmtuned 控制器设计全解析
  • 云原生
  • 虚拟化
  • 存储
  • 后端
  • 高可用

【免费下载链接】harvester

Open source hyperconverged infrastructure (HCI) software

项目地址:https://gitcode.com/gh_mirrors/ha/harvester
点击查看免费下载

导读

本文以 Harvester 开源仓库中的增强设计文档 enhancements/20220823-node-manager-support-ksm.md 为核心,系统讲解 Harvester 如何在节点上启用内核同页合并(Kernel Samepage Merging,KSM)以降低集群内存占用,并给出完整的 Ksmtuned 控制器设计方案——包括三种运行模式(stop/run/prune)、三种配置模式(standard/high/customized)、Ksmtuned 自定义资源(CR)的完整 YAML 示例、各参数语义、控制器行为与可落地的测试计划。读完本文,你将掌握:KSM 在 Harvester 中的整体架构、如何通过 UI/API 替代逐节点命令行配置、thresCoef等关键参数如何影响 ksmd 的扫描与合并行为,以及如何验证 KSM 是否按预期运行。

一、背景与动机:为什么 Harvester 需要 KSM

KSM(Kernel Samepage Merging)是 Linux 内核提供的内存去重机制,它允许内核将内容相同的物理内存页合并为共享页,从而显著降低运行大量相似工作负载(例如多个运行相同操作系统镜像的虚拟机)时的内存消耗。在 Harvester 这类超融合基础设施(HCI)中,节点上往往同时运行多个 KVM 虚拟机,内存是稀缺资源,启用 KSM 可以有效提升内存使用效率。

该增强方案的核心目标(Goals)包括:

  1. 配置方式现代化:从 UI 或 API 配置 Ksmtuned,替代登录每台节点使用命令行手工配置的运维方式,降低操作复杂度和安全风险;
  2. 可观测性:监控节点 ksmd 进程的 CPU 利用率,暴露给 Prometheus 抓取;
  3. 工程化落地:将 Ksmtuned 脚本转换为 Go 程序并补充单元测试,计划直接集成进 Harvester 的 ISO 发布物中。

方案原计划在 GA 版本 1.1.0 中首次交付,API 层面不引入额外变更。当前仓库中与 KSM 相关的 KubeVirt 侧能力也已存在:在 pkg/apis/harvesterhci.io/v1beta1/openapi_generated.go 中可以看到 KubeVirt 的KSMConfiguration定义,其nodeLabelSelector字段用于按节点标签过滤启用 KSM 的节点;同时 pkg/controller/master/node/condition_annotations_test.go 中出现了kubevirt.io/ksm-enabled、kubevirt.io/ksm-handler-managed注解,说明节点侧 KSM 状态会通过节点注解暴露。本方案则是在此基础上,把节点 KSM 参数的调优与管理能力以 Ksmtuned 控制器的形式沉淀为声明式配置。

二、总体设计:DaemonSet + Ksmtuned CR 的双层架构

2.1 实现总览

方案的核心是部署一个Ksmtuned controller(控制器)来管理 Harvester 各节点的 KSM 配置。其实现要点:

  • 使用DaemonSet在每个节点上运行,每个节点只获取与自身相关的配置信息,天然实现"一节点一配置"的隔离;
  • 控制器按配置写入 KSM 的 sysfs 接口文件(/sys/kernel/mm/ksm/下的run、pages_to_scan等),并定时读取节点的内存使用情况;
  • 根据阈值计算结果启动或停止 ksmd 程序,实现"内存充足时让出 CPU、内存紧张时才合并"的自适应行为。

这种设计把原先需要运维人员逐台登录节点执行的脚本化操作,抽象为 Kubernetes 原生的声明式资源管理,与 Harvester 的"以 API/UI 管理集群"理念一致。

2.2 Ksmtuned 自定义资源(CR)

Ksmtuned CR 的 API 分组为node.harvesterhci.io/v1beta1,kind 为Ksmtuned,一个 CR 对应一个节点的 KSM 管理配置,CR 与 Node 通过ownerReferences建立归属关系。当spec.mode为standard(标准)或high(高性能)模式时,spec.ksmtunedParameters展示对应的配置参数。一个典型的 CR 如下:

apiVersion: node.harvesterhci.io/v1beta1 kind: Ksmtuned metadata: name: node1 ownerReferences: - apiVersion: v1 kind: Node name: node1 spec: ksmtunedParameters: boost: 0 decay: 0 maxPages: 100 minPages: 100 sleepMsec: 20 mergeAcrossNodes: 0 mode: standard/high/customized run: stop/run/prune thresCoef: 20 status: fullScans: 17 ksmdPhase: Stopped/Running/Pruned shared: 171264 sharing: 1368772 stableNodeChains: 12 stableNodeDups: 538 unshared: 545943 volatile: 10909

其中status字段直接反映内核 KSM 的运行状态与统计信息(fullScans、shared、sharing、stableNodeChains、stableNodeDups、unshared、volatile),以及当前 ksmd 的阶段(ksmdPhase:Stopped/Running/Pruned),让管理员无需进入节点即可掌握 KSM 的实时合并效果。

三、三种运行模式与三种配置模式

3.1 运行模式(spec.run)

用户故事中明确了三种运行选项,覆盖 KSM 生命周期的管理:

运行模式行为适用场景
stop停止 Ksmtuned 与 KSM,但已存在的共享内存页继续保留临时关闭合并,避免影响 VM 内存访问性能
run运行 Ksmtuned,按配置驱动 KSM 工作日常默认运行态
prune停止 Ksmtuned 并清理(prune)KSM 共享内存页需要彻底回收共享页、恢复独立内存布局时

需要特别说明:当spec.run为stop时,只是"挂起"ksmtuned,虚拟机仍可继续使用已有的共享内存页,因此不会引发 VM 内存内容丢失;只有prune才会真正清理共享页(见下文示例中的 status 归零)。

3.2 配置模式(spec.mode)

方案提供三种配置模式,决定 ksmd 对 CPU 资源的占用策略与扫描合并效率:

Standard(标准模式,默认):控制节点的 ksmd 大约占用单个 CPU 的 20%,参数如下:

boost: 0 decay: 0 minPages: 100 maxPages: 100 sleepMsec: 20

由于boost与decay均为 0,每次扫描的页数恒定在 100 页,CPU 占用平稳可控,适合默认部署场景。

High Performance(高性能模式):节点 ksmd 占用单个 CPU 的 20%~100%,扫描与合并效率更高,参数如下:

boost: 200 decay: 50 minPages: 100 maxPages: 10000 sleepMsec: 20

该模式下boost与decay非零,扫描页数会随内存压力动态在 100~10000 页之间调整,内存越紧张扫描越激进,从而更快完成合并。

Customized(自定义模式):完全由用户自定义参数,以达成期望的性能与 CPU 占用平衡。当spec.mode为customized时,必须自行配置spec.ksmtunedParameters。

四、Ksmtuned 参数语义详解

Ksmtuned.spec中的每个参数都直接影响内核 KSM 的行为,理解其语义是调优的关键:

  • run:stop/run/prune,停止/运行 Ksmtuned 或清理共享页;
  • mode:standard/high/customized,三种配置模式;
  • thresCoef:空闲内存阈值(百分比)。当可用内存低于设定百分比时 KSM 启动,否则停止。这是 KSM 自适应的核心开关;
  • mergeAcrossNodes:指定是否允许合并来自不同 NUMA 节点的内存页(0 为不允许,1 为允许),对多路服务器上的跨 NUMA 合并行为有直接影响;
  • ksmtunedParameters.boost:当可用内存低于阈值时,每次扫描页数的增量,用于"增压"加速合并;
  • ksmtunedParameters.decay:当可用内存高于阈值时,每次扫描页数的减量,用于"减压"让出 CPU;
  • ksmtunedParameters.maxPages:每次扫描的最大页数上限;
  • ksmtunedParameters.minPages:每次扫描的最小页数,即首次运行的初始配置值;
  • ksmtunedParameters.sleepMsec:每次调整配置的时间间隔基准,两次扫描的实际间隔由公式sleepMsec * 16 * 1024 * 1024 / total memory计算得出(单位毫秒),即根据节点总内存动态换算扫描间隔。

设计文档中特别指出:由于 KSM 运行在单一模式下,大内存设备可能长时间占用 CPU。为解决此问题,ksmtuned 脚本通过阈值机制(thresCoef)让 KSM 仅在空闲内存低于一定百分比时运行,从而在内存充裕时避免无谓的 CPU 消耗——这正是thresCoef与boost/decay配合实现的自适应调节链路。

五、各运行状态的 CR 配置实例

5.1 自动创建的标准模式 CR

Ksmtuned 控制器会检查节点的 Ksmtuned CR 是否存在;若不存在,则自动为该节点创建一个mode 为 standard、thresCoef 为 20、状态为 stop的 CR(默认配置,避免新节点因启用 KSM 引入意外开销)。对应 CR 形态:

spec: run: run mode: customized thresCoef: 20 ksmtuneddParameters: boost: 300 decay: 50 maxPages: 2000 minPages: 100 sleepMsec: 20

(注:上面展示的是自定义模式示例,即mode: customized时需要显式给出全部ksmtunedParameters,此处boost: 300、maxPages: 2000演示了比标准模式更激进的合并策略。)

5.2 run=stop:挂起 KSM、保留共享页

apiVersion: harvesterhci.io/v1beta1 kind: Ksmtuned metadata: name: harvester-master spec: ksmtunedParameters: boost: 0 decay: 0 maxPages: 100 minPages: 100 sleepMsec: 20 mergeAcrossNodes: 0 mode: standard run: stop thresCoef: 20 status: sharing: 17299179 shared: 312514 unshared: 2334736 volatile: 65571 fullScans: 14102 stableNodeChains: 30 stableNodeDups: 56249 ksmdPhase: Stopped

可以看到run: stop后,ksmdPhase变为Stopped,但sharing(共享节省的内存)仍保留在 17299179,证明已合并的页面未被破坏。

5.3 run=prune:停止并清理共享页

apiVersion: harvesterhci.io/v1beta1 kind: Ksmtuned metadata: name: harvester-master spec: ksmtunedParameters: boost: 0 decay: 0 maxPages: 100 minPages: 100 sleepMsec: 20 mergeAcrossNodes: 0 mode: standard run: prune thresCoef: 20 status: sharing: 0 shared: 0 unshared: 0 volatile: 0 fullScans: 0 stableNodeChains: 0 stableNodeDups: 0 ksmdPhase: Pruned

run: prune后所有合并统计全部归零,ksmdPhase为Pruned,表明共享内存页已被彻底清理,系统回到未合并的初始状态。

5.4 通过 status 观测 KSM 内核指标

Ksmtuned CR 的status用于展示内核 KSM daemon 的 sysfs 指标与 ksmd 阶段。控制器会持续将以下内核统计同步进 CR:

apiVersion: harvesterhci.io/v1beta1 kind: Ksmtuned metadata: name: harvester-master spec: ... status: sharing: 17299179 shared: 312514 unshared: 2334736 volatile: 65571 fullScans: 14102 stableNodeChains: 30 stableNodeDups: 56249 ksmdPhase: Stopped/Running/Pruned

这些字段与/sys/kernel/mm/ksm/下同名指标一一对应:sharing为共享页节省的字节数、shared为共享页数、fullScans为完成的扫描次数、stableNodeDups/stableNodeChains为稳定树的去重计数、volatile为易变页数、unshared为取消共享的页数。将内核状态提升为 CR 的 status,使得 Grafana/Prometheus 与 UI 可以统一从 API 读取,无需再进入节点查看/sys文件。

六、控制器行为设计

6.1 Node Controller(节点控制器)

  • 自动创建:同步 Node 时,若该节点的 Ksmtuned CR 不存在,则自动为其创建,默认mode 为 standard、thresCoef 为 20、run 状态为 stop;
  • 随节点清理:Node 被删除时,同步删除该节点的 Ksmtuned CR,避免残留配置造成状态漂移。

6.2 Ksmtuned Controller(Ksmtuned 控制器)

  • 配置驱动运行:Ksmtuned CR 被创建/更新时,运行状态适配预定义(standard/high)或自定义(customized)配置;否则停止运行程序;
  • 删除即终止:Ksmtuned CR 被删除时,终止对应的 ksmtuned 程序,确保声明式配置与实际进程状态一致。

6.3 监控指标(Metrics)

  • 暴露ksmd 程序的 CPU 利用率指标,供 Prometheus 抓取;对应设计文档中的目标"Monitor node ksmd CPU utilization",并关联到 Harvester 的监控看板(见下节 UI 体验)。

七、用户体验:UI 展示与配置入口

在 UI 层面,方案规划了两处入口:

  1. 节点级配置:KSM 配置将在Hosts → info/edit → KSM页面展示与配置。管理员无需登录节点执行命令行,即可针对每个节点选择运行模式(stop/run/prune)与配置模式(standard/high/customized),并直接编辑thresCoef、boost、decay等参数;
  2. 集群级观测:在 Dashboard 页面的Cluster Metrics(集群指标)中增加ksmd 利用率 Top10图表,直观展示各节点 ksmd 的 CPU 占用排名,配合第 6.3 节的 Prometheus 指标形成"配置—运行—观测"闭环。

八、测试计划:如何验证 KSM 按预期运行

设计文档给出了可直接落地的验证方法,核心思路是利用/sys/kernel/mm/ksm/run与pages_to_scan两个内核接口观察 KSM 行为:

  1. 验证 thresCoef 阈值逻辑:设置thresCoef: 20后,当可用内存总量低于 总内存 × 0.2 时,执行cat /sys/kernel/mm/ksm/run应输出1(KSM 开启);反之(内存充足)应输出0(KSM 关闭);
  2. 观察扫描页数动态变化:使用watch -n1 grep . /sys/kernel/mm/ksm/*持续观察pages_to_scan的变化,即可验证boost、decay、maxPages、minPages配置是否生效——内存紧张时pages_to_scan应随 boost 递增,内存充裕时应随 decay 递减,且不超出[minPages, maxPages]区间。

完整的测试步骤如下:

  1. 准备一台内存充足的节点,并预先创建大量虚拟机(制造可合并的内存页);
  2. 检查自动为该节点创建的 Ksmtuned CR(应默认 standard/thresCoef=20/stop);
  3. 按测试预期调整该节点 Ksmtuned 中thresCoef的百分比;
  4. 按测试预期调整boost/decay/maxPages/minPages的值;
  5. 检查 Ksmtuned CR 的status,或登录系统(读取/sys/kernel/mm/ksm/*)观察实际运行情况,两者应相互印证。

九、升级策略与工程落地

设计文档明确该功能无独立的升级策略(Upgrade strategy: No),即它作为节点管理能力随 ISO 发行版整体交付,不需要额外的数据迁移或版本兼容处理。工程层面,方案要求把原本的 Ksmtuned 脚本改写成 Go 程序并补充单元测试,使其作为守护进程随 DaemonSet 在每节点运行——这既提升了程序健壮性,也使其能够复用 Harvester 现有的 clientset、controller-runtime 等基础设施。

值得说明的是:截至当前仓库快照,Ksmtuned CR 的 Go 类型尚未出现在 pkg/apis/harvesterhci.io/v1beta1 中(该目录目前包含 addon、backup、image、upgrade 等类型),也未见其 OpenAPI 定义进入 api/openapi-spec/swagger.json;与之相邻的 KubeVirt 侧 KSM 能力(KSMConfiguration.nodeLabelSelector)已存在于 openapi_generated.go。可以推断,本方案当前以设计文档形态沉淀在 enhancements/20220823-node-manager-support-ksm.md 中,具体 CRD 与控制器代码的落库位置可能位于配套的 node-manager 实现中。读者若要在自己的 Harvester 环境评估该能力,应以上述设计文档描述的 CR 结构与参数语义为准。

十、小结

Harvester 的 KSM 支持方案通过"DaemonSet 逐节点守护 + Ksmtuned CR 声明式配置 + 控制器自动编排 + Prometheus 可观测"四层设计,将 Linux 内核的 KSM 能力转化为 HCI 集群中可配置、可观测、可验证的运维资产:三种运行模式覆盖 KSM 的启停与清理,三种配置模式覆盖从保守到激进的 CPU/内存权衡,thresCoef阈值机制则确保 KSM 只在内存压力下才消耗 CPU。对大规模部署 Harvester 并希望压榨内存利用率的团队而言,这套方案是降低节点内存成本、提升虚拟机密度的一条现实路径。

  • 云原生
  • 虚拟化
  • 存储
  • 后端
  • 高可用

【免费下载链接】harvester

Open source hyperconverged infrastructure (HCI) software

项目地址:https://gitcode.com/gh_mirrors/ha/harvester
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进