メモリーが制限されたLXCコンテナー内のアプリケーションがディスクに大きなファイルを書き込むと、なぜOOMによって強制終了されるのですか?


10

EDIT2:この問題は3.8.0-25-generic#37-Ubuntu SMPにも存在するようです

編集:「なぜddを使用してファイルに書き込むことによってLinuxのメモリ不足マネージャーがトリガーされるのですか?」という元のタイトルからの質問を変更しました。以下で説明する一般的な問題について心配していることをよりよく反映するために:

メモリ制限(300MBに設定)を超えるサイズのファイルを書き込むと、LXCコンテナーでOOMキラーがプロセスを強制終了するという厄介なシナリオに遭遇しています。実際には512 MBのRAMしかないXen仮想マシン(EC2 t1.micro)でアプリケーションを実行しても問題は発生しないため、コンテナーのメモリ制限に関するファイルバッファリングに問題があるようです。

簡単な例として、ddによって書き込まれた大きなファイルがどのように問題を引き起こすかを示します。繰り返しますが、この問題はすべてのアプリケーションを悩ませています。アプリケーションのキャッシュが大きくなりすぎるという一般的な問題を解決しようとしています。「dd」を機能させる方法を理解しています。

シナリオ:

LXCコンテナーで、memory.limit_in_bytesが300 MBに設定されています。

私は次のように500 MB以下のファイルをddしようとします。

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

ほぼ20%の時間、Linux OOMマネージャーはこのコマンドによってトリガーされ、プロセスが強制終了されます。言うまでもなく、これは非常に意図しない動作です。ddは、コンテナ内で実行されるプログラムによる実際の「有用な」ファイル書き込みをシミュレートすることを目的としています。

詳細:ファイルキャッシュが大きくなる(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

OOMが強制終了を引き起こしたdmesgからの貼り付けは次のとおりです。記憶の種類の違いにはあまり詳しくありません。際立っていることの1つは、「Node 0 Normal」が非常に低い間、十分なNode 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 27 17:23:50 UTC 2012 x86_64 x86_64 x86_64 GNU / Linux on Amazon EC2。


1
それを読んだすべての人への簡単な要約として、これはLinuxカーネルのバグです
UsAaR33

回答:


13

編集:以下の元の回答はそのままにしますが、ここで何が起こっているのかを説明し、一般的な解決策を提供します。

編集2:別のオプションを提供しました。

ここで発生している問題は、カーネルがI / Oを管理する方法に関係しています。ファイルシステムに書き込みを行っても、その書き込みはすぐにはディスクにコミットされません。それは信じられないほど非効率です。代わりに、書き込みはページキャッシュと呼ばれるメモリ領域にキャッシュされ、定期的にチャンクでディスクに書き込まれます。ログの「ダーティ」セクションは、まだディスクに書き出されていないこのページキャッシュのサイズを示しています。

dirty:123816kB

では、このダーティキャッシュを空にするものは何でしょうか。なぜそれが仕事をしていないのですか?

Linuxの「フラッシュ」は、ダーティページをディスクに書き込む責任があります。これは、定期的に起動してディスクへの書き込みが必要かどうかを判断し、必要な場合はそれらを実行するデーモンです。あなたがCタイプの男なら、ここから始めてください。フラッシュは非常に効率的です。必要に応じて、データをディスクにフラッシュするという優れた機能を果たします。そして、それは想定どおりに機能しています。

LXCコンテナーには独自のカーネルがないため、フラッシュはLXCコンテナーの外部で実行さます。LXCコンテナーはcgroupsの周囲にある構成体として存在します。これはLinuxカーネルの機能であり、プロセスグループをより適切に制限および分離できますが、独自のカーネルやフラッシュデーモンは使用できません。

LXCのメモリ制限はカーネルが使用できるメモリよりも低いため、奇妙なことが起こります。フラッシュは、書き込みをキャッシュするホストの完全なメモリがあることを前提としています。LXCのプログラムは大きなファイルの書き込みを開始し、バッファリング...バッファ...そして最終的にハードリミットに達し、OOMマネージャーの呼び出しを開始します。これは特定のコンポーネントの障害ではありません。予想される動作です。やや。 この種のものはcgroupsで処理する必要がありますが、そうではありません。

これは、インスタンスサイズ間で見られる動作を完全に説明しています。大規模なインスタンスよりもマイクロインスタンス(512MB RAM)のほうがディスクへのフラッシュがはるかに早く開始されます

わかりました。しかし、それは役に立たない。私はまだ大きな尻のファイルを書く必要があります。

ええと、フラッシュはLXCの制限を認識していません。そのため、カーネルにパッチを当てる代わりに、微調整を試みることができるオプションがいくつかあります。

/proc/sys/vm/dirty_expire_centiseconds

これは、ページがダーティキャッシュに保持され、ディスクに書き込まれる期間を制御します。デフォルトでは30秒です。低く設定して、より速く押し出し始めてください。

/proc/sys/vm/dirty_background_ratio

これは、書き込みを強制的に開始する前に、アクティブなメモリフラッシュの何パーセントがいっぱいになるかを制御します。ここで正確な合計を分類するために少しいじくりますが、最も簡単な説明は、あなたの合計メモリを調べることです。デフォルトでは10%です(一部のディストリビューションでは5%です)。これを低く設定してください。ディスクへの書き込みをより早く強制し、LXCの制限を超えないようにする可能性があります。

私はファイルシステムを少しねじ込むことはできませんか?

まあ、そうだろう。ただし、これをテストしてください。パフォーマンスに影響を与える可能性があります。これを書き込む/ etc / fstab のマウントに、 ' sync 'マウントオプションを追加します。

元の答え:

DDが使用するブロックサイズを減らしてみてください。

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

一度に書き込むことができるセクターは1つだけです(古いHDDでは512バイト、新しいHDDでは4096バイト)。DDが書き込みをディスクが受け入れることができるよりも速くディスクにプッシュしている場合、DDは書き込みをメモリにキャッシュし始めます。そのため、ファイルキャッシュが増大しています。


ファイルオブジェクトを手動でフラッシュするpythonで同様のテストを実行した場合でも、同様の確率でエラーが発生することに注意してください。キャッシュはもちろん大きくなりますが、プロセスが強制終了されるのではなく、パージされるはずです。
UsAaR33 2013年

1
とにかく試してみる。Pythonでfsync()を強制しても、期待どおりに動作しないことがあります。
alexphilipp 2013年

1
@ UsAaR33より高速なディスクを取得します。
2013年

1
@ UsAaR33アプリケーションはできる限り速く書き込みます。カーネルがIOを処理することを期待しています。以前にLXCコンテナーを使用したことがありませんが、一見すると、作成したchrootに独自のカーネルを提供していないように見えますか?その場合、カーネルは、ホストシステムの全メモリが利用可能であるという前提でIOを提供しています。レートを300MBに制限したとは思いません。この制限に達すると、OOMはプロセスの強制終了を開始します。
alexphilipp 2013年

1
@ UsAaR33:悪い設定は悪い結果を引き起こします。システムの一部は、大量のメモリをキャッシュとして使用できると通知され、システムの別の部分は、キャッシュが大きすぎる場合はプロセスを強制終了するように通知されます。利用可能なRAMが十分にあるときに、ディスクを待つ必要があるのはなぜですか?利用可能なRAMが十分にある場合は、それを使用させてみませんか?
David Schwartz 2013年

3

ファイルは/ tmpに書き込んでいますか?もしそうなら、それは実際のファイルシステム上ではなく、ディスク上にあるかもしれません。したがって、ファイルに書き込むにつれて、ファイルのニーズを満たすためにますます多くのメモリが奪われます。最終的に、メモリとスワップ領域が不足し、パフォーマンスが完全にフラストレーションを感じるほどに低下します。


これは、基礎となるディスクへの書き込みをトリガーするAUFSマウント上の$ HOMEに書き込んでいます。(EC2 EBS)
UsAaR33 2013年

2

RAMディスクに書き込んでいない限り、oflag = directを使用してキャッシュを回避できます

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

directは「無効な引数」エラーを引き起こしますが、oflag = dsyncを使用しても機能します。
UsAaR33 2013年

manページの「データの直接使用直接I / O」のように、それがうまくいかなかった場合は申し訳ありません
Kevin Parker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.