ฉันจะหาสาเหตุของการรั่วไหลของหน่วยความจำที่ชัดเจนใน Apache / PHP บนเว็บแอพได้อย่างไร


18

ประมาณสัปดาห์ละครั้ง แต่บางครั้งแม้แต่สองครั้งต่อวันหลังจากทำงานได้ดีสำหรับวันอินสแตนซ์ EC2 ของฉันไม่ตอบสนอง กราฟหน่วยความจำของ Munin บอกเล่าเรื่องราวที่ค่อนข้างตรงไปตรงมา: หน่วยความจำที่จัดสรรให้กับ "แอพ" เริ่มเพิ่มขึ้นและจะไม่หยุดจนกว่าจะมีการใช้งาน swap อย่างเต็มประสิทธิภาพ กราฟที่กำหนดเองอื่น ๆ แสดงว่ากระบวนการที่กำลังเติบโตอย่างต่อเนื่องคือ apache2

ฉันเรียกใช้การตั้งค่า Apache prefork มาตรฐานพร้อม mod_php และสคริปต์ PHP สองสามตัว ดังที่คุณเห็นในกราฟด้านล่างมีบางอย่างเกิดขึ้นที่เรียกใช้กระบวนการ apache2 เพื่อเริ่มใช้หน่วยความจำมากขึ้นเรื่อย ๆ เข็มสีเขียวอันแรกที่ฉันจับได้ทันเวลาและรีสตาร์ท Apache ก่อนที่สิ่งต่าง ๆ จะหมดไป เข็มที่สองได้รับอีกนิดและอินสแตนซ์จะต้องรีบูตทันที

กราฟหน่วยความจำ Munin

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


UPDATE: ฉันสามารถติดตามการรั่วไหลหลังจากที่ strace เข้าร่วมตามที่ Matt แนะนำด้านล่าง

หลังจากค้นหากระบวนการ apache2 ที่ค่อยๆเพิ่มขึ้นอย่างต่อเนื่องในหน่วยความจำฉันเพิ่ม error_log () อีกครั้งในการเรียกใช้สคริปต์ PHP ของฉันซึ่งพิมพ์จำนวน RSS ทั้งหมดที่ใช้ในจุดต่างๆในการดำเนินการ (โดยใช้เอาต์พุตของ ps) อย่างไรก็ตามนั่นกลับกลายเป็นความเข้าใจผิด - ในขณะที่ปรากฏว่า RSS เพิ่มขึ้นหลังจากสคริปต์ของฉันดำเนินการเสร็จสิ้นการตรวจแก้จุดบกพร่องในภายหลังพบว่าไม่ใช่กรณีดังกล่าว ระวัง!

โชคดีที่การโทร error_log () เหล่านั้นกลายเป็นประโยชน์ในที่สุด เมื่อฉันเพิ่ม strace ( strace -p <pid> -tt -o trace.log -s 256) ฉันเห็นว่าสำหรับแต่ละคำขอกระบวนการจัดสรรหน่วยความจำประมาณ 400k (มองหาการเรียกระบบ 'brk' และลบพารามิเตอร์ของการโทรครั้งแรกจากการโทรครั้งสุดท้าย - ไม่กี่คนที่มาในครั้งเดียว หลังจากนั้น) จากนั้นฉันค้นหาการเรียกระบบ 'เขียน' ครั้งล่าสุดที่มีข้อความ error_log () ของฉันซึ่งบอกฉันว่าจุดใดในสคริปต์ที่มีการจัดสรรหน่วยความจำ ด้วยการโทร error_log () ที่วางไว้อย่างมีกลยุทธ์เพื่อระบุตำแหน่งที่แม่นยำยิ่งขึ้นในที่สุดฉันก็พบผู้กระทำผิด

หน่วยความจำรั่วเมื่อเราเรียก curl_exec () จากสคริปต์ PHP ของเรา รหัส curl บางตัวที่เกี่ยวข้องกับการจัดการการเชื่อมต่อ SSL กำลังทำสิ่งผิดปกติ - การรั่วไหลหายไปเมื่อฉันเปลี่ยนเป็น HTTP รายการเปลี่ยนแปลงของ Curl อ้างอิงการรั่วไหลของหน่วยความจำ SSL สองสามรายการที่ได้รับการแก้ไขใน 7.19.5 (เราอยู่ที่ 7.18.2) ดังนั้นฉันจะลองต่อไป

ในขณะเดียวกันฉันทำงานกับ MaxRequestsPerChild ที่ต่ำมากซึ่งทำให้ Apache อยู่ในขอบเขตที่เหมาะสม ขอบคุณทุกคน!


จำนวนกระบวนการ apache child แตกต่างกันอย่างไรในช่วงเวลาเดียวกัน?
SimonJ

@SimonJ Simon คำถามที่ยอดเยี่ยมจำนวนยังคงเหมือนเดิมอีกทั้งบวกลบด้วยกระบวนการบางอย่าง มันวนเวียนอยู่ประมาณ 60 เมื่อเซิร์ฟเวอร์มีปัญหาเช่นเดียวกับเมื่อพวกเขากำลังพักผ่อน ฉันจะตั้งค่ากราฟ Munin ให้แน่ใจ 100%
ondrej

ไม่ใช่วิธีแก้ปัญหา แต่ถ้ามีแอปพลิเคชั่นตัวหนึ่งที่รู้ว่ากิน RAM อย่างบ้าคลั่งมันจะเป็นการดีกว่าถ้าคุณปิดการสับเปลี่ยน: เมื่อเคอร์เนลตรวจพบการขาด RAM มันจะฆ่าหน่วยความจำที่ใหญ่ที่สุด (apache) ด้วยการเปิดใช้งานการสลับเคอร์เนลจะฆ่ากระบวนการบางอย่างในภายหลังเนื่องจากการสลับช้ากว่าแรมมาก ไม่มีการแลกเปลี่ยน - การกู้คืนที่เร็วกว่าหยุดทำงานน้อยลง (ฉันได้พยายามเพียงการปิดใช้งานแลกเปลี่ยนในกรณีที่คล้ายกันในเครื่องที่มี 8GiB RAM ดังนั้น YMMW.)
โครโนส

คำตอบ:


5

การติดตามสิ่งที่ทำให้เกิดปัญหาอาจเป็นความเจ็บปวดในตูด สิ่งแรกที่ฉันจะทำถ้าฉันมีปัญหาเช่นนั้นลดลงMaxRequestsPerChildเหลือน้อยมาก (~ 100-200) และดูว่ามันสร้างความแตกต่างได้ไหม ถ้าเป็นเช่นนั้นคุณอาจมีรหัสที่หน่วยความจำรั่วไหลวนหนึ่งและคุณต้องการรันการตรวจสอบรหัส

อีกสิ่งที่ควรพิจารณาคือ Apache ของ fullstatus ลองดูว่าคุณสามารถค้นหาว่าคำขอใดที่ทำให้หน่วยความจำรั่ว รับ PID จากกระบวนการที่สงสัยของคุณและเรียกใช้ strace จากนั้น


ขอบคุณแมตต์ 'ps aux | grep apache2 'บอกฉันว่าจากกระบวนการ 60 หรือมากกว่านั้นทำงานอยู่ประมาณหนึ่งโหลกำลังใช้หน่วยความจำมากกว่าที่ควรจะเป็น (> 100MB ใน RSS) ฉันได้ดูผลลัพธ์ของ / proc / <pid> / smaps แล้วและพบว่าแต่ละรายการมีการจับคู่แบบไม่ระบุชื่อเดียวที่ใช้พื้นที่ถึง 95% + ตอนนี้ฉันกำลังพยายามคิดออกว่าจะจัดสรรหน่วยความจำขนาดใหญ่ก้อนนี้เป็นอย่างไรและเมื่อไหร่ ฉันจะดู strace - ขอบคุณสำหรับเคล็ดลับ
ondrej

2

วันศุกร์เวลา 23.00 น. หรือไม่ สิ่งนี้สอดคล้องกับเวลาการสำรองข้อมูลหรือไม่? ระบบของคุณมี I / O ให้บริการสำหรับกระบวนการและการสำรองข้อมูลในเวลานั้นหรือไม่? คุณมีแนวโน้มซอฟต์แวร์แนวโน้ม # procs หรือแม้กระทั่งคะแนน apache วิธีการเกี่ยวกับดิสก์ I / O?

แรกสิ่งที่ฉันจะทำจะคำนวณว่าข่าวมากแต่ละ proc ใช้เวลาแล้วกำหนดวงเงินที่เหมาะสมสำหรับ MaxRequests ใน Apache เพื่อให้ $ procmem * $ procs ไม่เกิน RAM ที่มี ฉันสงสัยว่าอินสแตนซ์ของคุณต้องถูกรีบูตเนื่องจาก OOM เริ่มต้นล่าแม่มดที่มีแนวโน้ม (มัก) ไม่ได้ผลมากนัก คุณต้องแน่ใจว่ากล่องของคุณสามารถรับมือกับช่วงเวลาที่หนักหน่วงเหล่านี้ได้โดยอยู่ในขอบเขตและไม่ต้องเปลี่ยนและไม่ใช่ OOM แน่นอน สิ่งนี้ยากกว่าถ้าคุณใช้ cronjobs และยากมากถ้าพูดว่า cronjobs ทำงานโดยไม่ต้องแน่ใจว่ามันปลอดภัยที่จะทำงาน (เช่นสคริปต์ทุก 5 นาทีไม่สามารถตรวจสอบได้ว่าสคริปต์ 5 นาทีสุดท้ายยังทำงานอยู่หรือไม่)

ตอนนี้คุณได้มั่นใจแล้วว่าแม้ว่าสิ่งต่าง ๆ จะผิดปกติคุณไม่จำเป็นต้องรีบูตกล่องของคุณ แต่สิ่งต่างๆจะเริ่มดีขึ้นมากสำหรับคุณ คุณจะสามารถเข้าสู่ระบบในช่วงเวลาที่หนักหน่วงเหล่านี้และรับความคิดที่ดีว่าเกิดอะไรขึ้นกับการใช้ top, dstat, free -m, iostat ฯลฯ

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


0

คำถามแรกที่ถามคือแอปพลิเคชันที่ทำงานผ่าน Apache คืออะไร

คุณเป็นคนเขียนหรือแอพของบุคคลที่สามหรือไม่

มีการอ้างอิงส่วนประกอบ / แพ็คเกจอื่นใด

คุณทันสมัยกับแพ็คเกจของคุณหรือไม่?

มีอะไรพิเศษในhttpd.confไฟล์ของคุณที่เกี่ยวข้องกับประสิทธิภาพหรือไม่


0

ถ้าปัญหาของคุณเกิดจากโปรแกรม PHP และถ้าคุณเขียนซอฟแวร์ตัวเองแล้วฉันขอแนะนำให้คุณใช้ Profiler เหมือนเช่นPHP ด่วน Profiler หากคุณมีธุรกรรมฐานข้อมูลจำนวนมากเกิดขึ้นซอฟต์แวร์เช่นKontrollbaseจะช่วยคุณค้นหาปัญหาที่นั่น


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