占用大量的File Cache,内存利用不充分导致swap

基本原则:尽量使用内存,减少swap,同时,尽早flush到外存,早点释放内存给写cache使用。---特别在持续的写入操作中,此优化非常有效。 读少写多

调优措施:

vm.swapiness :60 改成 10

vm.dirty_ratio:90 改成 10

vm.dirty_background_ratio:60 改成 5

vm.dirty_expire_centisecs:3000改成500

vm.vfs_cache_pressure:100 改成 500

下面重点解释一下各个配置的含义:

一,vm.swappiness优化:

swappiness的值的大小对如何使用swap分区是有着很大的联系的。swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间,swappiness=100的时候表示积极的使用swap分区,并且把内存上的数据及时的搬运到swap空间里面。linux的基本默认设置为60,具体如下:

cat /proc/sys/vm/swappiness

60

也就是说,你的内存在使用到100-60=40%的时候,就开始出现有交换分区的使用。大家知道,内存的速度会比磁盘快很多,这样子会加大系统io,同时造的成大量页的换进换出,严重影响系统的性能,所以我们在操作系统层面,要尽可能使用内存,对该参数进行调整。

临时调整的方法如下,我们调成10:

sysctl vm.swappiness=10

vm.swappiness = 10

cat /proc/sys/vm/swappiness

10

这只是临时调整的方法,重启后会回到默认设置的

要想永久调整的话,需要将在/etc/sysctl.conf修改,加上:

cat /etc/sysctl.conf

vm.swappiness=10

二,vm.dirty_ratio: 同步刷脏页,会阻塞应用程序

这个参数控制文件系统的同步写写缓冲区的大小,单位是百分比,表示当写缓冲使用到系统内存多少的时候(即指定了当文件系统缓存脏页数量达到系统内存百分之多少时(如10%),),开始向磁盘写出数据,即系统不得不开始处理缓存脏页(因为此时脏页数量已经比较多,为了避免数据丢失需要将一定脏页刷入外存),在此过程中很多应用进程可能会因为系统转而处理文件IO而阻塞。

增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。但是,当你需要持续、恒定的写入场合时,应该降低其数值,一般启动上缺省是 10。

三,vm.dirty_background_ratio:异步刷脏页,不会阻塞应用程序

这个参数控制文件系统的后台进程,在何时刷新磁盘。单位是百分比,表示系统内存的百分比,意思是当写缓冲使用到系统内存多少的时候,就会触发pdflush/flush/kdmflush等后台回写进程运行,将一定缓存的脏页异步地刷入外存。增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。但是,当你需要持续、恒定的写入场合时,应该降低其数值,一般启动上缺省是 5。

注意:如果dirty_ratio设置比dirty_background_ratio大,可能认为dirty_ratio的触发条件不可能达到,因为每次肯定会先达到vm.dirty_background_ratio的条件,然而,确实是先达到vm.dirty_background_ratio的条件然后触发flush进程进行异步的回写操作,但是这一过程中应用进程仍然可以进行写操作,如果多个应用进程写入的量大于flush进程刷出的量那自然会达到vm.dirty_ratio这个参数所设定的坎,此时操作系统会转入同步地处理脏页的过程,阻塞应用进程。

四,vm.dirty_expire_centisecs:

这个参数声明Linux内核写缓冲区里面的数据多“旧”了之后,pdflush进程就开始考虑写到磁盘中去。单位是 1/100秒。缺省是 3000,也就是 30 秒的数据就算旧了,将会刷新磁盘。对于特别重载的写操作来说,这个值适当缩小也是好的,但也不能缩小太多,因为缩小太多也会导致IO提高太快。建议设置为 1500,也就是15秒算旧。当然,如果你的系统内存比较大,并且写入模式是间歇式的,并且每次写入的数据不大(比如几十M),那么这个值还是大些的好。

五,Vm.dirty_writeback_centisecs:

这个参数控制内核的脏数据刷新进程pdflush的运行间隔。单位是 1/100 秒。缺省数值是500,也就是 5 秒。如果你的系统是持续地写入动作,那么实际上还是降低这个数值比较好,这样可以把尖峰的写操作削平成多次写操作。设置方法如下:

echo "200" > /proc/sys/vm/dirty_writeback_centisecs

如果你的系统是短期地尖峰式的写操作,并且写入数据不大(几十M/次)且内存有比较多富裕,那么应该增大此数值:

六,Vm.vfs_cache_pressure:

增大这个参数设置了虚拟内存回收directory和inode缓冲的倾向,这个值越大。越易回收

该文件表示内核回收用于directory和inode cache内存的倾向;缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比;降低该值低于100,将导致内核倾向于保留directory和inode cache;增加该值超过100,将导致内核倾向于回收directory和inode cache。

This variable controls the tendency of the kernel to reclaim thememory which is used for caching of VFS caches, versus pagecache and swap.Increasing this value increases the rate at which VFS caches are reclaimed.Itis difficult to know when this should be changed, other than byexperimentation. The slabtop command (part of the package procps) shows topmemory objects used by the kernel. The vfs caches are the "dentry"and the "*_inode_cache" objects. If these are consuming a largeamount of memory in relation to pagecache, it may be worth trying to increasepressure. Could also help to reduce swapping. The default value is 100.


 

同事说有一台服务器的内存用光了,我连上去用free看了下,确实有点怪。

$ free -g
total used free shared buffers cached
Mem: 15 15 0 0 2 0
-/+ buffers/cache: 12 2
Swap: 17 0 17

正常情况

free -g
              total        used        free      shared  buff/cache   available
Mem:            251         204           3          23          43          18 --- 还有100多G分给了SGA
Swap:           127           0         127

这台服务器有16G内存,但是结果显示除了2G左右的文件Buffer缓存外,其余十几G都被确确实实的用光了。(free按1024进制计算,总内存可能比实际偏小)

这里大概介绍下free结果的含义:

/

total

used

free

shared

buffers

cached

Mem

总物理内存

当前使用的内存(包括slab+buffers+cached)

完全没有使用的内存

进程间共享的内存

缓存文件的元数据[1]

缓存文件的具体内容[1]

-/+ buffers/cache

当前使用的内存(不包括buffers+cached,但包括slab)

未使用和缓存的内存(free+buffers+cached)

Swap

总的交换空间

已使用的交换空间

未使用的交换空间

然后top看了下,没有特别吃内存的程序。用ps大概统计下所有程序占用的总内存:

$ ps aux | awk '{mem += $6} END {print mem/1024/1024}' 第6个值是使用的内存,第5个是shared
0.595089

结果显示所有进程占用的内存还不到1G,实际上,因为free, ps的统计方式的差别和Copy-on-write和Shared libraries等内存优化机制的存在,这两者的统计结果通常是不一样的。但是一般情况下绝对不会相差十几个G,

肯定是有什么隐藏的问题,Google了许久后发现,free没有专门统计另一项缓存: Slab。

Slab简介和进一步调查

Slab Allocation是Linux 2.2之后引入的一个内存管理机制,专门用于缓存内核的数据对象,可以理解为一个内核专用的对象池,可以提高系统性能并减少内存碎片。(Linux 2.6.23之后,SLUB成为了默认的allocator。)

查看Slab缓存

$ cat /proc/meminfo

其中,Slab相关的数据为

Slab: 154212 kB
SReclaimable: 87980 kB
SUnreclaim: 66232 kB

SReclaimable(Linux 2.6.19+)都是clean的缓存,随时可以释放。回到之前的内存问题,我查了下那台服务器上Slab占用的内存:

$ cat /proc/meminfo | grep Slab
Slab: 12777668 kB

12G的Slab缓存,有意思的是free把Slab缓存统计到了used memory中,这就是之前那个问题的症结所在了。

另外,还可以查看/proc/slabinfo(或使用slabtop命令)来查看Slab缓存的具体使用情况。

结果发现,ext3_inode_cache和dentry_cache占用了绝大部分内存。

考虑到这台服务器会频繁地用rsync同步大量的文件,这个结果也并不意外。

解决问题

先说明一下,如果问题仅仅是Slab占用了太多的内存(SReclaimable),那么通常不需要太操心,因为这根本不是个问题(如果是SUnreclaim太多且不断增长,那么很有可能是内核有bug)。但是,如果是因为Slab占用内存太多而引起了其他的问题,建议继续阅读。

清除Slab可回收缓存

通过/proc/sys/vm/drop_caches这个配置项,我们可以手动清除指定的可回收缓存(SReclaimable)[2]。

echo 2 > /proc/sys/vm/drop_caches
表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。

上面的命令会主动释放Slab中clean的缓存(包括inode和dentry的缓存)

,然后再free -g一下,未使用的内存陡增了十几个G。。。

需要注意的是,手动清除缓存可能会在一段时间内降低系统性能。原则上不推荐这么做,因为如果有需要,系统会自动释放出内存供其他程序使用。

另外,手动清除Slab缓存是一个治标不治本的办法。

因为问题不在Slab,而在于我们那个会引起Slab缓存飙涨的进程(我这里应该是rsync)。实际操作的时候发现,清除缓存一段时间后,Slab缓存很快又会“反弹”回去。如果需要治本,要么搞定问题进程,要么修改系统配置。

调整系统vm配置

风险预警: 调整以下系统配置可能会对系统性能造成负面影响,请仔细测试并谨慎操作

/etc/sysctl.conf里有几个对内存管理影响比较大的配置,以下配置项的文档见vm.txt。

vm.vfs_cache_pressure

系统在进行内存回收时,会先回收page cache, inode cache, dentry cache和swap cache。vfs_cache_pressure越大,每次回收时,inode cache和dentry cache所占比例越大[3]。

vfs_cache_pressure默认是100,值越大inode cache和dentry cache的回收速度会越快,越小则回收越慢,为0的时候完全不回收(OOM!)。

linux io caches0%

图片取自The Linux Kernel's VFS Layer

vm.min_free_kbytes

系统的"保留内存"的大小,"保留内存"用于低内存状态下的"atomic memory allocation requests"(eg. kmalloc + GFP_ATOMIC),该参数也被用于计算开始内存回收的阀值,默认在开机的时候根据当前的内存计算所得,越大则表示系统会越早开始内存回收。

min_free_kbytes过大可能会导致OOM,太小可能会导致系统出现死锁等问题。

vm.swappiness

该配置用于控制系统将内存swap out到交换空间的积极性,取值范围是[0, 100]。swappiness越大,系统的交换积极性越高,默认是60,如果为0则不会进行交换。

参考资料

  • man proc
  • The Linux Kernel's VFS Layer
  • The VFS in Linux Kernel V2.4
  • openSUSE: System Analysis and Tuning Guide, Chapter 15. Tuning the Memory Management Subsystem
  • Red Hat Enterprise Linux, 5.5 Tuning Virtual Memory
  • Odd behavior
  • Wikipedia:Slab allocation

Logo

更多推荐