systemd vs supervisord

過去咱們項目組的應用都是用 supervisord 託管的。最近由於某些因素,沒法使用 supervisord,所以考慮改用 systemd。
做爲主流 Linux 發行版的默認選項,以前多多少少用過一點 systemd。不過此次須要上生產環境,因此抽空深刻研究一番。html

爲何要用 supervisord?程序員

  1. 實現進程的分組管理,好比支持一同啓動/中止多個生產者/消費者實例。docker

  2. 進程崩潰的時候能夠重啓工具

要想改用 systemd,須要看下 systemd 如何應對這兩個問題。
(如無指明,在本文中,supervisord 的配置項在 [program:x] 下面,而 systemd 的配置項則位於 [Service]spa

進程控制

不管 supervisord 仍是 systemd,都採用 ini 做爲配置文件的格式。跟 supervisord 不一樣的是,systemd 每一個程序都要單獨開一個 unit 文件。
supervisord 能夠同時啓動/中止配置文件中因此的進程(或者某個進程組配置中的進程)。systemd 能夠用依賴來實現這一點。下面例子中,咱們
就建立了一個能夠同時管理的進程組:pwa

; group.target
[Unit]
Description=Application
Wants=prog1.service prog2.service
; prog1.service
[Unit]
Description=prog1
PartOf=group.target

[Service]
ExecStart=/usr/bin/prog1
Restart=on-failure
; prog2.service
[Unit]
Description=prog2
PartOf=group.target

[Service]
ExecStart=/usr/bin/prog2
Restart=on-failure

systemctl start group.targetprog1prog2 也會帶起來。systemctl restart group.targetprog1prog2 也會跟着重啓。設計

相對來講,supervisord 的作法更加直觀一些。rest

若是要更改 supervisord 的配置文件,supervisord 須要運行 supervisorctl reread 纔會生效。
而 systemd 則須要 systemctl daemon-reload。半斤八兩吧。
不過 supervisord 有一個好。若是你不知道哪些程序的配置改變了,簡單地執行 supervisorctl update,全部涉及的進程都會被重啓。
而 systemd 貌似作不到這一點。日誌

systemd 能夠指定 stop 操做時能夠選擇的命令(ExecStop=)。另外它還提供了 ExecReload=,能夠自定義調用 systemctl reload xxx 從新讀取程序配置文件時的操做。
supervisord 不支持 reload 指定進程。同時對於 stop 操做,它只容許你選擇要發送哪一種信號...code

supervisord 的 stopwaitsecs 能夠控制 stop 操做後等待程序退出的耐心(以秒衡量)。待給定的耐心都消耗完畢後,supervisord 纔會痛下殺手,發送 SIGKILL。
systemd 對應的配置項是 TimeoutStopSec=。systemd 會給多一次機會,在下最後通牒以前,會先發送 SIGTERM,過另外一個 TimeoutStopSec 以後才發送 SIGKILL。

進程重啓

爲了不在 supervisord 和 systemd 兩套術語間迷糊,請容許我拋棄全部術語,用本身的話描述。
life-cycle

從上圖能夠看到,進程在 RUNNING 以前,會有一個 STARTING 的過程。在 STARTING 過程當中,進程可能會讀取配置文件,進行初始化。
這一過程當中的錯誤處理,跟 RUNNING 狀態的應當有所不一樣。
以上是 supervisord 的想法。
因此 supervisord 提供了單獨的 startretries 配置項,用來配置 STARTING 階段的重啓次數。
systemd 對此沒有特殊處理。

一個程序,從 RUNNING 到 EXITED,有兩種可能:正常退出或異常退出…(廢話)
這兩種狀況,是經過配置的退出碼來區分的。對於 supervisord,這個配置項是 exitcodes。systemd 則經過 SuccessExitStatus 來控制。
有趣的是,exitcodes 的默認值是 0,2,不知道爲什麼它會認爲 2 也是正常的退出碼。

若是配置了 autorestart = true,只要程序退出,supervisord 都會把它啓動起來。相對的,若是配置的是 autorestart = unexpected,則只有
異常退出纔會重啓。這兩個選項,在 systemd 裏對應 Restart=alwaysRestart=on-failure。systemd 還提供了 Restart=on-success(只有正常
退出才重啓)和 Restart=on-abort(只有收到異常信號才重啓)。

對於重啓次數,supervisord 沒有做限定。由於重啓一個程序時,supervisord 會先讓它處於 STARTING 狀態。這個狀態的持續時間,是由配置項
中的 startsecs 決定的,默認 1 秒。若是是不可恢復的錯誤,程序就不可能成功進入到 RUNNING 狀態。固然也許存在這樣的狀況,程序運行 1 秒
後,就會崩潰。那麼它就會陷於不停重啓的無間地獄。

systemd 對此一如既往,提供了 N 多選項以供採用。你能夠用 RestartSec 控制每次重啓的間隔,能夠用 StartLimitIntervalStartLimitBurst 設定
給定週期內可以重啓的次數。好比指定 StartLimitInterval=1sStartLimitBurst=3,就能夠實現跟 supervisord 一致的默認重啓策略。

比較完最基本的兩種功能,讓咱們繼續看看,二者在一些小細節上的對對碰。

控制實例數

supervisord 能夠用 numprocs 來控制單個程序對應的實例數。systemd 也能夠作到這一點,雖然有點麻煩(某種意義上,更增強大)。
systemd 會把以 @ 結尾的 service 文件看成模板,在運行時根據給定的參數展開成多個實例。

具體實現方式見:http://0pointer.de/blog/proje...

日誌

supervisord 可以重定向被託管的程序的 stdout 和 stderr 到日誌文件中,並提供日誌切割服務。systemd 也支持這一點,儘管它的實現有很大的不一樣。

根據鄙人的經驗,基於按期檢查的日誌切割服務,不是個好的選擇。
一旦趕上突發高峯,有可能會出現日誌沒法及時切割的狀況;而調小檢查間隔,大部分狀況下都在無心義地空轉。(說的就是你,logroated)
好在不管是 supervisord,仍是 systemd,提供的切割服務都是實時的。每當寫入內容會超過上限時,就會自動切割。

systemd 的日誌服務是經過 journald 組件實現的。你能夠在 /etc/systemd/journald.conf 中配置它。
journald 默認的日誌存儲形式是 Storage=auto。這個選項比較奇妙,若是你建立了 /var/log/journal 文件夾,那麼它就會把日誌寫到這個文件夾下。不然不進行持久化。

持久化後的日誌是這個樣子的:

/var/log/journal/c4010ceea79847afbedecb60a775db96/
├── system.journal
├── user-1000.journal
└── user-65534.journal

第一次看到這樣的目錄結構,說不定你會大吃一驚。journald 設計者腦洞不是通常的大。從這個結構上,根本看不出應用日誌在哪裏嘛。
不,徹底沒有這樣的必要,由於全部的程序的日誌都會寫到一塊去。不分彼此,全變成一團漿糊。隨便一提,日誌默認都是壓縮的。

要看日誌,你得用 journalctl。好比看 prog1.service 的日誌,須要 journalctl -u prog1.service。要看特定時期的日誌,須要 journalctl --since $timestamp --until $timestamp

這麼前衛的設計我可接受無能。這種 journalctl 控制一切的方式,致使 systemd 日誌沒法集成到傳統的日誌收集工具中。
程序員工具箱中各類 text base 處理工具,對此也大眼瞪小眼,只能對着 journalctl 低聲下氣,接受對方的小脾氣。

journald 提供了三個配置項,RuntimeMaxFileSize=RuntimeMaxFiles=。顧名思義,就是單個日誌文件大小和容許的日誌數。
另外,RuntimeMaxUse=RuntimeKeepFree= 能夠控制總大小的上限。

supervisord 在這方面作的要好得多。經過 stdout/stderr_logfile_maxbytesstdout/stderr_logfile_backups,你能夠規劃每個程序的日誌文件的切割粒度。
不一樣程序的日誌不會擠一塊兒,產生日誌少的程序也不會被產生日誌多的程序干擾。

systemd vs supervisord

除了以上幾點外,還有一些沒有具體提到的功能。
好比 supervisord 經過 priority 配置進程啓動順序,以及 systemd 對應的 Before/After 依賴機制。
好比 supervisord 的 events 功能,和與之相對應的 systemd 的 notify 機制。
好比 supervisord 能夠管理 fastcgi(真有人這麼作嗎)。
好比 systemd 提供的基於 cgroup 的資源限制。
因爲沒有使用經驗,對這些功能就不做一一比較了。

是時候結題了。systemd 和 supervisord 各有長短,不存在哪一方絕對的碾壓。systemd 跟 Linux 緊密結合,所需的依賴少,其提供的保障天然比 supervisord 更可靠。然而在強大的能力背後,也有配置複雜、不易上手等問題。supervisord 偏於應用層,卻所以有獨特的用武之地。舉個例子,許多人會往 docker 打包裏面封入一份 supervisord,讓它來作 PID 1,以此稍微加強下健壯性。換 systemd 作一樣的事,就像用園藝剪刀裁紙,即便可以順利完成,也不免事倍功半。畢竟這樣的方式跟 systemd 的設計是背道而馳的。

相關文章
相關標籤/搜索