为什么应用程序在内存限制的LXC容器中将大文件写入磁盘被OOM杀死?

编辑2:此问题似乎也存在以及3.8.0-25 – generics#37 – Ubuntu的SMP

编辑:我修改了原来的标题“为什么会通过写入与dd文件触发Linux内存不足的经理”的问题? 以更好地反映我担心​​的一般问题如下:

当我写一个超过内存限制(设置为300MB)的文件时,我遇到了一个麻烦的情况,即OOM杀手在我的LXC容器中进行了严酷的查杀过程。 当我在Xen虚拟机(EC2 t1.micro)上运行应用程序时,实际上只有512 MB内存,所以这个问题不会发生,所以文件缓冲方面似乎存在一些问题,涉及容器内存限制。

作为一个简单的例子,我可以演示一个由dd编写的大文件如何导致问题。 再次,这个问题困扰所有的应用程序。 我正在寻求解决应用程序的caching的一般问题变得太大, 我明白我可以如何做“dd”的工作。

场景:

我有一个LXC容器,其中memory.limit_in_bytes设置为300 MB。

我试图dd一个〜500 MB的文件,如下所示:

dd if=/dev/zero of=test2 bs=100k count=5010 

大概有20%的时间,Linux OOMpipe理器被这个命令触发,一个进程被终止。 不用说,这是非常意想不到的行为; dd是为了模拟在容器内部运行的程序写入的实际“有用的”文件。

详细信息:虽然文件caching变大(260 MB),rss和文件映射似乎保持相当低。 下面是在写入过程中可能看起来像memory.stat的一个例子:

 cache 278667264 rss 20971520 mapped_file 24576 pgpgin 138147 pgpgout 64993 swap 0 pgfault 55054 pgmajfault 2 inactive_anon 10637312 active_anon 10342400 inactive_file 278339584 active_file 319488 unevictable 0 hierarchical_memory_limit 300003328 hierarchical_memsw_limit 300003328 total_cache 278667264 total_rss 20971520 total_mapped_file 24576 total_pgpgin 138147 total_pgpgout 64993 total_swap 0 total_pgfault 55054 total_pgmajfault 2 total_inactive_anon 10637312 total_active_anon 10342400 total_inactive_file 278339584 total_active_file 319488 total_unevictable 0 

这是一个来自dmesg的粘贴,OOM触发了杀死。 我不太熟悉记忆types之间的区别; 突出的一点是,虽然“节点0正常”非常低,但有大量节点0的DMA32内存空闲。 任何人都可以解释为什么文件写入造成的OOM? 我如何防止这种情况发生?

日志:

 [1801523.686755] Task in /lxc/c-7 killed as a result of limit of /lxc/c-7 [1801523.686758] memory: usage 292972kB, limit 292972kB, failcnt 39580 [1801523.686760] memory+swap: usage 292972kB, limit 292972kB, failcnt 0 [1801523.686762] Mem-Info: [1801523.686764] Node 0 DMA per-cpu: [1801523.686767] CPU 0: hi: 0, btch: 1 usd: 0 [1801523.686769] CPU 1: hi: 0, btch: 1 usd: 0 [1801523.686771] CPU 2: hi: 0, btch: 1 usd: 0 [1801523.686773] CPU 3: hi: 0, btch: 1 usd: 0 [1801523.686775] CPU 4: hi: 0, btch: 1 usd: 0 [1801523.686778] CPU 5: hi: 0, btch: 1 usd: 0 [1801523.686780] CPU 6: hi: 0, btch: 1 usd: 0 [1801523.686782] CPU 7: hi: 0, btch: 1 usd: 0 [1801523.686783] Node 0 DMA32 per-cpu: [1801523.686786] CPU 0: hi: 186, btch: 31 usd: 158 [1801523.686788] CPU 1: hi: 186, btch: 31 usd: 114 [1801523.686790] CPU 2: hi: 186, btch: 31 usd: 133 [1801523.686792] CPU 3: hi: 186, btch: 31 usd: 69 [1801523.686794] CPU 4: hi: 186, btch: 31 usd: 70 [1801523.686796] CPU 5: hi: 186, btch: 31 usd: 131 [1801523.686798] CPU 6: hi: 186, btch: 31 usd: 169 [1801523.686800] CPU 7: hi: 186, btch: 31 usd: 30 [1801523.686802] Node 0 Normal per-cpu: [1801523.686804] CPU 0: hi: 186, btch: 31 usd: 162 [1801523.686806] CPU 1: hi: 186, btch: 31 usd: 184 [1801523.686809] CPU 2: hi: 186, btch: 31 usd: 99 [1801523.686811] CPU 3: hi: 186, btch: 31 usd: 82 [1801523.686813] CPU 4: hi: 186, btch: 31 usd: 90 [1801523.686815] CPU 5: hi: 186, btch: 31 usd: 99 [1801523.686817] CPU 6: hi: 186, btch: 31 usd: 157 [1801523.686819] CPU 7: hi: 186, btch: 31 usd: 138 [1801523.686824] active_anon:60439 inactive_anon:28841 isolated_anon:0 [1801523.686825] active_file:110417 inactive_file:907078 isolated_file:64 [1801523.686827] unevictable:0 dirty:164722 writeback:1652 unstable:0 [1801523.686828] free:445909 slab_reclaimable:176594 slab_unreclaimable:14754 [1801523.686829] mapped:4753 shmem:66 pagetables:3600 bounce:0 [1801523.686831] Node 0 DMA free:7904kB min:8kB low:8kB high:12kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:7648kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [1801523.686841] lowmem_reserve[]: 0 4016 7048 7048 [1801523.686845] Node 0 DMA32 free:1770072kB min:6116kB low:7644kB high:9172kB active_anon:22312kB inactive_anon:12128kB active_file:4988kB inactive_file:2190136kB unevictable:0kB isolated(anon):0kB isolated(file):256kB present:4112640kB mlocked:0kB dirty:535072kB writeback:6452kB mapped:4kB shmem:4kB slab_reclaimable:72888kB slab_unreclaimable:1100kB kernel_stack:120kB pagetables:832kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [1801523.686855] lowmem_reserve[]: 0 0 3031 3031 [1801523.686859] Node 0 Normal free:5660kB min:4616kB low:5768kB high:6924kB active_anon:219444kB inactive_anon:103236kB active_file:436680kB inactive_file:1438176kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3104640kB mlocked:0kB dirty:123816kB writeback:156kB mapped:19008kB shmem:260kB slab_reclaimable:633488kB slab_unreclaimable:57916kB kernel_stack:2800kB pagetables:13568kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [1801523.686869] lowmem_reserve[]: 0 0 0 0 [1801523.686873] Node 0 DMA: 2*4kB 3*8kB 0*16kB 2*32kB 4*64kB 3*128kB 2*256kB 1*512kB 2*1024kB 2*2048kB 0*4096kB = 7904kB [1801523.686883] Node 0 DMA32: 129*4kB 87*8kB 86*16kB 89*32kB 87*64kB 65*128kB 12*256kB 5*512kB 2*1024kB 13*2048kB 419*4096kB = 1769852kB [1801523.686893] Node 0 Normal: 477*4kB 23*8kB 1*16kB 5*32kB 0*64kB 3*128kB 3*256kB 1*512kB 0*1024kB 1*2048kB 0*4096kB = 5980kB [1801523.686903] 1017542 total pagecache pages [1801523.686905] 0 pages in swap cache [1801523.686907] Swap cache stats: add 0, delete 0, find 0/0 [1801523.686908] Free swap = 1048572kB [1801523.686910] Total swap = 1048572kB [1801523.722319] 1837040 pages RAM [1801523.722322] 58337 pages reserved [1801523.722323] 972948 pages shared [1801523.722324] 406948 pages non-shared [1801523.722326] [ pid ] uid tgid total_vm rss cpu oom_adj oom_score_adj name [1801523.722396] [31266] 0 31266 6404 511 6 0 0 init [1801523.722445] [32489] 0 32489 12370 688 7 -17 -1000 sshd [1801523.722460] [32511] 101 32511 10513 325 0 0 0 rsyslogd [1801523.722495] [32625] 0 32625 17706 838 2 0 0 sshd [1801523.722522] [32652] 103 32652 5900 176 0 0 0 dbus-daemon [1801523.722583] [ 526] 0 526 1553 168 5 0 0 getty [1801523.722587] [ 530] 0 530 1553 168 1 0 0 getty [1801523.722593] [ 537] 2007 537 17706 423 5 0 0 sshd [1801523.722629] [ 538] 2007 538 16974 5191 1 0 0 python [1801523.722650] [ 877] 2007 877 2106 157 7 0 0 dd [1801523.722657] Memory cgroup out of memory: Kill process 538 (python) score 71 or sacrifice child [1801523.722674] Killed process 538 (python) total-vm:67896kB, anon-rss:17464kB, file-rss:3300kB 

我在Linux上运行ip-10-8-139-98 3.2.0-29-virtual#46-Ubuntu SMP Fri Jul 27 17:23:50 UTC 2012 x86_64 x86_64 x86_64在Amazon EC2上的GNU / Linux。

编辑:我会保留我原来的答案在下面,但我会尽力解释这里发生的事情,并为您提供一个通用的解决scheme。

编辑2:提供了另一个选项。

你在这里遇到的问题与内核如何pipe理I / O有关。 写入文件系统时,写入不会立即提交到磁盘; 这将是非常低效的。 相反,写入caching在称为页面caching的内存区域,并周期性地以块的forms写入磁盘。 日志的“脏”部分描述了尚未写入磁盘的此页高速caching的大小:

 dirty:123816kB 

那么什么东西清空这个脏的caching? 为什么不这样做呢?

Linux上的“刷新”负责将脏页写入磁盘。 这是一个守护进程,定期唤醒,以确定是否需要写入磁盘,如果是,执行它们。 如果你是一个C型的家伙,从这里开始。 冲洗效率非常高, 它在需要的时候把东西刷到磁盘上做的很好。 它正在如何工作。

因为你的LXC容器没有自己的内核,所以Flush运行你的LXC容器之外 。 LXC容器作为围绕cgroups的构造而存在,这是Linux内核的一个特性,它允许更好地限制和隔离进程组,而不是它自己的内核或flush守护进程。

由于你的LXC的内存限制低于内核的可用内存,奇怪的事情发生了。 Flush假定它拥有主机caching写入的全部内存.LXC中的一个程序开始写入一个大文件,它缓冲…缓冲……并最终达到硬限制,并开始调用OOMpipe理器。 这不是任何特定组件的失败; 这是预期的行为。 有点。 这种事情应该由cgroups处理,但似乎并不是这样。

这完全解释了您在实例大小之间看到的行为。 在微型实例(512MB RAM)上,您将开始刷新磁盘,而不是在大型实例上

好的,这是有道理的。 但是没用。 我仍然需要给我写一个大屁股文件。

那么,冲洗不知道你的LXC限制。 所以不是修补内核,而是可以尝试调整的东西有几个选项:

 /proc/sys/vm/dirty_expire_centiseconds 

这控制了一个页面可以在脏caching中保存多久并写入磁盘。 默认情况下是30秒; 尝试将其设置得更低以开始更快地推出。

 /proc/sys/vm/dirty_background_ratio 

这将控制在启动强制写入之前允许填充的活动内存刷新的百分比。 这里有一些摆弄的东西,最简单的解释就是看看你的总内存。 默认情况下是10%(一些发行版本是5%)。 设置这个较低; 它会强制写入到磁盘更快,并可能会让你的LXC超出它的限制。

我不能只是拧一下文件系统?

那么,是的。 但是请确保你testing了这一点..你可能会影响性能。 在/ etc / fstab中你将要写入的地方加载' sync '挂载选项。

原始答案:

尝试减lessDD使用的块大小:

 dd if=/dev/zero of=test2 bs=512 count=1024000 

一次只能写入一个扇区(较旧的硬盘为512字节,较新的为4096字节)。 如果DD正在向磁盘写入数据的速度比磁盘可以接受的速度快,则它将开始将写入caching到内存中。 这就是为什么你的文件caching在增长。

你的文件是写入/ tmp吗? 如果是这样,它可能不是在实际的文件系统上,而是驻留在磁盘上。 因此,当你写信给它时,越来越多的内存被拿走,以满足文件的需要。 最终,内存+交换空间耗尽,性能下降到令人沮丧的地步。

除非您正在写入RAM磁盘,否则您可以使用oflag = direct避免caching

 dd if=/dev/zero of=test2 bs=100k oflag=direct count=5010