@gy-ban
2016-11-27T09:30:21.000000Z
字数 4355
阅读 1183
技术
最近在查看zabbix监控的时候,发现一台服务器内存使用超过85%;而另外一个监控软件new relic则显示只使用了20%还不到。我只好登录到那台服务器进行查看:
[bhuser@boohee-dragon ~]$ free -m
total used free shared buffers cached
Mem: 15950 15682 267 27 321 1625
-/+ buffers/cache: 13735 2215
Swap: 16383 44 16339
通过free查看确实使用了将近14G,然后我用top查看一下,到底是哪个进程吃了这么大内存:
[bhuser@boohee-dragon ~]$ top
top - 09:38:24 up 225 days, 18:14, 1 user, load average: 0.36, 0.34, 0.36
Tasks: 288 total, 1 running, 287 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 16333464k total, 16066764k used, 266700k free, 329620k buffers
Swap: 16777212k total, 45060k used, 16732152k free, 1664812k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3173 bhuser 20 0 8095m 1.4g 119m S 0.0 9.0 14198:25 java
23493 mysql 20 0 3582m 410m 5712 S 0.0 2.6 4286:26 mysqld
2364 rabbitmq 20 0 4206m 36m 1712 S 0.0 0.2 617:14.78 beam.smp
30104 zabbix 20 0 161m 29m 27m S 0.0 0.2 11:58.55 zabbix_server
30106 zabbix 20 0 161m 29m 27m S 0.0 0.2 12:01.10 zabbix_server
30102 zabbix 20 0 161m 29m 27m S 0.0 0.2 11:55.26 zabbix_server
30103 zabbix 20 0 161m 29m 27m S 0.0 0.2 11:59.26 zabbix_server
30087 zabbix 20 0 256m 28m 27m S 0.0 0.2 113:50.06 zabbix_server
30083 zabbix 20 0 256m 28m 27m S 0.0 0.2 113:48.63 zabbix_server
30084 zabbix 20 0 256m 28m 27m S 0.0 0.2 113:48.54 zabbix_server
30085 zabbix 20 0 256m 28m 26m S 0.0 0.2 113:42.51 zabbix_server
30086 zabbix 20 0 256m 28m 26m S 0.0 0.2 113:51.84 zabbix_server
24243 apache 20 0 408m 24m 4244 S 0.0 0.2 0:33.10 httpd
24105 apache 20 0 408m 24m 4220 S 0.0 0.2 0:37.66 httpd
31776 apache 20 0 407m 24m 4248 S 0.0 0.2 0:33.48 httpd
31771 apache 20 0 407m 24m 4248 S 0.0 0.2 0:38.53 httpd
31770 apache 20 0 407m 24m 4240 S 0.0 0.2 0:33.80 httpd
通过top查看,并没有发现大内存的进程存在;
然后使用ps统计了下所有进程占用的总内存:
[bhuser@boohee-dragon ~]$ ps aux | awk '{mem += $6} END {print mem/1024/1024}'
2.17601
所有进程使用内存之和也就不过2G多,但系统为什么显示已经使用了14G,另外的12G内存到底被被谁占用了?还有就是new relic为什么监控的内存使用也只有2G,这难道还有什么隐情?
带着疑惑,我问了下google,许久之后才了解到,free没有专门统计另一项缓存: Slab。
Slab Allocation是Linux 2.2之后引入的一个内存管理机制,专门用于缓存内核的数据对象,可以理解为一个内核专用的对象池,可以提高系统性能并减少内存碎片。(Linux 2.6.23之后,SLUB成为了默认的allocator。)
[bhuser@boohee-dragon ~]$ cat /proc/meminfo
Slab: 11881152 kB
SReclaimable: 11839140 kB
SUnreclaim: 42012 kB
主要列出了与slab相关的信息,其它的都省略掉了;其中Slab:11881152kB表示slab使用的缓存;SReclaimable(Linux 2.6.19+):11839140kB都是clean的缓存,可回收的;SUnreclaim:42012kB
表示不可回收的。
那这将近12G的slab缓存到底用在哪里了,我们可以通过slabtop命令进行查看:
Active / Total Objects (% used) : 58926402 / 59679718 (98.7%)
Active / Total Slabs (% used) : 2968740 / 2968754 (100.0%)
Active / Total Caches (% used) : 108 / 186 (58.1%)
Active / Total Size (% used) : 11065539.12K / 11143861.49K (99.3%)
Minimum / Average / Maximum Object : 0.02K / 0.19K / 4096.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
58293780 58293780 26% 0.19K 2914689 20 11658756K dentry
1157656 417218 36% 0.10K 31288 37 125152K buffer_head
46688 46655 99% 0.98K 11672 4 46688K ext4_inode_cache
24409 23499 96% 0.05K 317 77 1268K anon_vma_chain
21868 19578 89% 0.55K 3124 7 12496K radix_tree_node
20272 20143 99% 0.03K 181 112 724K size-32
19399 19231 99% 0.20K 1021 19 4084K vm_area_struct
12862 11612 90% 0.06K 218 59 872K size-64
12312 12275 99% 0.14K 456 27 1824K sysfs_dir_cache
9581 8983 93% 0.05K 143 67 572K anon_vma
8480 8282 97% 0.07K 160 53 640K selinux_inode_security
8010 7210 90% 0.12K 267 30 1068K size-128
4800 4723 98% 0.19K 240 20 960K size-192
4668 4585 98% 0.58K 778 6 3112K inode_cache
4185 3534 84% 0.25K 279 15 1116K filp
3444 3017 87% 0.30K 287 12 1148K nf_conntrack_ffffffff81b280e0
2076 2028 97% 1.00K 519 4 2076K size-1024
1572 1559 99% 0.64K 262 6 1048K proc_inode_cache
1296 1275 98% 0.50K 162 8 648K size-512
1272 1161 91% 0.07K 24 53 96K Acpi-Operand
通过slabtop我们看到系统中有大量dentry(directory entry cache)占用内存,那个这个dentry是什么了?
dentry(directory entry cache)目录项高速缓存,是Linux为了提高目录项对象的处理效率而设计的;它记录了目录项到inode的映射关系。因此,当应用程序发起stat系统调用时,就会创建对应的dentry_cache项(更进一步,如果每次stat的文件都是不存在的文件,那么总是会有大量新的dentry_cache项被创建)。
通过/proc/sys/vm/drop_caches这个配置项,我们可以手动清除指定的可回收缓存(SReclaimable)
echo 2 > /proc/sys/vm/drop_caches
需要注意的是,手动清除缓存可能会在一段时间内降低系统性能。原则上不推荐这么做,因为如果有需要,系统会自动释放出内存供其他程序使用。
另外,手动清除Slab缓存是一个治标不治本的办法。因为问题不在Slab,而在于我们那个会引起Slab缓存飙涨的进程(我这里应该是rsync)。实际操作的时候发现,清除缓存一段时间后,Slab缓存很快又会“反弹”回去。如果需要治本,要么搞定问题进程,要么修改系统配置。(目前这台服务器的问题进程还在分析当中。。。)
通常不建议调整系统参数,这样风险比较大,除非你已经熟练的掌握。
/etc/sysctl.conf里有几个对内存管理影响比较大的配置
vm.vfs_cache_pressure
系统在进行内存回收时,会先回收page cache, inode cache, dentry cache和swap cache。vfs_cache_pressure越大,每次回收时,inode cache和dentry cache所占比例越大
vfs_cache_pressure默认是100,值越大inode cache和dentry cache的回收速度会越快,越小则回收越慢,为0的时候完全不回收
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则不会进行交换。