使用 systemd 创建 Linux 服务

在编写 Web 应用程序时,我经常需要将计算繁重的任务卸载到异步工作脚本,为以后安排任务,甚至编写一个监听套接字以直接与客户端通信的守护程序。

虽然有时可能会有更好的工具来完成这项工作——总是考虑先使用现有的软件,例如任务队列服务器——编写自己的服务可以为你提供一定程度的灵活性,当受第三方约束时你永远无法获得 软件。

很酷的是,创建 Linux 服务相当容易:使用我们最喜欢的编程语言编写一个长时间运行的程序,然后使用 systemd 将其转换为服务。

程序

让我们使用 PHP 创建一个小型服务。 我可以看到你的眉毛在上升,但效果出奇的好。 我们将监听 UDP 端口 10000,并返回通过 ROT13 转换收到的任何消息:

<?php

$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($sock, '0.0.0.0', 10000);

echo "server started\n";
for (;;) {
    socket_recvfrom($sock, $message, 1024, 0, $ip, $port);
    $reply = str_rot13($message);
    socket_sendto($sock, $reply, strlen($reply), 0, $ip, $port);
}

下面让我们启动它

$ php server.php

使用 systemd 创建 Linux 服务

并在另一个终端测试它:

$ nc -u 127.0.0.1 10000
Hello, world!
Uryyb, jbeyq!

使用 systemd 创建 Linux 服务

酷,它的工作原理。 现在我们希望这个脚本一直运行,在失败的情况下重新启动(意外退出),甚至在服务器重新启动时仍然存在。 这就是 systemd 发挥作用的地方。

把它变成一种服务

让我们创建一个名为 /etc/systemd/system/rot13.service 的文件

[Unit]
Description=ROT13 demo service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=centos
ExecStart=/usr/bin/env php /path/to/server.php

[Install]
WantedBy=multi-user.target

我们需要:

  • 在 User= 之后设置您的实际用户名
  • 在 ExecStart= 中设置脚本的正确路径

而已。 我们现在可以启动服务了:

$ systemctl start rot13

并自动让它在启动时启动:

$ systemctl enable rot13

深入理解

既然我们的服务(希望)可以正常工作,那么深入了解配置选项并确保它始终按期望的那样工作可能很重要。

以正确的顺序开始

我们可能想知道 After= 指令做了什么。 它只是意味着我们的服务必须在网络准备好后启动。 如果程序希望 MySQL 服务器启动并运行,应该添加:

After=mysqld.service

退出时重新启动

默认情况下,如果程序因任何原因退出,systemd 不会重新启动服务。 对于必须始终可用的服务,这通常不是我们想要的,因此我们指示它始终在退出时重新启动:

Restart=always

如果退出状态不为 0,我们也可以使用 on-failure 仅重新启动。

默认情况下,systemd 会在 100 毫秒后尝试重新启动。 我们可以使用以下方法指定尝试重新启动之前要等待的秒数:

RestartSec=1

避免陷阱:start 限制

我个人不止一次陷入这种情况。 默认情况下,当像我们一样配置 Restart=always 时,如果它在 10 秒的时间间隔内启动超过 5 次,systemd 将放弃重新启动我们的服务。 永远。

有两个 [Unit] 配置选项负责:

StartLimitBurst=5
StartLimitIntervalSec=10

RestartSec 指令对结果也有影响:如果将其设置为 3 秒后重新启动,那么我们永远无法在 10 秒内达到 5 次失败重试。

始终有效的简单修复方法是设置 StartLimitIntervalSec=0。 这样,systemd 将尝试永远重启我们的服务。

不过,最好将 RestartSec 设置为至少 1 秒,以避免在出现问题时给服务器造成太大压力。

作为替代方案,我们可以保留默认设置,并在达到启动限制时要求 systemd 重新启动服务器,使用 StartLimitAction=reboot

真的是这样吗?

这就是使用 systemd 创建 Linux 服务所需要的全部内容:编写一个引用我们的长时间运行程序的小配置文件。

Systemd 多年来一直是 RHEL/CentOSFedoraUbuntuDebian 和其他系统中的默认初始化系统,因此我们的服务器很可能已准备好托管自制服务!