Linux 多進程服務配置 systemd


Linux 多進程服務配置 systemd

整個項目由多個進程共同運行,現在需要一個可靠的保活機制,以便能夠在進程崩潰的時候能夠快速把它拉起來。有什么想法呢?最直觀的解決方案無非就是寫個保活腳本,在后台一直運行,如果發現某進程被關閉了,那么由腳本拉起來,但是腳本它自己掛掉怎么辦?(總不能使用腳本繼續保活保活腳本套娃吧)。此外,另一個辦法就是配置出來一個服務,讓Linux操作系統幫你守護進程,顯然,這種辦法完全不需要擔心守護進程自己掛掉,畢竟是systemd幫你守護,如果它掛掉了,操作系統應該也沒了。

sysvinit和systemd

sysvinitsystemd分別是兩個Linux操作系統的初始化系統,Linux操作系統的服務就是它們運行起來的。在centos7之前使用的是sysvinitcentos7及之后使用的是systemd。此外還有ubuntuUpStart,不過新版的Ubuntu也使用systemd了。

比較明顯的特征就是,舊版的linux使用service httpd start啟動服務,新版的linux使用systemctl start httpd來啟動服務,此外使用initd作為初始化系統的操作系統添加服務是在/etc/init.d/中添加腳本,而使用systemd作為初始化系統的操作系統只需要在/etc/systemd/system/文件夾中添加配置文件就好了。

具體和systemd相關的介紹可以看這里:淺析init和systemd【圖文】_babylater_51CTO博客

一般來說,為了保持系統ABI的兼容性,系統的systemd版本不會特別激進,所以需要老一點文檔,比如CentOS7運行的systemd對應的版本文檔應該是這個systemd.service (archive.org)

多進程保活

首先最官方的文檔在這里:systemd.service (www.freedesktop.org)

不過需要注意的是,需要注意操作系統上面使用的systemd的版本,通過執行systemd --version看到,比如我這個版本就是systemd 219,而最新的文檔是systemd 250(這個可以在上面url頁面的右上角看到)

但是,如果正在使用的systemd的版本和文檔版本相差太大,可能會出現不准確的情況。比如在systemd 230之前是沒有StartLimitInterSec這個選項的。此時就需要這個網站https://web.archive.org/,它會給網頁拍攝快照,相當棒。此外,[systemd.unit 中文手冊 金步國] (jinbuguo.com)這位譯者翻譯了相關文檔,不過也請注意文檔版本的問題。

創建配置文件(設定重試次數)

配置文件需要創建在/etc/systemd/system/文件夾里面,比如一個配置文件如下,文件名/etc/systemd/system/program.service

[Unit]
Description=program's service

[Service]
Type=idle
Environment=LD_LIBRARY_PATH=.:/export/home/admin/usr/install/gcc940/lib
ExecStart=/export/home/admin/gamed/program/bin/program gamesys.conf 1
Restart=always
RestartSec=5
StandardOutput=null
StandardError=null
StartLimitInterval=40000000
StartLimitBurst=3

[Install]
WantedBy=multi-user.target

新版本的系統(systemd 230之后),沒有StartLimitInterval需要使用StartLimitIntervalSec,並且StartLimitIntervalSecStartLimitBurst兩個項在[Unit]節區!!!詳情請通過https://web.archive.org/查詢和系統systemd版本對應的文檔

然后通過systemctl start program.service啟動服務,通過systemctl status program.service查看服務狀態和啟動失敗原因,通過systemctl stop program.service關閉服務。

首先一個服務的配置文件是.service作為后綴的,結構類似於windows.ini配置文件,其中一般由三個部分。分別是

  • [Unit]:包含與單元類型無關的通用信息
  • [Service]:其中是服務的屬性
  • [Install]: 該小節包含單元的啟用信息。 事實上,systemd(1) 在運行時並不使用此小節。 只有 systemctl(1)enabledisable 命令在啟用/停用單元時才會使用此小節(個人理解:決定在systemd處於什么目標狀態下有效)

其中有多個選項,例如上面的配置文件,含義分別如下

  • Description 是作為服務的描述

  • Type表示服務的類型,可以是simple exec forking oneshot dbus notify,一般使用simple

  • Environment 可以指定服務會用到的環境變量

  • ExecStart 是通過systemctl start xxx啟動服務時執行的命令

    • 需要注意的是,實測這里不能直接指定>重定向到文件,如有需要見下面StandardOutput
  • Restart 表示重啟的條件,可以取no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, always之一

  • RestartSec 如果重啟,兩次重啟之間的間隔 默認是100ms

  • StandardOutput 標准輸出,老版本(比如Systemd 219)不能直接指定文件,新版本可以這樣指定文件file:/var/log/xxx.log

  • StandardError 同上不過是標准錯誤

  • StartLimitIntervalStartLimitBurst 這兩個表示在StartLimitInterval指定的時間里重試失敗StartLimitBurst次則放棄重試,

    • 可以通過systemctl reset-failed 重置失敗次數,
    • 需要注意的是,手動停止服務也會被計數,並且如果設定上面兩個參數,失敗后必須手動重置
    • 再者,Systemd 230之后使用StartLimitIntervalSec替代了StartLimitInterval這里很坑...所以需要注意文檔版本
    • 新版本這個選項是在Unit節區
  • WantedBy它的值是一個或多個 Target,當前 Unit 激活時(enable)符號鏈接會放入/etc/systemd/system目錄下面以 Target 名 + .wants后綴構成的子目錄中

    (這里放一個我自己的理解,systemd有類似於initd的運行級別的東西,詳見淺析init和systemd【圖文】_babylater_51CTO博客Sysvinit 運行級別和 systemd 目標的對應表,所以 WantedBy設置為 multi-user.target的含義就比較明確了,也即是systemdctl enable xx.service之后,在對應目標狀態下啟用)

具體的含義見systemd.service (www.freedesktop.org)

以上配置能夠實現的效果就是進程因為任何方式停止運行(除了手動stop),都會觸發重啟,但是在4000000秒之內只重啟3次,重試三次不成功,就不再嘗試,此時並不能直接systemctl start program,需要首先systemctl reset-failed(重置失敗計數)之后才能再次start

如果不使用StartLimitIntervalSecStartLimitBurst 就不需要考慮systemctl reset-failed的使用了

多進程服務管理

如果需要創建很多服務,但是服務的配置文件只有ExecStart項有細微區別,那么可以考慮使用模板功能。

比如,創建服務文件/etc/systemd/system/ping@.service

[Unit]
Description=Ping service %i

[Service]
Type=simple
ExecStart=/usr/bin/ping %i

[Install]
WantedBy=multi-user.target

啟動進程可以這樣systemctl start ping@127.0.0.1.service,實際上,啟動服務可以省略.service后綴,也即是systemctl start ping@127.0.0.1,如果要一次啟動多個服務,可以systemctl start ping@127.0.0.1 ping@127.0.0.2,停止服務也是類似。

這樣,如果想要ping別的地址,只需要修改命令中@之后的字符串就好了。

也支持如下這樣拼接字符串

[Unit]
Description=Ping service %i

[Service]
Type=simple
ExecStart=/usr/bin/ping 127.0.0.%i

[Install]
WantedBy=multi-user.target

systemctl start ping@1就能執行ping 127.0.0.1服務

對於配置文件中的%i其實是有大小寫區別的,%i是轉義之后的字符串 %I是不轉義的字符串,對於完整的說明符列表,見systemd.unit (www.freedesktop.org)

鏈式啟動(服務依賴)

有這么一種情況,需要同時啟動多個服務,並且他們有啟動順序的限制。那么可以像下面這么配置

假設有 A進程B進程C進程,想要按順序依次啟動,那么可以這么配置

/etc/systemd/system/C.service

[Unit]
Description=C Process
Requires=B.service
After=B.service

[Service]
Type=simple
ExecStart=/export/CProgram

[Install]
WantedBy=multi-user.target

/etc/systemd/system/B.service

[Unit]
Description=B Process
Requires=A.service
After=A.service

[Service]
Type=simple
ExecStart=/export/BProgram

[Install]
WantedBy=multi-user.target

/etc/systemd/system/A.service

[Unit]
Description=A Process

[Service]
Type=simple
ExecStart=/export/AProgram

[Install]
WantedBy=multi-user.target

效果是,systemctl start C.service之后幾個進程會依次啟動,Requires指定了幾個服務之間的依賴關系,因為通過After選擇指定了服務間啟動順序,所以幾個服務是依次啟動的。如果沒有After啟動順序不被保證

如果,此時systemctl stop A.service,那么幾個服務都會被關閉,因為Requires要求了前置服務必須存在,否則自身也不應該啟動。如果不想自身服務被關閉,那么可以把Requires(要求)替換成Wants(想要)。

如果要形成依賴鏈,除了After也可以使用Before

完整說明參見systemd.unit (www.freedesktop.org)

指定關閉進程方式 - ExecStop

可以通過ExecStop選項關閉由ExecStart啟動的服務,因為有些程序需要發送特定的信號才能安全退出,所以這個選項會很有用。而對於其他被主進程拉起來的進程,按照KillMode的設置處理,默認情況下,停止服務會關閉主進程以及主進程啟動的所有子進程。

而對於KillMode有如下幾個設置,分別是

  • control-group:會干掉主進程及子進程 這是默認選項
  • mixed: SIGTERM 信號被發送到主進程,而隨后的 SIGKILL 信號被發送到單元控制組的所有剩余進程,可以通過KillSignal設置關閉主進程的信號
  • process: 僅關閉主進程
  • none: 什么也不干

詳情見:systemd.kill (www.freedesktop.org)

例如,如果要事先約定某進程需要發送SIGUSR1信號才能安全結束,那么可以在[Service]節區設定ExecStop=kill -SIGUSR1 $MAINPID

上文$MAINPID類似於環境變量,表示主進程的pid,完整列表見[systemd.exec (www.freedesktop.org)](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Environment Variables Set or Propagated by the Service Manager)

查看服務輸出 - journalctl

systemd不僅用來運行服務,它同時也有日志服務,用於取代老系統的syslog

運行的服務標准輸出和錯誤輸出會被交給journald管理,查看某個服務可以使用這樣的命令journalctl -u ping@1-e參數可以跳到最新一行 -f參數可以看到實時輸出,-n參數可以指定輸出的行數,-r反序輸出。

例如journalctl -u ping@1 -e 或者 journalctl -u ping@1 -f

如果服務的輸出太多,那么可以在.servive文件中的[Unit]節區配置StandardOutput=null

也可以通過systemctl status xx.service查看服務的部分輸出

具體使用參考

持久化journalctl日志清空命令查看配置參數詳解_陳溈亮博客 (chenweiliang.com)

journalctl (www.freedesktop.org)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM