การแตกแฟรกเมนต์หน่วยความจำ Linux


20

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

ฉันดู / proc / buddyinfo เป็นพิเศษ ฉันต้องการทราบว่ามีวิธีใดที่ดีกว่า (ไม่ใช่แค่คำสั่ง CLI ต่อ se โปรแกรมหรือพื้นหลังทางทฤษฎีจะทำ) เพื่อดู


ฉันไม่ได้มองหาโซลูชั่น commandline ด่วน ๆ โปรแกรม / ทฤษฎีง่าย ๆ ก็จะทำเช่นกัน ดังนั้นฉันไม่ได้ถามที่ serverfault
Raghu

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

@skwllsp - แก้ไขคำตอบของฉันให้เจาะจงยิ่งขึ้น
Tim Post

@Raghu - ฉันไม่คาดหวังว่าผู้ดูแลระบบส่วนใหญ่จะปรับเปลี่ยนรหัสเคอร์เนลเพื่อให้การจัดการหน่วยความจำทำงานแตกต่างกันอย่างไรก็ตามผู้ดูแลระบบ Linux ที่มีทักษะควรรู้ภาพรวมอย่างน้อยเกี่ยวกับวิธีที่ Linux จัดการหน่วยความจำ คำถามนี้อยู่ในสายจริงๆ ฉันลงคะแนนให้โยกย้ายเพียงเพราะฉันไม่สามารถแนะนำรหัส (ในคำตอบของฉัน) ที่ตอบคำถามของคุณ การอ่านจาก / proc หรือการใช้vmstatเป็นประสบการณ์ของผู้ใช้ทั่วไป หากคุณกำลังเขียนโปรแกรมเพื่อทำสิ่งเดียวกันมันจะแตกต่างกัน หากคุณตั้งใจจะใช้ bash เพื่อเก็บเกี่ยวข้อมูลนี้แก้ไขคำถามของคุณจะไม่ถูกปิด :)
Tim Post

@Tim - ตามที่ฉันแนะนำมันไม่ได้เป็นเพียงคำสั่ง bash / cli ที่ฉันอยากรู้ฉันต้องการข้อมูลเพื่อช่วยฉันในกระบวนการเปรียบเทียบของฉัน (เพื่อวิเคราะห์ผลลัพธ์ไม่ใช่เรียกใช้)
Raghu

คำตอบ:


12

ฉันกำลังตอบแท็กคำตอบของฉันเฉพาะกับLinuxเท่านั้น

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

การแมปเคอร์เนลของที่อยู่ที่ได้รับ (ของจริง) เป็นส่วนตัว มีเหตุผลที่ดีมากที่ userspace มองพวกเขาในขณะที่เคอร์เนลแสดงพวกเขาเนื่องจากเคอร์เนลจำเป็นต้องสามารถ overcommit โดยไม่ทำให้ผู้ใช้สับสน กระบวนการของคุณได้รับพื้นที่ที่อยู่"Disneyfied"ที่ดีต่อเนื่องซึ่งใช้งานได้โดยไม่สนใจว่าสิ่งที่เคอร์เนลทำกับหน่วยความจำนั้นอยู่เบื้องหลัง

เหตุผลที่คุณเห็นประสิทธิภาพลดลงในเซิร์ฟเวอร์ที่ใช้งานมานานน่าจะเป็นเพราะบล็อกที่จัดสรรซึ่งไม่ได้ล็อคอย่างชัดเจน (เช่นmlock()/ mlockall()หรือposix_madvise()) และไม่ได้รับการแก้ไขในระยะเวลาหนึ่งซึ่งได้ถูกเพจเอาต์ซึ่งหมายความว่าบริการของคุณ พวกเขา การแก้ไขพฤติกรรมนี้ทำให้กระบวนการของคุณเป็นเพื่อนบ้านที่ไม่ดีซึ่งเป็นสาเหตุที่หลายคนใส่ RDBMS ไว้ในเซิร์ฟเวอร์ที่แตกต่างจากเว็บ / php / python / ruby ​​/ อะไรก็ตาม วิธีเดียวที่จะแก้ไขปัญหานี้ได้คือการลดการแข่งขันสำหรับบล็อกที่ต่อเนื่องกัน

การแตกแฟรกเมนต์สามารถสังเกตเห็นได้จริง ๆ เท่านั้น (ในกรณีส่วนใหญ่) เมื่อเพจ A อยู่ในหน่วยความจำและเพจ B ย้ายไปสลับ โดยปกติแล้วการเริ่มต้นบริการของคุณอีกครั้งดูเหมือนจะ 'รักษา' สิ่งนี้ แต่เพียงเพราะเคอร์เนลยังไม่ได้มีโอกาสหน้ากระบวนการออก '(ตอนนี้) บล็อกที่จัดสรรใหม่ภายในขอบเขตอัตราส่วน overcommit

ในความเป็นจริงการเริ่มต้นใหม่ (สมมติว่า) 'apache' ภายใต้ภาระสูงมีแนวโน้มที่จะส่งบล็อกที่เป็นเจ้าของโดยบริการอื่น ๆ ตรงไปยังดิสก์ ดังนั้นใช่ 'apache' จะดีขึ้นในช่วงเวลาสั้น ๆ แต่ 'mysql' อาจประสบ .. อย่างน้อยก็จนกว่าเคอร์เนลจะทำให้พวกเขามีปัญหาเท่ากันเมื่อไม่มีหน่วยความจำกายภาพเหลือเฟือ

เพิ่มหน่วยความจำเพิ่มเติมหรือแยกกันตามความต้องการของmalloc()ผู้บริโภค :) ไม่ใช่เพียงแค่การแยกส่วนที่คุณต้องมอง

ลองvmstatดูภาพรวมของสิ่งที่ถูกจัดเก็บไว้ที่ใด


ขอบคุณสำหรับคำตอบ ฉันใช้เพจขนาดใหญ่ (ขนาด = 2048KB แต่ละอัน) สำหรับ mysql - พูลบัฟเฟอร์ innodb - เพื่อดูว่ามันดีแค่ไหน (ใช้ sysbench) เริ่มแรกเมื่อกระบวนการ uptime (และแม้แต่ uptime ของระบบ) อยู่ในระดับต่ำมันให้ผลลัพธ์ที่ดีมาก อย่างไรก็ตามประสิทธิภาพของมันเริ่มลดลงในการทำงานหลายครั้ง เกี่ยวกับหน้าเว็บที่คุณพูดถึงฉันก็สังเกตเห็นว่ามีกิจกรรม VM สูง แต่ฉันคิดว่ามันอาจเป็นเพราะเกณฑ์มาตรฐานและการล้างบันทึกข้อมูล Innodb (กิจกรรม vm สูงกว่าที่มีหน้าเว็บใหญ่กว่าที่ไม่มี) ฉันยังตั้งค่า vm.swappiness เป็น 1 ฉันไม่สามารถสังเกตเห็นการเปลี่ยนแปลงที่รุนแรง
Raghu

ตามคู่มือที่ดี "หน้าขนาดใหญ่ไม่สามารถสลับออกได้ภายใต้ความกดดันของหน่วยความจำ" ฉันคิดว่านี่เป็นคำตอบที่ดีในหน่วยความจำมาตรฐาน w / r / t แต่ไม่ใช่สำหรับ hugepages
Dan Pritts

5

เมล็ด

ในการรับดัชนีการแตกแฟรกเมนต์ปัจจุบันให้ใช้:

sudo cat /sys/kernel/debug/extfrag/extfrag_index

หากต้องการจัดเรียงข้อมูลหน่วยความจำเคอร์เนลลองดำเนินการ:

sysctl vm.compact_memory=1  

นอกจากนี้คุณลองปิด Transparent Huge Pages (aka THP) และ / หรือปิดการใช้งาน swap (หรือลดลงswappiness)

userspace

เพื่อลดการกระจายตัวของ userspace คุณอาจต้องการที่จะลองจัดสรรที่แตกต่างกันเช่นjemalloc(มันมีดีความสามารถในการวิปัสสนาซึ่งจะให้คุณเข้าสู่ภายในจัดสรรกระจายภายใน)

คุณสามารถเปลี่ยนเป็น malloc แบบกำหนดเองได้โดยการคอมไพล์โปรแกรมของคุณใหม่หรือเพียงแค่รันโปรแกรมด้วยLD_PRELOAD: LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app (ระวังการโต้ตอบระหว่าง THP และตัวจัดสรรหน่วยความจำหน่วยความจำ )

แม้ว่าจะไม่เกี่ยวข้องกับการกระจายตัวของหน่วยความจำเล็กน้อย (แต่เชื่อมต่อกับการกระชับ / การโยกย้ายหน่วยความจำ) คุณอาจต้องการเรียกใช้บริการของคุณหลายอินสแตนซ์หนึ่งรายการสำหรับแต่ละโหนด NUMA และผูกเข้าด้วยnumactlกัน


1
เหตุใดคุณคิดว่าการปิดใช้งานการสลับสามารถช่วยได้ สำหรับฉันดูเหมือนว่ามีความเป็นไปได้มากขึ้นที่การปิดใช้งานการสลับจะทำให้เจ็บปวดมากกว่า
kasperd

1
เนื่องจากมีข้อมูลไม่เพียงพอในโพสต์ต้นฉบับอาจเป็นเพียงกระบวนการที่รั่วไหลและเริ่มแลกเปลี่ยน นอกจากนี้ฉันไม่เห็นเหตุผลที่ถูกต้องสำหรับการใช้ swap ในระบบการผลิตใด ๆ (mb เฉพาะสำหรับเวิร์กสเตชันที่ใช้ร่วมกันสำหรับนักเรียน)
SaveTheRbtz

2
การมีพื้นที่สว็อปเพียงพอจะปรับปรุงประสิทธิภาพ ปัญหาด้านประสิทธิภาพที่คุณจะได้รับหากคุณมีพื้นที่สว็อปไม่เพียงพอเป็นเหตุผลเพียงพอที่จะเปิดใช้งานสว็อป
kasperd

1
@SaveTheRbtz เหตุผลที่ดีในการใช้ swap บนระบบที่ใช้งานจริงคือมันให้ตัวเลือกเพิ่มเติมแก่ระบบว่าจะใช้เฉพาะเมื่อคิดว่ามีประโยชน์ นอกจากนี้ยังอนุญาตให้เพจที่แก้ไขซึ่งไม่ได้เข้าถึงภายในไม่กี่ชั่วโมง (และอาจไม่สามารถเข้าถึงได้) ถูกไล่ออกจากหน่วยความจำกายภาพที่มีค่า ประการสุดท้ายมันช่วยให้ระบบจัดการกรณีที่มีการสงวนหน่วยความจำมากกว่าที่ใช้
David Schwartz

2
"เฉพาะเมื่อมันคิดว่าพวกเขามีประโยชน์" - ซึ่งเป็นการเพิ่มฮิวริสติกเพิ่มเติมและทำให้ระบบคาดเดาได้น้อยลง อัลกอริธึมการแทนที่หน้า (ใช้ในการสลับและไม่ระบุชื่อmmap) ถูกนำไปใช้แตกต่างกันในเมล็ดที่แตกต่างกัน (เช่น Linux กับ FreeBSD) หรือแม้แต่ระบบปฏิบัติการรุ่นเดียวกัน (2.6.32 เทียบกับ 3.2 กับ 3.10) .. "มันอนุญาตให้แก้ไขหน้าเว็บ .. ] เพื่อถูกปลดจาก [... ] หน่วยความจำกายภาพ "- ที่จะซ่อนหน่วยความจำรั่ว "จัดการกับกรณีที่มีการจองหน่วยความจำมากกว่าที่ใช้" - ระบบช้าเป็นวิธีที่เลวร้ายยิ่งกว่าระบบดาวน์ดังนั้น "สติ" จึงเป็นที่น่าสงสัย
SaveTheRbtz

4

การใช้เพจขนาดใหญ่ไม่ควรทำให้การแตกหน่วยความจำเพิ่มเติมบน Linux; การสนับสนุน Linux สำหรับเพจขนาดใหญ่ใช้สำหรับหน่วยความจำที่ใช้ร่วมกันเท่านั้น (ผ่าน shmget หรือ mmap) และหน้าขนาดใหญ่ที่ใช้ต้องได้รับการร้องขอและจัดสรรล่วงหน้าล่วงหน้าโดยผู้ดูแลระบบ เมื่ออยู่ในหน่วยความจำพวกเขาจะถูกตรึงที่นั่นและจะไม่สลับออก ความท้าทายของการสลับหน้าขนาดใหญ่ในการเผชิญกับการกระจายตัวของหน่วยความจำคือเหตุผลที่พวกเขายังคงตรึงอยู่ในหน่วยความจำ (เมื่อจัดสรรเพจขนาดใหญ่ 2MB เคอร์เนลต้องค้นหา 512B หน้าฟรี 4KB ติดกันซึ่งอาจไม่มีอยู่จริง)

เอกสารคู่มือ Linux ในหน้าใหญ่: http://lwn.net/Articles/375098/

มีสถานการณ์หนึ่งที่การกระจายตัวของหน่วยความจำอาจทำให้การจัดสรรหน้าขนาดใหญ่ช้า (แต่ไม่ใช่ที่หน้าขนาดใหญ่ทำให้เกิดการกระจายตัวของหน่วยความจำ) และนั่นคือถ้าระบบของคุณได้รับการกำหนดค่าให้ขยายกลุ่มเพจขนาดใหญ่ หาก / proc / sys / vm / nr_overcommit_hugepages มากกว่า / proc / sys / vm / nr_hugepages สิ่งนี้อาจเกิดขึ้น


แน่นอน - และโดยทั่วไปควรช่วยประสิทธิภาพเนื่องจากจะป้องกันการพลาด TLB (ดูบทความที่เชื่อมโยงเพื่อดูคำอธิบาย)
Dan Pritts

0

นอกจากนี้/proc/buddyinfoที่มีประโยชน์มาก มันมีประโยชน์มากกว่าด้วยรูปแบบเอาต์พุตที่ดีเช่นเดียวกับสคริปต์ Python นี้:

https://gist.github.com/labeneator/9574294

สำหรับหน้าขนาดใหญ่คุณต้องการชิ้นส่วนฟรีในขนาด 2097152 (2MiB) ขึ้นไป สำหรับเพจขนาดใหญ่ที่โปร่งใสจะมีการกระชับโดยอัตโนมัติเมื่อมีการขอเคอร์เนลสำหรับบางหน้า แต่ถ้าคุณต้องการดูจำนวนที่คุณสามารถรับได้ในขณะที่รูทรัน:

echo 1 | sudo tee /proc/sys/vm/compact_memory

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

ฉันมีทางออกที่เหมาะกับฉัน ฉันใช้มันกับเซิร์ฟเวอร์และแล็ปท็อปของฉัน มันใช้งานได้ดีสำหรับเครื่องเสมือน

เพิ่มkernelcore=4Gตัวเลือกในบรรทัดคำสั่งเคอร์เนล Linux บนเซิร์ฟเวอร์ของฉันฉันใช้ 8G ระวังด้วยหมายเลขเพราะมันจะป้องกันเคอร์เนลของคุณจากการจัดสรรสิ่งใดนอกหน่วยความจำ เซิร์ฟเวอร์ที่ต้องการซ็อกเก็ตบัฟเฟอร์จำนวนมากหรือสตรีมดิสก์เขียนไปยังไดรฟ์นับร้อยจะไม่ถูก จำกัด เช่นนี้ การจัดสรรหน่วยความจำใด ๆ ที่จะต้อง "ตรึง" สำหรับแผ่นหรือ DMA อยู่ในหมวดหมู่นี้

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

และฉันไม่แน่ใจว่าสิ่งนี้โต้ตอบกับศูนย์ direct copy ของ IO ได้อย่างไร หน่วยความจำใน "เขตที่เคลื่อนย้ายได้" ไม่ควรถูกตรึงไว้ แต่การร้องขอโดยตรงจาก IO จะทำเช่นนั้นสำหรับ DMA มันอาจจะคัดลอก มันอาจจะปักหมุดไว้ในโซนที่เคลื่อนย้ายได้อยู่ดี ไม่ว่าในกรณีใดมันอาจไม่ใช่สิ่งที่คุณต้องการ

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