เหตุใดแอปพลิเคชันในคอนเทนเนอร์ LXC ที่มีหน่วยความจำ จำกัด จึงเขียนไฟล์ขนาดใหญ่ลงดิสก์โดย OOM


10

EDIT2: ปัญหานี้ดูเหมือนจะมีอยู่ภายใต้ 3.8.0-25-generic # 37-Ubuntu SMP

แก้ไข: ฉันแก้ไขคำถามจากชื่อดั้งเดิมของ "ทำไมตัวจัดการ Linux ไม่อยู่ในหน่วยความจำจึงถูกทริกเกอร์โดยการเขียนไปยังไฟล์ที่มีวว?" เพื่อสะท้อนให้เห็นดีขึ้นว่าฉันเป็นห่วงเกี่ยวกับปัญหาทั่วไปที่อธิบายไว้ด้านล่าง:

ฉันพบสถานการณ์ที่ลำบากที่ OOM killer เป็นกระบวนการฆ่ายากในคอนเทนเนอร์ LXC ของฉันเมื่อฉันเขียนไฟล์ที่มีขนาดเกินขีด จำกัด หน่วยความจำ (ตั้งค่าเป็น 300MB) ปัญหาไม่เกิดขึ้นเมื่อฉันรันแอปพลิเคชันบนเครื่องเสมือน Xen (EC2 t1.micro) ที่จริงมี RAM 512 MB เท่านั้นดังนั้นดูเหมือนว่าจะมีปัญหาบางอย่างกับไฟล์บัฟเฟอร์ที่เกี่ยวข้องกับขีด จำกัด หน่วยความจำคอนเทนเนอร์

ตัวอย่างง่ายๆฉันสามารถแสดงให้เห็นว่าไฟล์ขนาดใหญ่เขียนโดย dd จะทำให้เกิดปัญหา ปัญหานี้อีกครั้งทำให้เกิดปัญหาแอปพลิเคชันทั้งหมด ฉันต้องการแก้ไขปัญหาทั่วไปของแคชแอปพลิเคชันที่ใหญ่เกินไป ฉันเข้าใจว่าฉันสามารถทำงาน "dd" ได้อย่างไร

สถานการณ์:

ฉันมีคอนเทนเนอร์ LXC โดยที่ memory.limit_in_bytes ถูกตั้งค่าเป็น 300 MB

ฉันพยายาม dd ไฟล์ ~ 500 MB ดังต่อไปนี้:

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

ประมาณ 20% ของเวลาผู้จัดการ Linux OOM จะถูกกระตุ้นโดยคำสั่งนี้และกระบวนการถูกฆ่า จำเป็นต้องพูดนี่เป็นพฤติกรรมที่ไม่ได้ตั้งใจอย่างมาก dd มีวัตถุประสงค์เพื่อจำลองการเขียนไฟล์ "มีประโยชน์" จริงโดยโปรแกรมที่รันอยู่ภายในคอนเทนเนอร์

รายละเอียด: ในขณะที่แคชไฟล์มีขนาดใหญ่ (260 MB) rss และการแมปไฟล์ดูเหมือนจะค่อนข้างต่ำ นี่คือตัวอย่างของหน่วยความจำที่มีลักษณะเป็นอย่างไรระหว่างการเขียน:

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

นี่คือ Paste จาก dmesg ที่ OOM เรียกใช้การฆ่า ฉันไม่คุ้นเคยกับความแตกต่างระหว่างประเภทของหน่วยความจำ สิ่งหนึ่งที่โดดเด่นคือในขณะที่ "Node 0 Normal" ต่ำมากมีหน่วยความจำ NMA 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- เสมือน # 46-Ubuntu SMP ศุกร์ 27 ก.ค. 17:23:50 UTC 2012 x86_64 x86_64 x86_64 GNU / Linux ใน Amazon EC2


1
โดยสรุปสำหรับทุกคนที่อ่านนี่เป็นข้อบกพร่องเคอร์เนลของ linux
UsAaR33

คำตอบ:


13

แก้ไข: ฉันจะเก็บคำตอบดั้งเดิมของฉันไว้ด้านล่าง แต่ฉันจะพยายามอธิบายสิ่งที่เกิดขึ้นที่นี่และเสนอวิธีแก้ปัญหาทั่วไปให้คุณ

แก้ไข 2: ระบุตัวเลือกอื่น

ปัญหาที่คุณกดปุ่มตรงนี้เกี่ยวข้องกับวิธีที่เคอร์เนลจัดการ I / O เมื่อคุณทำการเขียนไปยังระบบไฟล์ของคุณการเขียนนั้นไม่ได้ถูกส่งไปยังดิสก์ทันที ที่จะไม่มีประสิทธิภาพอย่างไม่น่าเชื่อ แต่การเขียนจะถูกแคชในพื้นที่ของหน่วยความจำที่เรียกว่าแคชหน้าและเขียนเป็นระยะเป็นระยะในดิสก์ ส่วน "สกปรก" ในบันทึกของคุณอธิบายขนาดของแคชหน้านี้ที่ยังไม่ได้เขียนลงดิสก์:

dirty:123816kB

แล้วแคชที่สกปรกนี้คืออะไร ทำไมมันไม่ทำงาน

'Flush' บน Linux มีหน้าที่เขียนหน้าสกปรกออกสู่ดิสก์ มันเป็นภูตที่ตื่นขึ้นมาเป็นระยะเพื่อตรวจสอบว่าจำเป็นต้องเขียนลงดิสก์หรือไม่และถ้าเป็นเช่นนั้น หากคุณเป็นชนิด C ของผู้ชายเริ่มต้นที่นี่ ล้างมีประสิทธิภาพอย่างไม่น่าเชื่อ มันเป็นงานที่ยอดเยี่ยมในการล้างข้อมูลในดิสก์เมื่อจำเป็น และมันก็ทำงานได้อย่างที่ควรจะเป็น

Flush ทำงานนอกคอนเทนเนอร์ LXC ของคุณเนื่องจากคอนเทนเนอร์ LXC ของคุณไม่มีเคอร์เนลของตัวเอง ภาชนะบรรจุ LXC มีอยู่เป็นโครงสร้างรอบcgroupsซึ่งเป็นคุณลักษณะของเคอร์เนล Linux ที่อนุญาตให้มีข้อ จำกัด และการแยกกลุ่มกระบวนการที่ดีกว่า แต่ไม่ใช่เคอร์เนลหรือ flush daemon ของตัวเอง

เนื่องจาก LXC ของคุณมีขีด จำกัด หน่วยความจำต่ำกว่าหน่วยความจำที่เคอร์เนลมีอยู่สิ่งแปลก ๆ ก็เกิดขึ้น ล้างข้อมูลสมมติว่ามีหน่วยความจำเต็มของโฮสต์ที่จะแคชเขียนโปรแกรมใน LXC ของคุณเริ่มเขียนไฟล์ขนาดใหญ่บัฟเฟอร์ ... บัฟเฟอร์ ... และในที่สุดก็ถึงขีด จำกัด ที่ยากและเริ่มเรียกผู้จัดการ OOM นี่ไม่ใช่ความล้มเหลวขององค์ประกอบเฉพาะใด ๆ มันเป็นพฤติกรรมที่คาดหวัง ชนิดของ สิ่งนี้ควรได้รับการจัดการโดยกลุ่ม cg แต่ดูเหมือนจะไม่เป็นเช่นนั้น

สิ่งนี้จะอธิบายพฤติกรรมที่คุณเห็นระหว่างขนาดอินสแตนซ์อย่างสมบูรณ์ คุณจะเริ่มล้างข้อมูลลงบนดิสก์เร็วกว่าบนอินสแตนซ์ขนาดเล็ก (ที่มี RAM 512MB) เทียบกับอินสแตนซ์ขนาดใหญ่

ตกลงที่เหมาะสม แต่มันไร้ประโยชน์ ฉันยังต้องเขียนไฟล์ตูดใหญ่ให้ฉันด้วย

ล้างไม่ทราบขีด จำกัด LXC ของคุณ ดังนั้นแทนที่จะทำการแกไขเคอร์เนลมีตัวเลือกไม่กี่อย่างที่นี่สำหรับสิ่งที่คุณสามารถปรับแต่งได้:

/proc/sys/vm/dirty_expire_centiseconds

วิธีนี้จะควบคุมระยะเวลาที่เพจสามารถเก็บไว้ในแคชที่สกปรกและเขียนไปยังดิสก์ โดยค่าเริ่มต้นคือ 30 วินาที ลองตั้งค่าให้ต่ำลงเพื่อเริ่มดันมันเร็วขึ้น

/proc/sys/vm/dirty_background_ratio

สิ่งนี้จะควบคุมเปอร์เซ็นต์ของการล้างหน่วยความจำที่ใช้งานซึ่งได้รับอนุญาตให้เติมก่อนที่จะเริ่มบังคับให้เขียน มีปัญหานิดหน่อยที่จะแยกแยะผลรวมที่แน่นอนที่นี่ แต่คำอธิบายที่ง่ายที่สุดคือดูที่หน่วยความจำทั้งหมดของคุณ โดยค่าเริ่มต้นคือ 10% (ในบาง distros เป็น 5%) ตั้งค่าที่ต่ำกว่านี้ มันจะบังคับให้เขียนลงดิสก์เร็วกว่านี้และอาจป้องกัน LXC ของคุณไม่ให้เกินขีด จำกัด

ฉันไม่เพียงแค่สกรูกับระบบแฟ้มเล็กน้อย?

ใช่แล้ว แต่ให้แน่ใจว่าคุณทดสอบสิ่งนี้ .. คุณอาจส่งผลต่อประสิทธิภาพ บนเมานต์ของคุณใน / etc / fstab ที่ซึ่งคุณจะเขียนสิ่งนี้ไปยังให้เพิ่มตัวเลือก' ซิงค์ '

คำตอบเดิม:

ลองลดขนาดบล็อกที่ใช้โดย DD:

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

คุณสามารถเขียนเซกเตอร์ได้ครั้งละหนึ่งเซกเตอร์ (512 ไบต์บน HDD ที่เก่ากว่า 4096 ใหม่กว่า) หาก DD ผลักดันการเขียนไปยังดิสก์เร็วกว่าที่ดิสก์ยอมรับได้มันจะเริ่มแคชการเขียนในหน่วยความจำ นั่นเป็นสาเหตุที่แคชไฟล์ของคุณเพิ่มขึ้น


ฉันควรทราบว่าถ้าฉันใช้การทดสอบที่คล้ายกันในหลามที่ฉันล้างวัตถุไฟล์ด้วยตนเองข้อผิดพลาดยังคงเกิดขึ้นกับความน่าจะเป็นที่คล้ายกัน แน่นอนว่าแคชเพิ่มขึ้น แต่นั่นควรจะได้รับการกำจัดอย่างใดอย่างหนึ่งจะคิดว่ามากกว่ากระบวนการที่ถูกฆ่าตาย
UsAaR33

1
ฉันจะให้มันยิงต่อไป ฉันพบการบังคับให้ fsync () กับ Python ไม่ได้ทำสิ่งที่คุณคาดหวังเสมอไป
alexphilipp

1
@ UsAaR33 รับดิสก์ที่เร็วกว่า
ทิงค์

1
@ UsAaR33 แอปพลิเคชันจะเขียนเร็วที่สุดเท่าที่จะทำได้ คาดว่าเคอร์เนลจะจัดการกับ IO ฉันไม่เคยใช้คอนเทนเนอร์ LXC มาก่อน แต่จากภาพรวมคร่าวๆดูเหมือนว่าจะไม่ให้เคอร์เนลของตัวเองใน chroot มันสร้าง? หากเป็นกรณีนี้เคอร์เนลจะให้ IO กับข้อสันนิษฐานว่ามีหน่วยความจำเต็มของระบบโฮสต์ที่มีอยู่ มันไม่มีความคิดว่าคุณให้คะแนนมันแค่ 300MB เมื่อถึงขีด จำกัด ดังกล่าว OOM จะเริ่มกระบวนการฆ่า
alexphilipp

1
@ UsAaR33: การตั้งค่าที่ไม่ถูกต้องทำให้เกิดผลลัพธ์ที่ไม่ดี ส่วนหนึ่งของระบบจะบอกว่าหน่วยความจำจำนวนมากสามารถใช้เป็นแคชส่วนอื่นของระบบจะบอกให้ฆ่ากระบวนการหากแคชมีขนาดใหญ่เกินไป เหตุใดจึงต้องรอดิสก์เมื่อมี RAM จำนวนมาก และถ้าหากมี RAM เหลือเฟือทำไมไม่ลองใช้มันดูล่ะ
David Schwartz

3

ไฟล์ของคุณเขียนถึง / tmp หรือไม่? ถ้าเป็นเช่นนั้นอาจไม่ได้อยู่ในระบบไฟล์จริง แต่อาศัยอยู่ในดิสก์ ดังนั้นเมื่อคุณเขียนลงไปหน่วยความจำมากขึ้นจะถูกนำไปใช้เพื่อกำจัดความต้องการของไฟล์ ในที่สุดคุณหมดพื้นที่หน่วยความจำ + พื้นที่สว็อปและประสิทธิภาพการทำงานของคุณลดลงจนถึงจุดที่ยุ่งยากที่สุด


มันกำลังเขียนถึง $ HOME ซึ่งอยู่บนการเมานต์ AUFS ซึ่งทริกเกอร์การเขียนไปยังดิสก์ต้นแบบ (EC2 EBS)
UsAaR33

2

นอกจากว่าคุณกำลังเขียนไปยังดิสก์ RAM คุณสามารถหลีกเลี่ยงการแคชโดยใช้ oflag = direct

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

direct ทำให้เกิดข้อผิดพลาด "อาร์กิวเมนต์ไม่ถูกต้อง" แต่การใช้ oflag = dsync ทำงานได้
UsAaR33

ฉันขอโทษถ้ามันไม่ได้ผลสำหรับคุณตามหน้าคน "ใช้โดยตรง I / O โดยตรงสำหรับข้อมูล"
Kevin Parker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.