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

เพิ่มประสิทธิภาพ Sidekiq Clusters: สคริปต์ใหม่สำหรับ Deployment ที่ราบรื่น

ที่ Honeybadger เราพึ่งพา Sidekiq มากใน processing pipeline เกือบทุกอย่างผ่าน queue จุดหนึ่ง ผมจึงอยากแน่ใจว่าเรารัน Sidekiq ได้ดี การย้ายไป EC2 ล่าสุด เปลี่ยนจากชุดเซิร์ฟเวอร์ long-lived ที่เสถียร เป็นชุด instances ที่เปลี่ยนแปลงตลอดเวลา ทำให้การเริ่ม Sidekiq ตอน boot สำคัญกว่าเดิมมาก

ก่อนหน้านี้พึ่งพา god spin up worker processes เพราะอยาก monitor และ terminate ตัวที่ใช้ memory มากเกินไป god config ปรับแต่งมือสำหรับเซิร์ฟเวอร์ที่ deploy workers แต่พบว่า boot god config เก่าบน instances ใหม่ด้วย systemd บางครั้งได้ workers มากกว่าที่ config ระบุ นำไปสู่ memory pressure ที่แย่ หลังลองแก้สักพัก และตระหนักว่าไม่ได้ใช้ฟังก์ชันมาก ผมตัดสินใจหยุดใช้ god จัดการ processes

คำสั่งเดียวสำหรับรัน multiple Sidekiq processes

สิ่งที่ผมอยากได้จริง: สคริปต์รันเป็น systemd service spawn Sidekiq process ต่อ core และ restart processes ที่ใช้ memory มากเกินไป สคริปต์ต้องทำงานกับ EC2 instances ขนาดต่างๆ ได้ เนื่องจากจำนวน cores และ RAM อาจต่างกันขณะลอง instance sizes ต่างๆ เพื่อหาที่เหมาะกับ workload เนื่องจากหาสคริปต์ที่ทำได้พอดีไม่เจอ ผมเขียนเอง:

ในสคริปต์มีโค้ดยืมมาบ้าง :) โค้ดในเมธอด process_count น่าจะมาจาก Stack Overflow (ใช้มาปีก่อนใน unicorn configs) และเมธอด fork_child 基本上คือ sidekiq bin จาก sidekiq gem

สคริปต์ spawn child processes จำนวนตาม CPU cores แต่ละ child process เหมือนรันคำสั่ง sidekiq โดยตรง ดังนั้น command-line options ที่ส่งให้สคริปต์จะถูกส่งต่อไป (และ parse โดย) Sidekiq CLI code กล่าวคือ ส่ง options ใดๆ ที่ส่งให้ sidekiq ตอนรันโดยตรงได้ แม้บาง options (เช่น pid file option) ไม่ควรใช้ Thread ยัง spawn ไป check memory usage ของ child processes เป็นระยะ หาก child process ข้าม threshold จะถูก kill และ spawn process ใหม่แทน

ทำงานกับ cluster

จำนวน processes default ตามจำนวน cores (สมมติ dedicate instance ให้ Sidekiq) แต่ override ได้โดยตั้งค่า environment variable SK_PROCESS_COUNT ก่อนรันสคริปต์ Memory threshold ตั้งเป็นเปอร์เซ็นต์ของ total RAM ของ instance (เหลือ RAM สำรองโดยเพิ่ม 1 ใน process_count บรรทัด 58) แต่ตั้งเปอร์เซ็นต์ไหนก็ได้ด้วย SK_MEMORY_PCT_LIMIT เราใช้ตัวแปรทั้งสองจำกัดจำนวน Sidekiq processes และ memory usage บน instances ที่รัน Rails app ของ UI

เพิ่มพิเศษ: สคริปต์จับ signals ที่ใช้จัดการ Sidekiq processes ปกติ และส่งต่อ signals ไปยัง child processes ทำให้เราใช้ pkill -f -USR1 skcluster ให้ child processes หยุดรับงานใหม่ (early task ใน deployment script) และ pkill -f skcluster เพื่อ terminate ทั้งหมด

ตั้งค่า systemd

systemd service definition ตรงไปตรงมา:

เราใช้ pgbouncer บนทุก instance proxy connections ไป postgres จึง ensure pgbouncer service รันก่อน sidekiq processes boot หากรัน redis บน instances เดียวกัน จะเพิ่ม redis-server.service ใน Requires และ After lines EnvironmentFile ใช้ - prefix บอก systemd ว่า ok ถ้าไฟล์ไม่มี ทำให้เราละไฟล์นั้นได้ตอนอยากใช้ default process count และ memory limit เราใช้ option --require บอก Sidekiq ว่าไปโหลด config และ initializers ของ Rails app ที่ไหน เนื่องจาก skcluster script จับ SIGTERM เราจึงใช้ systemctl restart skcluster.service restart workers ทั้งหมด (late task ใน deployment script)

เราใช้สคริปต์นี้มาพักแล้ว ทำงานได้เยี่ยม ไม่มีปัญหา processes spawn มากเกินไปตอน boot ไม่มี memory usage warnings จาก monitoring และ launch EC2 instance type ใดก็ได้ Hassle-free ops คือ ops ที่ผมชอบมาก :)