KSM(Kernel Samepage Merging)是Linux内核自带的一项内存优化技术,它能扫描系统中内容相同的内存页并将其合并为一页,从而释放大量物理内存。在CentOS系统中,ksmtuned是专门用来动态管理和调节KSM行为的守护进程服务。简单说,如果你的服务器跑了大量虚拟机或者容器,内存吃紧,那么开启并合理调节ksmtuned就是最直接有效的手段。核心操作就三步:安装ksmtuned、配置参数、启动服务并监控效果。下面我把每个环节拆开讲透。
一、KSM和ksmtuned到底是什么关系KSM是内核层面的功能,它通过扫描/sys/kernel/mm/ksm/目录下的参数来工作。但内核自己不会智能调节,它需要一个用户态的工具来告诉它"什么时候该扫描、扫描多快、合并多少页"。ksmtuned就是这个角色——它是一个基于Python的守护进程,会根据系统当前的内存使用情况自动调整KSM的运行参数。没有ksmtuned,KSM虽然能用,但你得手动去改参数,效率低且容易出问题。有了ksmtuned,系统会自己判断内存压力,动态调节扫描频率和合并阈值。
在CentOS 7和CentOS 8/Stream中,ksmtuned都可以通过yum或dnf直接安装。它依赖qemu-kvm包(因为KSM最初就是为KVM虚拟化设计的),但即使你不跑虚拟机,只要系统内存有重复页,KSM同样能起作用。
二、安装ksmtuned的具体步骤首先确认系统是否已经安装了ksmtuned:
rpm -qa | grep ksmtuned
如果没有输出,执行安装:
yum install -y ksmtuned
CentOS 8/Stream用户用dnf:
dnf install -y ksmtuned
安装完成后,检查ksmtuned的配置文件位置:
ls -la /etc/ksmtuned.conf
这个文件就是后续所有调优的核心。默认配置已经能满足大部分场景,但如果你想精细控制,就需要深入改参数。
三、ksmtuned.conf核心参数详解打开配置文件:
vi /etc/ksmtuned.conf
文件内容大致如下,我逐个解释每个关键参数:
[ksmtuned] # 内存空闲阈值,低于此值时ksmtuned会停止合并 # 单位是MB,默认512MB free_mb=512 # 内存使用阈值,高于此值时ksmtuned开始积极工作 # 单位是MB,默认1024MB threshold_mb=1024 # 扫描间隔,单位毫秒,默认20ms scan_interval_ms=20 # 每次扫描的最大页数,默认1000 max_scan_pages=1000 # 睡眠时间,单位毫秒,默认10ms sleep_ms=10 # 合并跨NUMA节点的页面,默认1(开启) merge_across_nodes=1
free_mb:这是最重要的参数之一。当系统空闲内存低于这个值时,ksmtuned会认为内存已经够紧张了,不应该再花CPU去扫描合并,否则会影响业务性能。如果你的服务器内存总量小(比如8GB),建议设为256或384;如果是64GB以上的大内存机器,可以设为1024甚至更高。
threshold_mb:当系统已使用内存超过这个值时,ksmtuned会加大扫描力度。这个值应该设得比free_mb高,形成一个"工作区间"。比如free_mb=512,threshold_mb=2048,意味着内存使用在512MB到2048MB之间时ksmtuned处于正常工作状态。
scan_interval_ms:扫描间隔越小,KSM工作越频繁,CPU占用越高,但内存回收越快。默认值20ms对大多数场景合适。如果你发现CPU被ksmtuned吃掉太多(超过10%),可以调大到50甚至100。反之如果内存回收不够快,可以降到10。
max_scan_pages:每次扫描的最大页数。这个值越大,单次扫描处理的页面越多,效率高但CPU峰值也高。默认1000是个平衡点。对于内存特别大的机器(128GB+),可以适当提高到2000或5000。
merge_across_nodes:NUMA架构的服务器有多个内存节点,跨节点合并会增加延迟但能回收更多内存。如果你的业务对延迟敏感(比如数据库),设为0关闭跨节点合并;如果是虚拟化宿主机追求最大内存利用率,保持1。
四、启动服务并设置开机自启配置改完后,启动ksmtuned:
systemctl start ksmtuned systemctl enable ksmtuned
验证服务状态:
systemctl status ksmtuned
你应该看到active (running)的状态。如果启动失败,检查日志:
journalctl -u ksmtuned -f
常见失败原因是/sys/kernel/mm/ksm/目录下的参数无法写入,通常是因为内核没有编译KSM支持或者SELinux阻止。确认内核支持:
cat /sys/kernel/mm/ksm/run
如果输出1,说明KSM已在内核中启用。如果是0,需要手动开启:
echo 1 > /sys/kernel/mm/ksm/run
但注意这只是临时生效,重启后会恢复。要永久开启,在/etc/rc.local或创建systemd服务来执行这个命令。
五、手动调节KSM参数的进阶操作有时候你不想用ksmtuned自动管理,而是想自己精确控制KSM。可以直接操作/sys/kernel/mm/ksm/下的参数:
# 开启KSM echo 1 > /sys/kernel/mm/ksm/run # 设置扫描页数(每次扫描多少页) echo 1000 > /sys/kernel/mm/ksm/pages_to_scan # 设置睡眠时间(扫描完后休眠多久,单位毫秒) echo 10 > /sys/kernel/mm/ksm/sleep_millisecs # 查看当前合并了多少页 cat /sys/kernel/mm/ksm/pages_shared # 查看节省了多少内存(单位KB) cat /sys/kernel/mm/ksm/pages_saving
pages_sharing是已经被合并的页面数,pages_saving是节省的内存量(因为每合并一页就少用一页内存)。这两个数字是衡量KSM效果的直接指标。如果pages_saving持续增长,说明KSM在正常工作。
一个实用的监控脚本,可以定期记录KSM状态:
#!/bin/bash echo "=== KSM Status $(date) ===" >> /var/log/ksm_status.log echo "run: $(cat /sys/kernel/mm/ksm/run)" >> /var/log/ksm_status.log echo "pages_shared: $(cat /sys/kernel/mm/ksm/pages_shared)" >> /var/log/ksm_status.log echo "pages_saving: $(cat /sys/kernel/mm/ksm/pages_saving)" >> /var/log/ksm_status.log echo "pages_scanned: $(cat /sys/kernel/mm/ksm/pages_scanned)" >> /var/log/ksm_status.log echo "full_scans: $(cat /sys/kernel/mm/ksm/full_scans)" >> /var/log/ksm_status.log echo "" >> /var/log/ksm_status.log
把这个脚本放到crontab每5分钟执行一次,就能持续追踪KSM的工作状态。
六、不同场景下的调优建议场景一:KVM虚拟化宿主机。这是KSM最经典的应用场景。多个虚拟机运行相同的操作系统时,内核代码页、库文件页大量重复。建议free_mb设为1024,threshold_mb设为4096,scan_interval_ms设为20。如果宿主机CPU核心数多(32核以上),max_scan_pages可以设到5000。实际测试中,一台64GB内存的KVM宿主机跑8个CentOS虚拟机,开启KSM后可节省3-8GB内存。
场景二:容器密集部署(Docker/Podman)。容器共享宿主机内核,镜像层的页面重复率高。但容器场景下要注意,ksmtuned默认可能不够积极。建议把threshold_mb降低到512,让它更早开始工作。同时scan_interval_ms可以设为30,避免在容器频繁启停时CPU开销过大。
场景三:数据库服务器。MySQL、PostgreSQL等数据库对内存延迟极其敏感。这种场景下我建议谨慎使用KSM,或者把scan_interval_ms设到100以上,max_scan_pages降到500,让KSM在后台慢慢干活,不要抢占数据库的CPU。merge_across_nodes一定要设为0,避免跨NUMA节点合并带来的延迟抖动。
场景四:大内存计算节点(128GB+)。这类机器通常跑大数据、AI训练等任务,内存利用率高但重复页不一定多。建议先观察pages_sharing的增长速度,如果增长缓慢说明重复页少,KSM效果有限,不必过度调优。可以把free_mb设为2048,避免KSM在内存充裕时浪费CPU。
七、常见问题和排查思路问题一:ksmtuned启动后pages_sharing一直是0。先确认KSM是否真的在运行(cat /sys/kernel/mm/ksm/run),再确认是否有足够的重复页。可以用smem或pmap工具查看进程的内存映射,看是否有大量相同内容的匿名页。如果是全新启动的系统,重复页本来就少,需要跑一段时间业务后才会有效果。
问题二:CPU被ksmtuned占满。直接降低scan_interval_ms到50或100,同时减小max_scan_pages到500。如果还是高,考虑在业务低峰期才让ksmtuned全速工作,高峰期限制它。
问题三:开启KSM后系统变慢。这通常是因为ksmtuned在扫描时消耗了太多CPU,导致业务进程得不到足够的CPU时间。解决办法是调大sleep_ms参数(在/etc/ksmtuned.conf中),让ksmtuned每次扫描后多休息一会儿。另外检查是否有透明大页(THP)和KSM冲突的情况,必要时关闭THP:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
问题四:重启后KSM参数丢失。所有/sys/kernel/mm/ksm/下的修改都是临时的。要永久生效,必须通过ksmtuned服务来管理,或者在/etc/rc.local中加入echo命令。推荐用ksmtuned,因为它会根据内存状态动态调整,比固定参数更智能。
八、监控KSM效果的实用方法除了前面提到的脚本,还可以用sar或vmstat来观察整体内存变化趋势。开启KSM前后对比free命令的输出:
free -h
重点关注available和used的变化。更精确的方法是看/proc/meminfo中的AnonHugePages和KSM相关统计。另外,如果你用的是CentOS 8,可以用cockpit的Web界面直接查看内存使用图表,直观看到KSM生效后的内存释放曲线。
长期来看,建议把KSM的监控纳入运维体系。用Zabbix或Prometheus采集ksm.pages_sharing和ksm.pages_saving这两个指标,设置告警阈值。当pages_sharing突然下降时,可能意味着业务发生了变化(比如虚拟机迁移了),需要排查原因。
总结ksmtuned是CentOS系统上管理KSM内存合并的最佳工具,安装简单、配置灵活、自动化程度高。核心就是根据你的业务类型和硬件配置,调整free_mb、threshold_mb、scan_interval_ms这几个关键参数。虚拟化场景大胆开,数据库场景谨慎开,大内存场景先观察再决定。记住一个原则:KSM是用CPU换内存,CPU不紧张就多合并,CPU紧张就少合并。掌握这个平衡,你的服务器内存利用率就能上一个台阶。
