Systemctl stop XXX 时间太长
一、背景
假如我們自己開發了一個系統,例如web,想要通過systemd來控制。但使用過程中,出現了問題,systemctl stop XXX 的時間太長了。
二、問題原因
先說結論:我們的系統停止的辦法采用的是默認的kill -15(SIGTERM)的辦法,kill -15(SIGTERM)不會導致程序立刻停止。超時之后才會kill -9(SIGKILL)強制殺死。
接下來是分析。
我們的配置文件是這樣的。
[Unit] Description=sxxxxxx After=network.target xx.service xx.service xx.service Before=xx.service [Service] ExecStart=xxxxxxxxxxxxxxxxx WorkingDirectory=/xxxx/xxxx/xxx/ StandardOutput=inherit StandardError=inherit Restart=always User=root Group=root[Install] WantedBy=multi-user.target里面配置了程序如何啟動,卻沒有配置如何停止,看看官方文檔里面的說明。
ExecStop=
這是一個可選的指令, 用于設置當該服務被要求停止時所執行的命令行。 語法規則與?ExecStart=?完全相同。 執行完此處設置的所有命令行之后,該服務將被視為已經停止, 此時,該服務所有剩余的進程將會根據?KillMode=?的設置被殺死(參見?systemd.kill(5))。 如果未設置此選項,那么當此服務被停止時, 該服務的所有進程都將會根據?KillSignal=?的設置被立即全部殺死。 與?ExecReload=?一樣, 也有一個特殊的環境變量?$MAINPID?可用于表示主進程的PID 。
一般來說,不應該僅僅設置一個結束服務的命令而不等待其完成。 因為當此處設置的命令執行完之后, 剩余的進程會被按照?KillMode=?與?KillSignal=?的設置立即殺死, 這可能會導致數據丟失。 因此,這里設置的命令必須是同步操作,而不能是異步操作。
注意,僅在服務確實啟動成功的前提下,才會執行?ExecStop=?中設置的命令。 如果服務從未啟動或啟動失敗(例如,任意一個?ExecStart=,?ExecStartPre=,?ExecStartPost=?中無 "-" 前綴的命令執行失敗或超時), 那么?ExecStop=?將會被跳過。 如果想要無條件的在服務停止后執行特定的動作,那么應該使用?ExecStopPost=?選項。 如果服務啟動成功,那么即使主服務進程已經終止(無論是主動退出還是被殺死),也會繼續執行停止操作。 因此停止命令必須正確處理這種場景,如果 systemd 發現在調用停止命令時主服務進程已經終止,那么將會撤銷 $MAINPID 變量。
重啟服務的動作被實現為"先停止、再啟動"。所以在重啟期間,將會執行?ExecStop=?與?ExecStopPost=?命令。 推薦將此選項用于那些必須在服務干凈退出之前執行的命令(例如還需要繼續與主服務進程通信)。當此選項設置的命令被執行的時候,應該假定服務正處于完全正常的運行狀態,可以正常的與其通信。 如果想要無條件的在服務停止后"清理尸體",那么應該使用?ExecStopPost=?選項。
?有這么一句話
如果未設置此選項,那么當此服務被停止時, 該服務的所有進程都將會根據?KillSignal=?的設置被立即全部殺死
再來看另一段有關KillSignal
?KillMode=
設置在單元停止時,殺死進程的方法。 取值范圍如下:?control-group,?process,?mixed,?none
control-group?表示殺死該單元的 cgroup 內的所有進程(對于 service 單元,還要先執行?ExecStop=?動作)。?process?表示僅殺死主進程。?mixed?表示首先向主進程發送?SIGTERM?信號(見下文), 然后再向該單元的 cgroup 內的所有其他進程發送?SIGKILL?信號(見下文)。?none?表示僅執行?ExecStop=?動作, 而不殺死任何進程。 這會導致即使單元已經停止, 但是該單元的 cgroup 依然一直存在, 直到其中的進程 全部死亡。
殺死進程的時候, 第一步首先使用?KillSignal=?信號(默認為?SIGTERM) (如果?SendSIGHUP=yes?,那么還會立即緊跟一個?SIGHUP?信號), 若等候?TimeoutStopSec=?時間后, 進程仍然未被殺死, 則繼續第二步使用?SIGKILL?或?FinalKillSignal=?信號(除非?SendSIGKILL=no)強制殺死。 詳見?kill(2)?手冊。
默認值是?control-group
?也就是說,默認的方法就是先用kill -15(SIGTERM) 殺,超時殺不掉再用kill -9(SIGKILL)強殺。
信號和數字對應關系可以參考下表。
?
Signal x86/ARM Alpha/ MIPS PARISC Notesmost others SPARC─────────────────────────────────────────────────────────────────SIGHUP 1 1 1 1SIGINT 2 2 2 2SIGQUIT 3 3 3 3SIGILL 4 4 4 4SIGTRAP 5 5 5 5SIGABRT 6 6 6 6SIGIOT 6 6 6 6SIGBUS 7 10 10 10SIGEMT - 7 7 -SIGFPE 8 8 8 8SIGKILL 9 9 9 9SIGUSR1 10 30 16 16SIGSEGV 11 11 11 11SIGUSR2 12 31 17 17SIGPIPE 13 13 13 13SIGALRM 14 14 14 14SIGTERM 15 15 15 15SIGSTKFLT 16 - - 7SIGCHLD 17 20 18 18SIGCLD - - 18 -SIGCONT 18 19 25 26SIGSTOP 19 17 23 24SIGTSTP 20 18 24 25SIGTTIN 21 21 26 27SIGTTOU 22 22 27 28SIGURG 23 16 21 29SIGXCPU 24 24 30 12SIGXFSZ 25 25 31 30SIGVTALRM 26 26 28 20SIGPROF 27 27 29 21SIGWINCH 28 28 20 23SIGIO 29 23 22 22SIGPOLL Same as SIGIOSIGPWR 30 29/- 19 19SIGINFO - 29/- - -SIGLOST - -/29 - -SIGSYS 31 12 12 31SIGUNUSED 31 - - 31那么 kill -15(SIGTERM) 和kill -9(SIGKILL) 到底有啥區別呢?這里就不展開了。
簡而言之。
大部分程序接收到kill -15(SIGTERM)信號后,會先釋放自己的資源,然后再停止。
三、解決辦法
在配置文件中增加一句
ExecStop=/usr/bin/kill -9 $MAINPID整個文件的樣子大概是
[Unit] Description=sxxxxxx After=network.target xx.service xx.service xx.service Before=xx.service [Service] ExecStart=xxxxxxxxxxxxxxxxx ExecStop=/usr/bin/kill -9 $MAINPID WorkingDirectory=/xxxx/xxxx/xxx/ StandardOutput=inherit StandardError=inherit Restart=always User=root Group=root[Install] WantedBy=multi-user.target這樣做,就能夠導致在收到stop指令的時候,直接發kiil -9信號退出
總結
以上是生活随笔為你收集整理的Systemctl stop XXX 时间太长的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 本地虚拟机ceph 100.000% p
- 下一篇: 制造网卡的延迟