欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Systemctl stop XXX 时间太长

发布时间:2025/3/19 编程问答 51 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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 时间太长的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。