ทำไม“ กระบวนการต้องไม่แยก” สำหรับบริการประเภทธรรมดาใน systemd?
ฉันต้องการเขียนsystemd
ไฟล์ยูนิตของตัวเองเพื่อจัดการคำสั่งที่รันเป็นเวลานาน1 (ตามลำดับชั่วโมง) ในขณะที่ดูบทความ ArchWiki เกี่ยวกับ systemdจะมีการกล่าวถึงการเลือกประเภทเริ่มต้นดังนี้
Type=simple
(ค่าเริ่มต้น): systemd ถือว่าบริการเริ่มต้นทันที กระบวนการนี้จะต้องไม่แยก อย่าใช้ประเภทนี้หากจำเป็นต้องสั่งซื้อบริการอื่นในบริการนี้เว้นแต่จะเปิดใช้งานซ็อกเก็ต
ทำไมกระบวนการต้องไม่ส้อมเลย? มันหมายถึงการฟอร์กในรูปแบบของกระบวนการอัญเชิญภูต (พาเรนต์ฟอร์กแล้วออก) หรือฟอร์กประเภทใด?
1ฉันไม่ต้องการ tmux / tmux send-keys
จอเพราะผมต้องการวิธีที่สง่างามมากขึ้นในการตรวจสอบสถานะและรีสตาร์ทบริการโดยไม่ต้อง
คำตอบ
บริการได้รับอนุญาตให้โทรเข้าfork
ระบบ Systemd จะไม่ป้องกันหรือแม้กระทั่งสังเกตว่าเป็นเช่นนั้น ประโยคนี้อ้างอิงโดยเฉพาะถึงการฝึกฝนการตีที่จุดเริ่มต้นของ daemon เพื่อแยก daemon ออกจากกระบวนการพาเรนต์ “ กระบวนการต้องไม่แยก [และออกจากพาเรนต์ในขณะที่เรียกใช้บริการในกระบวนการย่อย]”
หน้าคนอธิบายมากกว่านี้ verbosely และด้วยถ้อยคำที่ไม่นำไปสู่ความสับสนนี้โดยเฉพาะอย่างยิ่ง
โปรแกรมจำนวนมากที่ใช้เป็น daemons มีโหมด (มักเป็นโหมดเริ่มต้น) ซึ่งเมื่อเริ่มต้นโปรแกรมจะแยกตัวเองออกจากผู้ปกครอง daemon เริ่มต้นการเรียกใช้fork()
และพาเรนต์ออก กระบวนการลูกเรียกsetsid()
เพื่อให้รันในกลุ่มกระบวนการและเซสชันของตนเองและเรียกใช้บริการ จุดประสงค์คือหากเรียกใช้ daemon จากบรรทัดคำสั่งเชลล์ daemon จะไม่ได้รับสัญญาณใด ๆ จากเคอร์เนลหรือจากเชลล์แม้ว่าจะมีบางอย่างเกิดขึ้นกับเทอร์มินัลเช่นการปิดเทอร์มินัล (ในกรณีนี้เชลล์จะส่ง SIGHUP ไปยังกลุ่มกระบวนการทั้งหมดที่รู้จัก) นอกจากนี้ยังทำให้กระบวนการให้บริการถูกนำมาใช้โดย init ซึ่งจะเก็บเกี่ยวเมื่อมันออกโดยหลีกเลี่ยงซอมบี้หาก daemon เริ่มต้นด้วยสิ่งที่ไม่wait()
ต้องการ (สิ่งนี้จะไม่เกิดขึ้นหาก daemon เริ่มต้นโดยเชลล์ ).
เมื่อ daemon เริ่มต้นโดยกระบวนการมอนิเตอร์เช่น systemd การฟอร์กจะต่อต้าน กระบวนการตรวจสอบควรจะเริ่มบริการใหม่หากเกิดปัญหาดังนั้นจึงจำเป็นต้องทราบว่าบริการออกหรือไม่และเป็นเรื่องยากหากบริการไม่ได้เป็นลูกโดยตรงของกระบวนการตรวจสอบ กระบวนการตรวจสอบไม่ควรจะตายและไม่มีเทอร์มินัลควบคุมดังนั้นจึงไม่มีข้อกังวลเกี่ยวกับสัญญาณที่ไม่ต้องการหรือการเก็บเกี่ยว ดังนั้นจึงไม่มีเหตุผลที่กระบวนการให้บริการจะไม่เป็นลูกของจอภาพและมีเหตุผลที่ดีที่จะเป็นเช่นนั้น
ละเว้นหน้า Arch wiki นี้
มันมีสิ่งผิดปกติอย่างมากเกี่ยวกับการType
ตั้งค่า สิ่งนี้ไม่ได้ จำกัด เพียงแค่คำอธิบายsimple
เท่านั้นยิ่งไปกว่านั้น สิ่งที่กล่าวถึงforking
ก็ผิดเช่นกัน
คำแนะนำที่ถูกต้องสำหรับสิ่งประเภทนี้มีมานานหลายทศวรรษแล้วกว่าที่ systemd จะมีอยู่และย้อนกลับไปอย่างน้อยก็ต้นปี 1990 ตามที่ฉันสังเกตเห็นhttps://unix.stackexchange.com/a/476608/5132ใน systemd doco มีคำแนะนำสำหรับdæmonsรุ่น Johnny-come-เมื่อเร็ว ๆ นี้ซึ่งส่วนใหญ่จะทำซ้ำสิ่งที่ผู้ใช้ daemontools, IBM, ผู้คนใช้inittab
และ ... ดี ... ฉันพูดมาหลายสิบปีแล้ว (เป็นคำตอบที่ได้รับบ่อยอยู่แล้วเมื่อฉันเขียนขึ้นในปี 2544)
ทำซ้ำ:
ถ้าโปรแกรมของคุณมีบางส่วน "dæmonization" กลไกว่าในงาโดยเฉพาะอย่างยิ่งเด็กและออกจากการปกครองที่จะปิดและไม่ได้ใช้มัน ขอบคุณข้อมูล daemontools et al ซึ่งเป็นข้อกำหนดมาเป็นเวลานานหลายโปรแกรมได้เพิ่มความสามารถที่จะไม่มีกลไกดังกล่าวในช่วงกว่า 20 ปีที่ผ่านมาและอื่น ๆ ก็ไม่ได้ตั้งต้นที่จะ "dæmonizing" ตั้งแต่แรกเพื่อให้สามารถใช้ใน โหมดการทำงานเริ่มต้น
การจัดการบริการระบบย่อยกระบวนการบริการเปิดตัวในบริบทภูติแล้ว กระบวนการเหล่านั้นไม่จำเป็นต้อง "dæmonize" (อันที่จริงมันเป็นความเข้าใจผิดในระบบปฏิบัติการสมัยใหม่จำนวนมากที่คิดว่าโปรแกรมสามารถ "d "monize" ได้จากบริบทเซสชันการเข้าสู่ระบบซึ่งเป็นสิ่งที่ "dæmonization" เป็นเรื่องจริง) พวกเขามีค่าสภาพแวดล้อมอยู่แล้วและตัวอธิบายไฟล์ที่เปิดอยู่ เหมาะสมที่จะเรียกใช้บริบทและหลายสิ่งที่ทำโดย "การมอนิเตอร์" ในความเป็นจริงขัดขวางบางสิ่งทั่วไปที่ทำด้วย d withmons เป็นประจำ (เช่นการบันทึกเอาต์พุตมาตรฐาน / ข้อผิดพลาดลงในบันทึก) โดยผู้จัดการบริการ
ต้องการType=simple
ด้วยการเปิดซ็อกเก็ตในช่วงต้น (ซึ่งการจัดการบริการเปิดซ็อกเก็ตเซิร์ฟเวอร์และส่งต่อเป็นตัวบอกไฟล์ที่เปิดอยู่แล้วไปยังโปรแกรมบริการ) หรือType=notify
.
Type=simple
ถือว่าบริการพร้อม (เพื่อให้บริการที่สั่งซื้อตามสามารถเริ่ม / หยุดได้) ทันทีที่กระบวนการบริการเริ่มต้นด้วยการเปิดซ็อกเก็ตก่อนกำหนดโดยใช้ความหมายการเชื่อมต่อซ็อกเก็ตเพื่อชะลอการให้บริการไคลเอ็นต์ ณ จุดที่พยายามเชื่อมต่อกับเซิร์ฟเวอร์สำหรับ บริการจนกว่าเซิร์ฟเวอร์จะพร้อมใช้งานจริงType=notify
มีข้อเสียที่แปลกประหลาดสำหรับ systemd และ Linux (ควบคู่ไปกับปัญหาการใช้งานไม่ได้จากกระบวนการที่มีอายุสั้นเช่นการวางไข่ของเชลล์systemd-notify
และการใช้การแยกวิเคราะห์รูปแบบที่มนุษย์สามารถอ่านได้ไปยังรูปแบบที่เครื่องอ่านได้ในกระบวนการที่มีสิทธิพิเศษโดยที่ ปัญหาการแยกวิเคราะห์ได้เกิดขึ้นแล้วในอดีต) แต่มีข้อได้เปรียบในการให้การควบคุมที่ละเอียดยิ่งขึ้น (จากมุมมองของโปรแกรมบริการ) เมื่อบริการได้รับการพิจารณาว่าพร้อมใช้งานจริง นอกจากนี้ยังช่วยให้สามารถปรับแต่งเอาต์พุตสถานะได้
โปรแกรมบริการทั้งสองประเภทสามารถแยก เป็นการฟอร์คแล้วออกจากกระบวนการเดิมที่เป็นปัญหา
(ควรสังเกตว่านี่เป็นปัญหามากพอ ๆ กับการเรียกใช้โปรแกรมจากเชลล์เช่นเดียวกับการรันโปรแกรมจากตัวจัดการบริการโดยผู้ใช้เห็นว่าโปรแกรมหยุดทำงานและทำให้เชลล์พรอมต์อื่นเกือบจะในทันทีอันที่จริงวันนี้มีคนถามอีกครั้ง เกี่ยวกับการรันโปรแกรมจากเชลล์ที่แยกและออกจากพาเรนต์ที่ทำไมบางครั้งเมื่อฉันรันโปรแกรมในเทอร์มินัลโปรแกรมจะไม่ทำงานในเทอร์มินัล )
Type=oneshot
อาจไม่ใช่สิ่งที่คุณต้องการในกรณีนี้เนื่องจากบริการจะถือว่าพร้อมใช้งานก็ต่อเมื่อโปรแกรมบริการทั้งหมดทำงานจนเสร็จสิ้น มันมีประโยชน์ แต่ด้วยเสียงของมันพวกเขาไม่ได้ใช้กับคุณ
Type=forking
ไม่เคยใช้งาน มันควรเป็นทางเลือกสุดท้ายของความสิ้นหวังเนื่องจากแทบไม่มีโปรแกรมใดพูดถึงโปรโตคอลเลย พวกเขากำลังทำอย่างอื่นซึ่งในความเป็นจริงไม่ใช่โปรโตคอลนี้ไม่สามารถทำงานร่วมกันได้อย่างถูกต้องกับโปรโตคอลนี้และไม่ใช่ความพร้อมในการส่งสัญญาณ
อ่านเพิ่มเติม
- โจนาธานเดอบอยน์พอลลาร์ด (2544) ข้อผิดพลาดที่ควรหลีกเลี่ยงเมื่อออกแบบโปรแกรมภูติยูนิกซ์ คำตอบที่ได้รับบ่อยครั้ง
- โจนาธานเดอบอยน์พอลลาร์ด (2015). คุณไม่จำเป็นต้องแสดงผล จริงๆ. . บ้านแห่งความสยองขวัญ systemd
- โจนาธานเดอบอยน์พอลลาร์ด (2015). ปัญหาโปรโตคอลการเตรียมพร้อมกับdæmonsยูนิกซ์ คำตอบที่ได้รับบ่อยครั้ง
- https://unix.stackexchange.com/a/401611/5132