一、背景

假如我们自己开发了一个系统,例如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-groupprocessmixednone

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   Notes
                   most others   SPARC
       ─────────────────────────────────────────────────────────────────
       SIGHUP           1           1       1       1
       SIGINT           2           2       2       2
       SIGQUIT          3           3       3       3
       SIGILL           4           4       4       4
       SIGTRAP          5           5       5       5
       SIGABRT          6           6       6       6
       SIGIOT           6           6       6       6
       SIGBUS           7          10      10      10
       SIGEMT           -           7       7      -
       SIGFPE           8           8       8       8
       SIGKILL          9           9       9       9
       SIGUSR1         10          30      16      16
       SIGSEGV         11          11      11      11
       SIGUSR2         12          31      17      17
       SIGPIPE         13          13      13      13
       SIGALRM         14          14      14      14
       SIGTERM         15          15      15      15
       SIGSTKFLT       16          -       -        7
       SIGCHLD         17          20      18      18
       SIGCLD           -          -       18      -
       SIGCONT         18          19      25      26
       SIGSTOP         19          17      23      24
       SIGTSTP         20          18      24      25
       SIGTTIN         21          21      26      27
       SIGTTOU         22          22      27      28
       SIGURG          23          16      21      29
       SIGXCPU         24          24      30      12
       SIGXFSZ         25          25      31      30
       SIGVTALRM       26          26      28      20
       SIGPROF         27          27      29      21
       SIGWINCH        28          28      20      23
       SIGIO           29          23      22      22
       SIGPOLL                                            Same as SIGIO
       SIGPWR          30         29/-     19      19
       SIGINFO          -         29/-     -       -
       SIGLOST          -         -/29     -       -
       SIGSYS          31          12      12      31
       SIGUNUSED       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信号退出

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐