资源描述
在我们的生产系统中,因为一些原因,我们在一部分服务器上安装了版本号为 2.6.38 的内核(曾经为 Debian 6 backports 的版本),这个版本被证明是存在很多bug。下面开始描述该内核版本中存在的一个bug。
背景和症状:
系统: Debian 6, 32 bit
内存: 4GiB
作为客户端挂载nfs,nfs server提供了大量的小文件
症状:在运行一段时间后,触发oom killer,大量进程被杀死。但是诡异的是,触发 oom killer 的时候,实际上系统还是有大量的内存是可用的
分析:
幸运的是,我们有日志可以分析,先查看syslog
apache2 invoked oom-killer: gfp_mask=0xd0, order=0, oom_adj=0, oom_score_adj=0
apache2 cpuset=/ mems_allowed=0
Pid: 3270, comm: apache2 Not tainted 2.6.38-bpo.2-686-bigmem #1
Call Trace:
[] ? T.646+0x5a/0×135
[] ? T.645+0×30/0x20e
[] ? security_real_capable_noaudit+0x1f/0×39
[] ? out_of_memory+0x1fa/0×280
…snip
CPU 6: hi: 186, btch: 31 usd: 177
CPU 7: hi: 186, btch: 31 usd: 111
active_anon:131731 inactive_anon:27084 isolated_anon:0
active_file:222873 inactive_file:185534 isolated_file:0
unevictable:685 dirty:51 writeback:0 unstable:0
free:259021 slab_reclaimable:194035 slab_unreclaimable:5733
mapped:5063 shmem:325 pagetables:927 bounce:0
DMA free:4240kB min:784kB low:980kB high:1176kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15808kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:11328kB slab_unreclaimable:312kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
lowmem_reserve[]: 0 867 4032 4032
Normal free:43732kB min:44116kB low:55144kB high:66172kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:8kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:887976kB mlocked:0kB dirty:8kB writeback:0kB mapped:4kB shmem:0kB slab_reclaimable:764812kB slab_unreclaimable:22620kB kernel_stack:2704kB pagetables:24kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:112 all_unreclaimable? yes
lowmem_reserve[]: 0 0 25324 25324
HighMem free:988112kB min:512kB low:40772kB high:81036kB active_anon:526924kB inactive_anon:108336kB active_file:891704kB inactive_file:742128kB unevictable:2740kB isolated(anon):0kB isolated(file):0kB present:3241528kB mlocked:2740kB dirty:196kB writeback:0kB mapped:20248kB shmem:1300kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:3684kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
lowmem_reserve[]: 0 0 0 0
DMA: 4*4kB 2*8kB 43*16kB 14*32kB 12*64kB 6*128kB 2*256kB 0*512kB 1*1024kB 0*2048kB 0*4096kB = 4240kB
Normal: 668*4kB 1385*8kB 1673*16kB 1*32kB 1*64kB 1*128kB 2*256kB 2*512kB 0*1024kB 1*2048kB 0*4096kB = 44328kB
HighMem: 123*4kB 37567*8kB 28863*16kB 4814*32kB 359*64kB 132*128kB 48*256kB 19*512kB 7*1024kB 1*2048kB 0*4096kB = 987988kB
417632 total pagecache pages
8311 pages in swap cache
Swap cache stats: add 20440, delete 12129, find 11215/11322
Free swap = 9923268kB
Total swap = 10000424kB
1245168 pages RAM
1017346 pages HighMem
210680 pages reserved
47964 pages shared
745096 pages non-shared
预备知识:
Memory Zone:
在 32 位系统中,内存被分为 3 个区域,DMA zone,Normal zone 和 HighMem zone,其中 DMA zone 主要用于 DMA 传输数据,位于低地址空间,其服务对象为各种驱动程序,其大小为 16MiB,其中 Normal zone 是 kernel 可以直接访问的地址空间,其大小为 924 MiB,基本上所有的内核数据都在这个区域,同时如果内核要访问更高地址空间的内容,均需要通过 Normal zone 映射过去才可以。地址空间大于 940 MiB 的为 HIghMem zone.
Memory watermark:
在 Linux 的内存管理中,对于内存是否该释放是针对每个 zone 考量的。而考量的参数有 high, low, min 三个参数。当内存可用量小于 low 的时候,kernel 开始释放内存,当内存可用量小于 min 的时候,oom-killer 就开始活跃了。kernel 要么不释放内存,一旦开始释放内存,它将持续释放内存一直到可用的内存大于 high。参考下图:
好,预备知识准备完毕,现在开始进入诊断流程。
让我们先来关注下面这行:
Normal free:43732kB min:44116kB low:55144kB high:66172kB
我们看到 Normal zone 可用的( free ) 内存小于 min,这是触发 oom-killer 的原因。在这个时候,HighMem zone可用空间还是很多,同时几乎没有swap使用。
那么我们看看到底是什么占用了这么多内存,先看内核空间的:
# slabtop -s c | head
Active / Total Objects (% used) : 1610968 / 2176420 (74.0%)
Active / Total Slabs (% used) : 39335 / 39335 (100.0%)
Active / Total Caches (% used) : 61 / 85 (71.8%)
Active / Total Size (% used) : 423355.27K / 461223.70K (91.8%)
Minimum / Average / Maximum Object : 0.01K / 0.21K / 8.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
490588 490588 100% 0.65K 10012 49 320384K nfs_inode_cache
1203584 708306 58% 0.06K 18806 64 75224K kmalloc-64
188960 188520 99% 0.12K 5905 32 23620K dentry
#
我们看到 nfs_inode_cache 占用了大概 300 MiB,在正常情况下,nfs_inode_cache 应该 30 MiB 左右。所以 nfs_inode_cache 在这里是异常的。
我们尝试设置在内存不够用的情况下,优先回收 inode cache,但是没有效果,最后我们通过升级内核到 3.2 版本,系统恢复了正常。
展开阅读全文