目录
文章目录
KSM 内存页共享的性能问题
KSM(Kernel Shared Memory)是 Linux Kernel 的一种内存共享机制,在 2.6.36 版本引入。简而言之,KSM 用于合并具有相同内容的物理主存页面以减少页面冗余。在 Kernel 中有一个 KSM 守护进程 ksmd,它会定期扫描用户向它注册的内存区域,寻找到相同的页面就会将其合并,并用一个添加了写保护的页面来代替。当有进程尝试写入该页面时,Kernel 会自动为其分配一个新的页面,然后将新数据写入到这个新页面,这就是典型的 COW 机制。类似的,存储技术中有一个称为去耦合(de-duplication)的技术,通过删除冗余数据(基于数据块,或者基于更大的数据片段,比如文件)来减少已存储的数据。公共数据片段被合并(以一种 COW 方式),释放空间供其他用途。使用这种方法,存储成本更低,最终需要的存储器也更少。
KSM 最初被应用到 KVM 上,因为事实证明,如果虚拟化了许多相同的操作系统和应用程序组,那么宿主机上许多内存页面都是相同的。假如操作系统和应用程序代码以及常量数据在 VMs 之间相同,那么这个特点就很有用。当页面惟一时,它们可以被合并,从而释放内存,供其他应用程序使用。将多个 VMs 具有的相同内存页合并(共享),可以腾出更多的可用物理内存。
但是事实上,KSM 可以应用于任何应用。KSM 仅仅会合并匿名页面,不会对文件映射的页面做处理,经过 KSM 合并的页面最初是被锁定的内存中的,但是现在已经可以像其他页面一样被换出到交换区了。但是共享页一经换出,其共享的特性就被打破,再次换入的时候,ksmd 必须重新对其处理。前面提到,KSM 仅仅会扫描那些向其注册的区域,就是向 KSM 模块注册了如果条件允许可以被合并的区域,通过 madvise 系统调用可以做到这点 int madvise(addr, length, MADV_MERGEABLE)
。同时,应用也可以通过调用 int madvise(addr, length, MADV_UNMERGEABLE)
来取消这个注册,从而让页面恢复私有特性。但是该调用可能会造成内存超额,造成 unmerge 失败,很大程度上会造成唤醒 Out-Of-Memory killer,杀死当前进程。如果 KSM 没有在当前运行的 Kernel 启用,那么前面提到的 madvise 调用就会失败,如果内核配置了 CONFIG_KSM=y
,调用一般是会成功的。
KSM 的管理和监控通过 sysfs(位于根 /sys/kernel/mm/ksm)执行。
- pages_to_scan:定义一次给定扫描中可以扫描的页面数。
- sleep_millisecs:定义执行另一次页面扫描前 ksmd 休眠的毫秒数。
- max_kernel_pages:定义 ksmd 可以使用的最大页面数(默认值是可用内存的 25%,但可以写入一个 0 来指定为无限)。
- merge_across_nodes:控制不同 NUMA 节点内存的合并,如果被设置成 0,则只合并当前 NUMA 节点的内存。
- run:控制 ksmd 的运行
- 0 表示停止 ksmd,但是保持合并的页面;
- 1 表示运行 ksmd;
- 2 表示停止 ksmd 并请求取消合并所有合并页面。
KSM 合并效果会实时显示在下面文件:
- pages_shared:KSM 正在使用的不可交换的内核页面的数量。
- pages_sharing:一个内存存储指示。
- pages_unshared :为合并而重复检查的惟一页面的数量。
- pages_volatile:频繁改变的页面的数量。
- full_scans:表明已经执行的全区域扫描的次数。
KSM 作者定义:较高的 pages_sharing/pages_shared 比率表明高效的页面共享(反之则表明资源浪费)。
需要注意的是,应用 KSM 的时候要慎重考虑,因为 KSM 扫描相同的页面的过程会消耗较多的 CPU 资源,在对虚拟机性能要求苛刻的环境中一般都会禁用 KSM。关闭 KSM,可以让作为 Hypervisor 的 Linux Kernel(KVM)在负载增加时候,保证虚拟机的响应速度。这里再次印证了一句名言:计算机艺术永远是时间与空间的较量。
来源:oschina
链接:https://my.oschina.net/u/4342092/blog/4318496