Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ขอแนะนำสคริปต์คลัสเตอร์ Sidekiq ของเรา

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

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

คำสั่งง่ายๆ คำสั่งเดียวสำหรับการเรียกใช้กระบวนการ Sidekiq หลายรายการ

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

แน่นอนว่ามีโค้ดที่ยืมมาเล็กน้อยในสคริปต์นั้น :) รหัสใน process_count วิธีอาจมาจาก Stack Overflow (ฉันใช้มันมาหลายปีแล้วในการกำหนดค่ายูนิคอร์นของเรา) และ fork_child วิธีการนั้นเป็น sidekiq bin จากอัญมณี sidekiq

สคริปต์นี้สร้างโปรเซสลูกจำนวนหนึ่งตามจำนวนคอร์ของ CPU ที่มีอยู่ โดยแต่ละโปรเซสลูกจะเหมือนกับว่าคุณได้เรียกใช้ sidekiq คำสั่งโดยตรง ด้วยเหตุนี้ ตัวเลือกบรรทัดคำสั่งใดๆ ที่คุณส่งไปยังสคริปต์นี้จะถูกส่งต่อไปยัง (และแยกวิเคราะห์โดย) รหัส Sidekiq CLI กล่าวอีกนัยหนึ่ง คุณสามารถส่งตัวเลือกใดๆ ไปยังสคริปต์นี้ซึ่งคุณสามารถส่งผ่านไปยัง sidekiq เมื่อเรียกใช้โดยตรง แม้ว่าบางตัวเลือก (เช่น ตัวเลือกไฟล์ pid) ไม่สมเหตุสมผลเลยที่จะใช้ เธรดยังถูกสร้างขึ้นเพื่อตรวจสอบการใช้หน่วยความจำของกระบวนการย่อยแต่ละกระบวนการเป็นระยะๆ หากกระบวนการลูกใด ๆ เกินเกณฑ์การใช้งาน กระบวนการนั้นจะถูกฆ่าและกระบวนการใหม่จะถูกสร้างขึ้นมาแทนที่

การทำงานกับคลัสเตอร์

แม้ว่าจำนวนกระบวนการจะเริ่มต้นที่จำนวนคอร์ (สมมติว่าคุณกำลังทุ่มเทอินสแตนซ์เพื่อเรียกใช้กระบวนการ Sidekiq) คุณสามารถแทนที่ได้โดยการตั้งค่าตัวแปรสภาพแวดล้อม SK_PROCESS_COUNT ก่อนเรียกใช้สคริปต์ ในทำนองเดียวกัน เกณฑ์หน่วยความจำถูกกำหนดเป็นเปอร์เซ็นต์ของ RAM ทั้งหมดของอินสแตนซ์ (เหลือ RAM บางส่วนไว้โดยการเพิ่มค่าหนึ่งลงในค่า process_count ในบรรทัดที่ 58) แต่คุณสามารถตั้งค่าเปอร์เซ็นต์ใดก็ได้ตามต้องการด้วยตัวแปรสภาพแวดล้อม SK_MEMORY_PCT_LIMIT เราใช้ตัวแปรทั้งสองนี้เพื่อจำกัดจำนวนกระบวนการ Sidekiq และการใช้หน่วยความจำบนอินสแตนซ์ที่เรียกใช้แอป Rails ที่ขับเคลื่อน UI ของเรา

เป็นโบนัสเพิ่มเติม สคริปต์นี้จะจับสัญญาณที่ใช้โดยทั่วไปเพื่อจัดการกระบวนการ Sidekiq และส่งสัญญาณเหล่านั้นไปยังกระบวนการย่อย ซึ่งช่วยให้เราใช้ pkill -f -USR1 skcluster เพื่อให้กระบวนการลูกหยุดรับงานใหม่ (นี่เป็นงานแรกในสคริปต์การปรับใช้ของเรา) และเราสามารถใช้ pkill -f skcluster เพื่อยุติทุกสิ่ง

การกำหนดค่า systemd

คำจำกัดความของบริการ systemd ตรงไปตรงมา:

เนื่องจากเราใช้ pgbouncer กับทุกอินสแตนซ์เพื่อเชื่อมต่อพร็อกซีกับ postgres เราจึงมั่นใจได้ว่าบริการ pgbouncer กำลังทำงานก่อนที่กระบวนการ sidekiq จะถูกบูต หากเราใช้ redis ในอินสแตนซ์เดียวกัน เราจะเพิ่ม redis-server.service ลงในบรรทัด Requires และ After EnvironmentFile ใช้ - นำหน้าชื่อไฟล์เพื่อบอก systemd ว่าไม่เป็นไรหากไม่มีไฟล์ ซึ่งช่วยให้เราละเว้นไฟล์นั้นเมื่อเราต้องการใช้จำนวนกระบวนการเริ่มต้นและขีดจำกัดหน่วยความจำ เราใช้ --require ตัวเลือกเพื่อให้ Sidekiq รู้ว่าจะไปโหลดการกำหนดค่าและตัวเริ่มต้นของแอปพลิเคชัน Rails ของเราได้ที่ไหน เนื่องจากสคริปต์ skcluster จับ SIGTERM เราจึงสามารถใช้ systemctl restart skcluster.service เพื่อรีสตาร์ทผู้ปฏิบัติงานทั้งหมด (นี่เป็นงานล่าช้าในสคริปต์การปรับใช้ของเรา)

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