ใน Ubuntu วิธีที่ปลอดภัยที่สุดในการจำกัดปริมาณงานด้วย cgroups คือการปล่อยให้ systemd สร้างและจัดการกลุ่มควบคุมเอง ใช้systemd-runสำหรับคำสั่งที่คุณกำลังเริ่มต้น หรือกำหนดค่าบริการ systemd เมื่อข้อจำกัดนั้นต้องคงอยู่หลังจากการรีสตาร์ท ตั้งCPUQuota=ค่าขีดจำกัดเวลา CPU ที่แน่นอน และเลือกระหว่างMemoryHigh=ค่าแรงดันและMemoryMax=ค่าขีดจำกัดหน่วยความจำที่แน่นอน ข้อจำกัดเหล่านี้ใช้กับหน่วยและกระบวนการลูกของมันด้วยกัน
cgroup (control group) คือกลไกในเคอร์เนลของลินุกซ์ที่จัดระเบียบกระบวนการต่างๆ เพื่อให้ระบบสามารถตรวจสอบและควบคุมการใช้ทรัพยากรได้ systemd ของ Ubuntu ได้จัดวางบริการต่างๆ ไว้ใน cgroup อยู่แล้ว ดังนั้นผู้ใช้ส่วนใหญ่จึงไม่จำเป็นต้องสร้างไดเร็กทอรี/sys/fs/cgroupด้วยตนเอง ตัวอย่างด้านล่างใช้ส่วนติดต่อควบคุมทรัพยากรของ systemd และควรตรวจสอบกับเวอร์ชัน systemd ที่ติดตั้งใน Ubuntu เวอร์ชันของคุณ
ภาพจำลองเทอร์มินัลสำหรับตรวจสอบ systemd และการเมานต์ cgroup v2 เวอร์ชันและผลลัพธ์ที่แสดงเป็นเพียงตัวอย่าง ไม่ใช่ผลการทดสอบจริง
เลือกตัวควบคุมที่ตรงกับปัญหา
วิธี สิ่งที่มันควบคุม เหมาะสมที่สุด ข้อแลกเปลี่ยนหลัก
systemd-runขอบเขตชั่วคราวโควต้า CPU และขีดจำกัดหน่วยความจำสำหรับคำสั่งที่เรียกใช้ใหม่และคำสั่งที่สืบทอดมาจากคำสั่งนั้น การสร้าง การเขียนสคริปต์ การนำเข้า หรืองานแบบแบตช์ครั้งเดียว ขอบเขตการใช้งานเป็นแบบชั่วคราวและจะสิ้นสุดลงเมื่อปริมาณงานเสร็จสิ้น โดยจะไม่ผูกติดกับกระบวนการใดๆ ที่กำลังทำงานอยู่แล้ว
การตั้งค่าบริการ systemd ทรัพยากรสำหรับ cgroup ของบริการ รวมถึงกระบวนการย่อย โปรแกรมหรือแอปพลิเคชันที่ควรคงค่าขีดจำกัดเดิมไว้หลังจากรีบูตเครื่อง จำเป็นต้องกำหนดค่าบริการและโดยปกติจะต้องรีสตาร์ทเพื่อใช้งานการตั้งค่าใหม่
ไฟล์ cgroup v2 โดยตรง ตัวควบคุมระดับเคอร์เนล เช่นcpu.maxและmemory.max รันไทม์คอนเทนเนอร์, ตัวจัดการ cgroup ที่ได้รับมอบหมาย หรือการบริหารจัดการเฉพาะทาง ต้องดำเนินการด้วยตนเองมากขึ้น เนื่องจาก systemd เป็นเจ้าของโครงสร้างลำดับชั้นส่วนใหญ่ของ Ubuntu และการเขียนลงในโครงสร้างที่จัดการโดย systemd อาจขัดแย้งกับ systemd หรือล้มเหลวเนื่องจากสิทธิ์และการมอบหมาย
niceหรือCPUWeight=ลำดับความสำคัญของ CPU เมื่อกลุ่มต่างๆ แข่งขันกัน ลดลำดับความสำคัญของงานเบื้องหลังลง ในขณะที่ยังคงอนุญาตให้ใช้ CPU ที่ว่างอยู่ นี่ไม่ใช่ข้อจำกัดด้าน CPU ที่เข้มงวด และไม่ได้จำกัดหน่วยความจำ
สำหรับเครื่อง Ubuntu ที่ใช้งานแบบโต้ตอบส่วนใหญ่ ขอบเขตชั่วคราว (transient scope) เป็นตัวเลือกที่รวดเร็วและสามารถย้อนกลับได้ สำหรับบริการที่ใช้งานจริง ให้ใช้หน่วยบริการ (service unit) เพื่อให้มีการบันทึกนโยบายและเรียกคืนได้เมื่อบูตเครื่อง ใช้ไฟล์ cgroup โดยตรงเฉพาะเมื่อคุณกำลังจัดการลำดับชั้นที่ได้รับมอบหมายอย่างตั้งใจ หรือกำลังสร้างเวิร์กโฟลว์คอนเทนเนอร์/รันไทม์
ตรวจสอบระบบ Ubuntu ก่อนตั้งค่าข้อจำกัด
ขั้นแรก ตรวจสอบว่า systemd พร้อมใช้งานหรือไม่ และระบบไฟล์ cgroup เป็น unified v2 หรือไม่:
systemctl --version
stat -fc %T /sys/fs/cgroup
ผลลัพธ์cgroup2fsจากคำสั่งที่สองบ่งชี้ว่าระบบไฟล์เป็นแบบ cgroup v2 ที่รวมกัน ระบบปฏิบัติการ Ubuntu และระบบที่ปรับแต่งเองอาจแตกต่างกัน ดังนั้นอย่าคิดว่าทุกเครื่องจะมีลำดับชั้นหรือคุณสมบัติของ systemd เหมือนกัน คุณสามารถตรวจสอบเวอร์ชัน systemd ปัจจุบันได้ด้วยคำสั่งแรก หากการเมานต์ cgroup ไม่ใช่ v2 คุณสมบัติของทรัพยากรหรือพฤติกรรมของคอนโทรลเลอร์บางอย่างอาจแตกต่างกัน โปรดศึกษาคู่มือ Ubuntu สำหรับเวอร์ชันที่ติดตั้งก่อนคัดลอกการกำหนดค่า
เลือกค่าต่างๆ หลังจากวัดปริมาณงานแล้ว เว้นพื้นที่ไว้สำหรับส่วนที่เหลือของระบบ และอย่าลืมว่าข้อจำกัดที่ตั้งไว้สำหรับบริการของผู้ใช้จะถูกจำกัดโดยข้อจำกัดใดๆ ที่ตั้งไว้สำหรับสไลซ์แม่ด้วย cgroup ย่อยไม่สามารถรับทรัพยากรได้มากกว่าที่ cgroup บรรพบุรุษอนุญาต
จำกัดคำสั่งที่คุณกำลังจะเริ่มต้น
สำหรับการเรียกใช้คำสั่งในเซสชันผู้ใช้ของคุณเอง ให้เรียกใช้คำสั่งนั้นในขอบเขตชั่วคราวด้วยsystemd-run --user --scopeตัวอย่างเช่น:
ภาพจำลองหน้าจอเทอร์มินัลแสดงคำสั่ง systemd-run แบบครั้งเดียว พร้อมโควต้า CPU ขีดจำกัดแรงดันหน่วยความจำ และขีดจำกัดหน่วยความจำสูงสุด
systemd-run --user --scope --unit=worker-capped \
-p CPUQuota=50% \
-p MemoryHigh=700M \
-p MemoryMax=900M \
-- python3 /opt/worker.py
แทนที่คำสั่ง Python ด้วยโปรแกรมที่คุณต้องการเรียกใช้งานจริง ตัวอย่างนี้กำหนดแบนด์วิดท์ CPU สูงสุดให้กับ cgroup เทียบเท่ากับครึ่งหนึ่งของ CPU หนึ่งตัว เริ่มจัดการแรงดันหน่วยความจำเมื่อถึง 700 MiB และตั้งค่าหน่วยความจำสูงสุดแบบฮาร์ดแวร์ไว้ที่ 900 MiB ค่าหน่วยความจำใช้หน่วยฐาน 1024 ของ systemd โควต้า100%หมายถึงเวลาใช้งานได้สูงสุดหนึ่ง CPU 200%สามารถใช้งานได้สูงสุดสอง CPU เมื่อมีให้ใช้งาน ไม่ได้หมายถึงเปอร์เซ็นต์ของคอร์ทั้งหมดในคอมพิวเตอร์
คำสั่งนี้จะทำงานในโหมดพื้นหน้าเนื่องจากเป็นขอบเขตการทำงาน เมื่อคำสั่งสิ้นสุดลง หน่วยชั่วคราวจะหายไป ลบ--userเฉพาะในกรณีที่คุณต้องการใช้ตัวจัดการระบบและมีสิทธิ์ที่จำเป็น สำหรับหน่วยชั่วคราวที่ครอบคลุมทั้งระบบ ให้เรียกใช้คำสั่งsudoโดยใช้ตัวเลือกคำสั่งที่เหมาะสม การตั้งค่าทรัพยากรอาจถูกปฏิเสธหากตัวจัดการหรือตัวควบคุม cgroup ไม่รองรับ
กำหนดข้อจำกัดให้กับบริการ systemd ที่ทำงานอย่างต่อเนื่อง
สำหรับบริการเช่นworker.serviceให้สร้าง drop-in แทนการแก้ไขไฟล์หน่วยของผู้จำหน่าย เรียกใช้คำสั่งsudo systemctl edit worker.serviceและเพิ่ม:
ตัวอย่างการกำหนดค่าบริการ systemd พร้อมการควบคุม CPU และหน่วยความจำแบบถาวร โปรดใช้ชื่อบริการจริงและค่าที่เหมาะสมกับปริมาณงานของคุณ
[Service]
CPUQuota=50%
MemoryHigh=700M
MemoryMax=900M
บันทึกไฟล์ drop-in จากนั้นโหลดคำจำกัดความหน่วยของ systemd ใหม่ และรีสตาร์ทบริการเพื่อให้กระบวนการเริ่มต้นภายใต้นโยบายที่แก้ไขแล้ว:
sudo systemctl daemon-reload
sudo systemctl restart worker.service
ควรกำหนดขีดจำกัดหน่วยความจำอย่างระมัดระวัง หากบริการไม่สามารถเรียกคืนหน่วยความจำได้เพียงพอต่ำกว่าMemoryMaxขีดจำกัดที่กำหนดไว้ เคอร์เนลอาจเรียกใช้กลไกการจัดการหน่วยความจำไม่เพียงพอภายใน cgroup นั้น ซึ่งอาจยุติกระบวนการหนึ่งหรือหลายกระบวนการในกลุ่มบริการและขัดจังหวะการทำงาน รูปแบบที่ปลอดภัยกว่ามักจะเป็นการตั้งค่าMemoryHighในระดับที่การเรียกคืนและการจำกัดการใช้งานเป็นที่ยอมรับได้ จากนั้นจึงตั้งค่าMemoryMaxให้สูงขึ้นเป็นขีดจำกัดสุดท้าย ทดสอบด้วยภาระงานสูงสุดที่สมจริงก่อนที่จะใช้งานขีดจำกัดที่เข้มงวด
ตรวจสอบอุปกรณ์และสังเกตพฤติกรรมของมัน
สำหรับออสซิลโลสโคปแบบชั่วคราว ให้ตรวจสอบสถานะโดยใช้ชื่อหน่วยที่คุณระบุไว้:
ภาพแสดงสถานะและการตรวจสอบ cgroup ตัวเลข CPU และหน่วยความจำที่แสดงในที่นี้ไม่ใช่ค่าที่วัดได้จากการใช้งานจริง
systemctl --user status worker-capped.scope
systemd-cgtop
สำหรับบริการระบบ ให้ละเว้น--userในคำสั่งสถานะ มุมมองสถานะจะยืนยันว่าหน่วยนั้นมีอยู่และทำงานอยู่systemd-cgtopแสดงการใช้งานทรัพยากรแบบเรียลไทม์ตามกลุ่มควบคุม หากต้องการตรวจสอบคุณสมบัติที่กำหนดค่าไว้ ให้สอบถามหน่วยโดยตรง เช่น:
systemctl --user show worker-capped.scope \
-p CPUQuotaPerSecUSec -p MemoryHigh -p MemoryMax
ปริมาณหน่วยความจำที่รายงานสำหรับ cgroup ไม่จำเป็นต้องเท่ากับปริมาณหน่วยความจำที่ใช้จริงของกระบวนการใดกระบวนการหนึ่งเสมอไป เพราะมันรวมถึงหน่วยความจำที่ถูกเรียกเก็บจากกลุ่ม และอาจรวมถึงกระบวนการย่อยของเวิร์กโหลดด้วย ควรพิจารณาการตรวจสอบนี้เป็นหลักฐานแสดงถึงพฤติกรรมของเวิร์กโหลดนี้เมื่อเวลาผ่านไป ไม่ใช่เป็นเพียงตัวเลขเดียวที่จะนำไปใช้ในการปรับให้เหมาะสมโดยไม่คิดไตร่ตรอง
แล้วถ้ากระบวนการนั้นกำลังทำงานอยู่ล่ะ?
systemd-runคำสั่งนี้จะเริ่มต้นคำสั่งใหม่ภายในหน่วยใหม่ โดยจะไม่นำ PID ที่มีอยู่แล้วมาใส่ในขอบเขตนั้น หากกระบวนการนั้นเป็นส่วนหนึ่งของบริการ systemd ให้ใช้การตั้งค่ากับบริการนั้นด้วย drop-in หรือหากต้องการเปลี่ยนแปลงชั่วคราว ให้ใช้ รูปแบบ sudo systemctl set-property --runtime worker.service CPUQuota=50% MemoryHigh=700M MemoryMax=900Mนี้--runtimeเป็นแบบชั่วคราวและจะไม่แทนที่การกำหนดค่าบริการแบบถาวร
หากกระบวนการนั้นเป็นโปรแกรมปกติในเซสชันเดสก์ท็อปของคุณ วิธีที่ปลอดภัยและง่ายที่สุดคือการหยุดโปรแกรมแล้วเริ่มใหม่ภายใต้systemd-runการใช้คุณสมบัติกับส่วนที่กว้างกว่า เช่น ส่วนของผู้ใช้ทั้งหมด อาจส่งผลกระทบต่อแอปพลิเคชันที่ไม่เกี่ยวข้องหลายตัว การย้ายกระบวนการโดยการเขียน PID ลงในไฟล์ cgroup จำเป็นต้องควบคุมลำดับชั้นการมอบหมายที่เกี่ยวข้องและต้องเคารพกฎการจัดวางกระบวนการ cgroup v2 อย่าเขียนลงในไดเร็กทอรีที่จัดการโดย systemd โดยอาศัยการคาดเดา
วิธีการเลือกนโยบาย CPU และหน่วยความจำ
ต้องการกำหนดขีดจำกัดการใช้งาน CPU ที่แน่นอนใช่ไหม เลือกค่านี้CPUQuota=ค่าที่ต่ำกว่าจะช่วยลดการใช้งาน CPU สูงสุด แต่จะทำให้การประมวลผลช้าลงและเพิ่มเวลาในการรอคิวต้องการลำดับความสำคัญต่ำกว่าใช่ไหม ลองพิจารณาใช้CPUWeight=แทนการกำหนดโควต้า การจัดสรรน้ำหนักจะแบ่งใช้ CPU ตามสัดส่วนการใช้งาน ไม่ได้สงวนเปอร์เซ็นต์คงที่หรือป้องกันการใช้งาน CPU ที่ว่างอยู่ต้องการจัดการแรงดันหน่วยความจำโดยไม่ให้หยุดทำงานทันทีใช่ไหม? ตั้งค่านี้MemoryHigh=เป็นเกณฑ์แรงดันหลัก แล้วสังเกตความหน่วงและพฤติกรรมการเรียกคืนหน่วยความจำต้องการขอบเขตการกักเก็บขั้นสุดท้ายหรือไม่? เพิ่มMemoryMax=พื้นที่ว่างให้เพียงพอสำหรับปริมาณสูงสุดปกติ เตรียมพร้อมรับมือกับพฤติกรรม OOM (Out of Ground) เมื่อไม่สามารถเคารพขอบเขตที่กำหนดได้กำลังใช้งานคอนเทนเนอร์อยู่แล้วใช่ไหม? ควรเลือกใช้แฟล็ก CPU และหน่วยความจำที่ตัวจัดการคอนเทนเนอร์รองรับ ซึ่งจะกำหนดค่า cgroups สำหรับคอนเทนเนอร์นั้นและเหมาะสมกับวงจรชีวิตของมัน
ไม่มีขีดจำกัดที่เหมาะสมที่สุดเพียงอย่างเดียวสำหรับทุกภาระงาน งานประมวลผลแบบแบตช์บนเดสก์ท็อปอาจยอมรับโควต้าต่ำและขีดจำกัดหน่วยความจำระดับปานกลางได้ ในขณะที่บริการที่ไวต่อความหน่วงอาจต้องการพื้นที่ CPU มากขึ้นและขีดจำกัดที่สูงขึ้นMemoryHighเพื่อหลีกเลี่ยงการหยุดชะงักที่เกิดจากการเรียกคืนทรัพยากร เริ่มต้นอย่างระมัดระวัง ตรวจสอบเครื่องในระหว่างช่วงเวลาที่มีการใช้งานสูงสุด และปรับการตั้งค่าทีละอย่าง
เอกสารอ้างอิง