Belleğe sınırlı bir LXC kapsayıcısındaki disklere büyük dosyalar yazan uygulamalar neden OOM tarafından öldürülüyor?


10

EDIT2: Bu sorun 3.8.0-25-jenerik # 37-Ubuntu SMP altında da var gibi görünüyor

DÜZENLEME: Soruyu "Linux Bellek Dışı yöneticisi neden dd içeren bir dosyaya yazarak tetiklenecek?" aşağıda açıklanan genel sorundan endişe duyduğumu daha iyi yansıtmak için:

Bellek sınırlamasını (300MB olarak ayarlanmış) aşan bir dosya yazdığımda, OOM katilinin LXC konteynırımdaki sert öldürme işlemleri olduğu zahmetli bir senaryoda çalışıyorum. Ben aslında 512 MB RAM olan bir Xen sanal makinede (EC2 t1.micro) uygulamayı çalıştırdığımda sorun oluşmaz, bu nedenle kapsayıcı bellek sınırına saygı dosya arabelleğe alma ile ilgili bir sorun var gibi görünüyor.

Basit bir örnek olarak, dd tarafından yazılan büyük bir dosyanın nasıl sorunlara neden olacağını gösterebilirim. Yine, bu sayı tüm başvuruları rahatsız ediyor. Uygulamanın önbelleğinin çok büyük hale gelmesi genel sorununu çözmek için arıyorum; "Dd" yi nasıl çalıştırabileceğimi anlıyorum.

Senaryo:

Memory.limit_in_bytes 300 MB olarak ayarlanmış bir LXC kapsayıcı var.

Aşağıdaki gibi ~ 500 MB bir dosya dd denemek:

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

Kabaca% 20 oranında, Linux OOM yöneticisi bu komutla tetiklenir ve bir süreç öldürülür. Söylemeye gerek yok, bu oldukça istenmeyen bir davranıştır; dd, konteynerin içinde çalışan bir program tarafından gerçek bir "yararlı" dosya yazımını simüle eder.

Ayrıntılar: Dosya önbellekleri büyürken (260 MB), rss ve dosya haritası oldukça düşük gibi görünüyor. Yazma sırasında memory.stat'ın nasıl görünebileceğine bir örnek:

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

İşte OOM'un bir öldürmeyi tetiklediği dmesg'den bir macun. Bellek türleri arasındaki ayrımlara pek aşina değilim; göze çarpan bir şey, "Düğüm 0 Normal" çok düşük olsa da, Düğüm 0 DMA32 belleğinde bol miktarda yer olmasıdır. Herkes dosya yazma neden OOM neden açıklayabilir? Bunun olmasını nasıl önleyebilirim?

Günlük:

[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 üzerinde çalışıyorum ip-10-8-139-98 3.2.0-29-virtual # 46-Ubuntu SMP Cum 27 Temmuz 17:23:50 UTC 2012 x86_64 x86_64 x86_64 Amazon EC2'de GNU / Linux.


1
Bunu okuyan herkese hızlı bir özet olarak, bu bir linux çekirdek hatasıdır
UsAaR33

Yanıtlar:


13

Düzenleme: Orijinal cevabımı aşağıda tutacağım, ancak burada neler olduğunu açıklamaya ve sizin için genel bir çözüm sunmaya çalışacağım.

Düzenle 2: Başka bir seçenek sağladı.

Burada vurduğunuz sorun, çekirdeğin G / Ç'yi nasıl yönettiğiyle ilgilidir. Dosya sisteminize bir yazma işlemi yaptığınızda, bu yazma hemen diske kaydedilmez; bu inanılmaz derecede verimsiz olurdu. Bunun yerine, yazma işlemleri sayfa önbelleği olarak adlandırılan bir bellek alanında önbelleğe alınır ve düzenli olarak diske gönderilir. Günlüğünüzün "kirli" bölümünde, henüz diske yazılmamış olan bu sayfa önbelleğinin boyutu açıklanır:

dirty:123816kB

Peki bu kirli önbelleği boşaltan nedir? Neden işini yapmıyor?

Linux'taki 'Flush' kirli sayfaları diske yazmaktan sorumludur. Diske yazma işleminin gerekli olup olmadığını belirlemek için periyodik olarak uyanan bir daemon ve bunları gerçekleştirir. C tipi bir adamsanız, buradan başlayın . Floş inanılmaz derecede verimlidir; gerektiğinde bir şeyleri diske akıtmak için harika bir iş çıkarır. Ve tam olarak nasıl olması gerektiği gibi çalışıyor.

Yıkama , LXC konteynerinizin kendi çekirdeği olmadığından LXC konteynerinizin dışında çalışır . LXC kapları , Linux çekirdeğinin, süreç gruplarının daha iyi sınırlamalarına ve izolasyonuna izin veren, ancak kendi çekirdeği veya sifonu daemonuna izin vermeyen bir grup olarak bir yapı olarak bulunur .

LXC'niz, çekirdeğin sahip olduğu bellekten daha düşük bir bellek sınırına sahip olduğundan, garip şeyler olur. Flush, önbelleğe yazmaları için ana bilgisayarın tam belleğine sahip olduğunu varsayar. LXC'nizdeki bir program büyük bir dosya yazmaya başlar, arabelleğe alır ... arabellekler ... ve sonunda zor sınırına ulaşır ve OOM yöneticisini çağırmaya başlar. Bu belirli bir bileşenin başarısızlığı değildir; beklenen davranış. Biraz. Bu tür şeyler gruplar tarafından ele alınmalı, ancak öyle görünmüyor.

Bu, örnek boyutları arasında gördüğünüz davranışı tamamen açıklar. Mikro örnekte (512MB RAM ile) ve büyük örnekte çok daha erken diske basmaya başlayacaksınız

Tamam, bu mantıklı. Ama işe yaramaz. Hala bana büyük göt dosyası yazmam gerekiyor.

Flush, LXC limitinizin farkında değil. Çekirdeği yamalamak yerine, burada düzeltmeye çalışabileceğiniz şeyler için birkaç seçenek var:

/proc/sys/vm/dirty_expire_centiseconds

Bu, bir sayfanın kirli önbellekte ne kadar süreyle tutulabileceğini ve diske yazılabileceğini denetler. Varsayılan olarak 30 saniyedir; daha hızlı itmeye başlamak için daha düşük ayarlamayı deneyin.

/proc/sys/vm/dirty_background_ratio

Bu, yazmaya zorlamadan önce etkin bellek yıkama yüzdesinin dolmasına izin verildiğini denetler. Burada tam toplamı sıralayan biraz karışıklık var, ancak en kolay açıklama sadece toplam belleğinize bakmaktır. Varsayılan olarak% 10'dur (bazı dağıtımlarda% 5'tir). Bunu daha alçak yapın; daha erken yazmayı diske zorlar ve LXC'nizin sınırlarının dolmasını engelleyebilir.

Dosya sistemine biraz vidalayamaz mıyım?

İyi evet. Ancak bunu test ettiğinizden emin olun .. performansı etkileyebilirsiniz. Bunu yazacağınız / etc / fstab dizinindeki bağlantı noktalarınıza ' eşitleme ' bağlama seçeneğini ekleyin .

Orijinal cevap:

DD tarafından kullanılan blok boyutunu azaltmayı deneyin:

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

Bir kerede yalnızca bir sektör yazabilirsiniz (eski HDD'lerde 512 bayt, daha yenilerinde 4096). DD yazma işlemleri diske kabul edebileceğinden daha hızlı yazdırıyorsa, yazma işlemlerini bellekte önbelleğe almaya başlar. Bu yüzden dosya önbelleğiniz büyüyor.


Dosya nesnesini el ile temizlediğim python'da benzer testler çalıştırırsam, hata yine de benzer olasılıkla gerçekleşir. Önbellek elbette büyüyor, ancak bu tasfiye edilmesi, öldürülmekte olan süreçten ziyade düşünülecekti.
UsAaR33

1
Zaten bir şans verirdim. Python ile bir fsync () zorlama buldum her zaman beklediğiniz şeyi yapmaz.
alexphilipp

1
@ UsAaR33 Daha hızlı disk alın.
tink

1
@ UsAaR33 Bir uygulama olabildiğince çabuk yazacaktır; çekirdeğin IO ile çalışmasını bekler. Daha önce bir LXC konteyneri kullanmadım, ama bir cursory bakışta, oluşturduğu krokinde kendi çekirdeğini sağlamıyor gibi görünüyor mu? Bu durumda, çekirdek IO'ya mevcut ana bilgisayar sisteminin tam belleğine sahip olduğu varsayımını vermektedir. Oranı 300MB ile sınırladığınız hakkında hiçbir fikri yok. Bu sınıra ulaşıldığında, OOM işlemleri öldürmeye başlar.
alexphilipp

1
@ UsAaR33: Kötü ayarlar kötü sonuçlara neden olur. Sistemin bir kısmına çok fazla belleğin önbellek olarak kullanılabileceği, sistemin başka bir kısmına önbellek çok büyükse işlemleri öldürmesi söylenir. Neden bol miktarda RAM varsa diski beklesin ki? Ve bol miktarda RAM varsa, neden kullanmasına izin vermiyorsunuz?
David Schwartz

3

Dosyanız / tmp dosyasına mı yazılıyor? Öyleyse, gerçek bir dosya sisteminde olmayabilir, ancak diskte yerleşik olabilir. Böylece, dosyaya yazarken, dosyanın ihtiyaçlarını karşılamak için giderek daha fazla bellek alınır. Sonunda, bellek + takas alanı tükenir ve performansınız tamamen hayal kırıklığına uğrar.


Alttaki diske yazmayı tetikleyen bir AUFS bağında bulunan $ HOME'a yazıyor. (EC2 EBS)
UsAaR33 15:13

2

RAM diskine yazmadığınız sürece, oflag = direct komutunu kullanarak önbelleğe almayı önleyebilirsiniz

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

direct "Geçersiz bağımsız değişken" hatasına neden olur, ancak oflag = dsync kullanımı işe yarar.
UsAaR33

adam sayfası için "veri için doğrudan kullanım doğrudan I / O" göre, sizin için işe yaramadı eğer üzgünüm
Kevin Parker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.