Tại sao “tiến trình không được rẽ nhánh” đối với các dịch vụ loại đơn giản trong systemd?

Aug 15 2020

Tôi muốn viết systemdcác tệp đơn vị của riêng mình để quản lý các lệnh chạy thực sự dài 1 (theo thứ tự hàng giờ). Trong khi xem bài báo ArchWiki trên systemd , nó cho biết những điều sau về việc chọn kiểu khởi động:

Type=simple(mặc định): systemd coi dịch vụ sẽ được khởi động ngay lập tức. Quá trình không được fork . Không sử dụng loại này nếu các dịch vụ khác cần được đặt hàng trên dịch vụ này, trừ khi nó được kích hoạt ổ cắm.

Tại sao quá trình không phải fork ở tất cả? Có phải nó đang đề cập đến việc fork theo phong cách của quá trình triệu hồi daemon (fork cha mẹ, sau đó thoát ra), hay bất kỳ loại fork nào?


1 Tôi không muốn tmux / screen vì tôi muốn có một cách kiểm tra trạng thái và khởi động lại dịch vụ đơn giản hơn mà không cần dùng đến tmux send-keys.

Trả lời

41 Gilles'SO-stopbeingevil' Aug 15 2020 at 17:29

Dịch vụ được phép gọi cuộc gọi forkhệ thống. Systemd sẽ không ngăn chặn nó, hoặc thậm chí thông báo nếu nó xảy ra. Câu này đề cập cụ thể đến việc thực hành fork ở phần đầu của một daemon để cách ly daemon khỏi tiến trình cha của nó. “Quy trình không được rẽ nhánh [và thoát khỏi quy trình gốc trong khi chạy dịch vụ trong quy trình con]”.

Các trang người đàn ông giải thích điều này một cách chi tiết hơn, và với một từ ngữ mà không dẫn đến sự nhầm lẫn đặc biệt này.

Nhiều chương trình được sử dụng làm daemon có một chế độ (thường là chế độ mặc định) mà khi khởi động, chúng sẽ tự tách mình khỏi cha mẹ của chúng. Daemon bắt đầu, gọi fork()và thoát ra khỏi cha mẹ. Tiến trình con gọi setsid()để nó chạy trong nhóm tiến trình và phiên của chính nó, và chạy dịch vụ. Mục đích là nếu daemon được gọi từ một dòng lệnh shell, thì daemon sẽ không nhận được bất kỳ tín hiệu nào từ kernel hoặc từ shell ngay cả khi có điều gì đó xảy ra với thiết bị đầu cuối chẳng hạn như đóng thiết bị đầu cuối (trong trường hợp đó, trình nền sẽ gửi SIGHUP cho tất cả các nhóm quy trình mà nó biết). Điều này cũng làm cho quy trình phục vụ được init thông qua, quy trình này sẽ gặt hái nó khi nó thoát ra, tránh một thây ma nếu daemon được khởi động bởi thứ gì đó không wait()dành cho nó (điều này sẽ không xảy ra nếu daemon được khởi động bằng shell ).

Khi một daemon được khởi động bởi một quy trình giám sát chẳng hạn như systemd, thì việc phân nhánh sẽ phản tác dụng. Quá trình giám sát phải khởi động lại dịch vụ nếu nó gặp sự cố, vì vậy nó cần biết liệu dịch vụ có thoát hay không và điều đó rất khó nếu dịch vụ không phải là con trực tiếp của quá trình giám sát. Quá trình giám sát được cho là không bao giờ chết và không có thiết bị đầu cuối điều khiển, vì vậy không có lo ngại về các tín hiệu không mong muốn hoặc thu hoạch. Vì vậy, không có lý do gì để quy trình dịch vụ không phải là con của màn hình, và có lý do chính đáng để làm như vậy.

15 JdeBP Aug 16 2020 at 11:59

Bỏ qua trang wiki Arch này.

Nó đã có những điều khá sai lầm liên quan đến Typecài đặt. simpleHơn nữa, điều này không chỉ giới hạn trong các mô tả của nó . Những gì nó nói về forkingcũng sai.

Các khuyến nghị chính xác cho loại điều này đã tồn tại lâu hơn nhiều thập kỷ so với bản thân systemd đã tồn tại và ít nhất là từ đầu những năm 1990. Như tôi đã lưu ý tạihttps://unix.stackexchange.com/a/476608/5132, trong systemd doco, gần đây có một phiên bản Johnny-come-in của các khuyến nghị dành cho linh vật, phần lớn lặp lại những gì người dùng daemontools, IBM, những người đang sử dụng inittab, và… à… tôi đã nói trong nhiều thập kỷ. (Nó đã là một câu trả lời thường xuyên được đưa ra khi tôi viết nó như vậy vào năm 2001.)

Lặp lại:

Nếu chương trình của bạn có một số cơ chế "dæmonization", cụ thể là fork con và thoát khỏi quy trình cha, hãy tắt nó đikhông sử dụng nó . Cảm ơn daemontools et al. nơi mà điều này đã được yêu cầu trong một thời gian dài, nhiều chương trình đã phát triển khả năng không có cơ chế như vậy trong hơn 20 năm qua, và những chương trình khác chỉ đơn giản là không mặc định "dæmonizing" ngay từ đầu nên có thể được sử dụng trong chế độ hoạt động mặc định của họ.

Hệ thống con quản lý dịch vụ khởi chạy các quy trình dịch vụ trong ngữ cảnh linh thú đã có . Những quá trình đó không cần phải "dæmonize". (Thật vậy, thật là sai lầm trên nhiều hệ điều hành hiện đại khi nghĩ rằng các chương trình thậm chí có thể "linh hóa" từ ngữ cảnh phiên đăng nhập, đó là những gì thực sự là "linh hóa".) Chúng đã có các giá trị môi trường và mở bộ mô tả tệp, phù hợp với bối cảnh linh thú, và một số việc được thực hiện bằng cách "linh thú hóa" trên thực tế đã cản trở một số công việc truyền thống thường xuyên được thực hiện với linh thú (ví dụ như ghi lại kết quả / lỗi tiêu chuẩn của chúng vào nhật ký) bởi các nhà quản lý dịch vụ.

Ưu tiên hơn Type=simple, với việc mở ổ cắm sớm (nơi quản lý dịch vụ mở các ổ cắm máy chủ và chuyển chúng dưới dạng bộ mô tả tệp đã mở cho chương trình dịch vụ) hoặc Type=notify.

  • Type=simple xử lý dịch vụ ở trạng thái sẵn sàng (để các dịch vụ được đặt hàng theo đó có thể được khởi động / dừng) ngay khi quá trình dịch vụ bắt đầu, với việc mở ổ cắm sớm sử dụng ngữ nghĩa kết nối ổ cắm để trì hoãn các máy khách dịch vụ, tại các điểm mà chúng cố gắng kết nối với máy chủ cho đến khi máy chủ thực sự sẵn sàng.
  • Type=notifycó nhược điểm là đặc biệt đối với systemd và Linux (cùng với các vấn đề không hoạt động được từ các quy trình tồn tại trong thời gian ngắn như tạo shell systemd-notifyvà sử dụng phân tích cú pháp các biểu mẫu có thể đọc được của con người thành các biểu mẫu có thể đọc được của máy trong một quy trình đặc quyền, trong đó các vấn đề phân tích cú pháp đã từng xảy ra trước đây) nhưng có lợi thế là cung cấp khả năng kiểm soát tốt hơn (theo quan điểm của chương trình dịch vụ) về thời điểm dịch vụ thực sự được coi là sẵn sàng. Nó cũng cho phép một số tùy chỉnh của đầu ra trạng thái.

Các chương trình dịch vụ, thuộc cả hai loại, đều có thể phân nhánh. Đó là sự cố và sau đó thoát khỏi quy trình ban đầu là vấn đề.

(Cần lưu ý rằng đây cũng là một vấn đề đối với việc chạy các chương trình từ shell cũng như đối với việc chạy các chương trình từ các trình quản lý dịch vụ, với việc người dùng thấy chương trình chấm dứt và gây ra một lời nhắc shell khác gần như ngay lập tức. Thật vậy, chỉ hôm nay ai đó đã hỏi lại , về việc chạy các chương trình từ shell rẽ nhánh và thoát khỏi cha, tại Tại sao đôi khi khi tôi chạy một chương trình trong terminal, chương trình đó không chạy trong terminal?. )

Type=oneshotcó thể không phải là những gì bạn muốn trong trường hợp cụ thể này, vì dịch vụ chỉ được coi là sẵn sàng khi toàn bộ chương trình dịch vụ đã chạy xong. Nó có những công dụng của nó, nhưng về âm thanh của nó, chúng không áp dụng cho bạn.

Không bao giờ sử dụng Type=forking. Nó sẽ là phương sách cuối cùng của sự tuyệt vọng, vì hầu như không có chương trình nào thực sự nói giao thức . Họ đang làm một cái gì đó khác , mà trên thực tế không phải là giao thức này, không tương thích chính xác với giao thức này và trên thực tế không phải là tín hiệu sẵn sàng.

đọc thêm

  • Jonathan de Boyne Pollard (2001). Những sai lầm cần tránh khi thiết kế chương trình linh thú Unix . Các câu trả lời thường được đưa ra.
  • Jonathan de Boyne Pollard (2015). Bạn thực sự không cần phải daemonize. Có thật không. . The systemd House of Horror.
  • Jonathan de Boyne Pollard (2015). Các vấn đề về giao thức sẵn sàng với Unix dæmons . Các câu trả lời thường được đưa ra.
  • https://unix.stackexchange.com/a/401611/5132