空闲时间后停用 systemd 服务

空闲时间后停用 systemd 服务

我希望服务按需启动而不是启动时启动。为此,我可以使用 systemd 套接字激活(使用服务和套接字文件)。

但这是一个资源有限的服务器,因此在一段时间(例如1小时)不活动后,我想停止该服务(直到再次触发)。我怎样才能做到这一点?

我浏览了一些文档但我不知道这是否受支持。


更新:
假设这不受支持,那么该用例可能仍然很常见。实现这一目标的好方法/解决方法是什么?

答案1

systemd 中的套接字激活可以以两种模式工作:

  • Accept=true:systemd 保留侦听套接字,接受每个传入连接,为每个连接生成一个新进程并将已建立的套接字传递给它。这种情况很简单(每个进程完成后都会退出)。
  • Accept=false:systemd 创建监听套接字并监视它的传入连接。一旦有人进来,systemd 就会生成该服务并将侦听套接字传递给它。然后,该服务接受传入连接和任何后续连接。 Systemd 不再跟踪套接字上发生的情况,因此它无法检测不活动状态。

在后一种情况下,我认为唯一真正干净的解决方案是修改应用程序,使其在空闲一段时间后退出。如果你做不到这一点,一个粗略的解决方法可能是设置 cron 或 systemd 计时器来每小时终止一次服务。如果服务很少生成,这可能是一个合理的近似值。

请注意,这种用例可能非常罕见。处于 poll()/select() 等待连接的进程不会消耗任何 CPU 时间,因此在这种情况下使用的唯一资源是内存。仅仅设置一些交换并让内核决定是否值得将进程一直保留在 RAM 中可能会更容易、更有效。

答案2

如果您无法调整程序的主循环,使其在没有套接字活动的情况下在一段时间后退出,那么您可以使用systemd-socket-proxyd,它确实有一个空闲超时选项。

假设您的服务名为thing.service.它正在监听监听地址。您将添加一个位于 和 之间的服务thing.socketthing.service转发来自监听地址PRIVATE_LISTEN_ADDR

  1. thing调整监听配置PRIVATE_LISTEN_ADDR代替监听地址。这可能在 中完成thing.service,或者可能在thing.conf- 这取决于应用程序。

  2. 将您的服务配置为在没有其他单元依赖它时停止。这可以通过设置来完成StopWhenUnneeded=true[Unit]你的文件的部分thing.service

  3. 添加thing-proxy.service。这使得连接到thing.serviceviaPRIVATE_LISTEN_ADDR。我们在这里将空闲超时配置为 10 分钟。

    [Unit]
    Requires=thing.service
    After=thing.service
    Requires=thing.socket
    After=thing.socket
    
    [Service]
    ExecStart=/usr/lib/systemd/systemd-socket-proxyd --exit-idle-time=10min PRIVATE_LISTEN_ADDR
    PrivateTmp=yes
    PrivateNetwork=yes
    
  4. 调整thing.socket使其启动thing-proxy.service而不是thing.service

    [Socket]
    Accept=false
    ListenStream=LISTEN_ADDR
    Service=thing-proxy.service
    
    [Install]
    WantedBy=sockets.target
    

的价值观监听地址PRIVATE_LISTEN_ADDR可以hostname:port用于 TCP 服务,或 UNIX 域套接字路径,或两者,具体取决于您想要什么以及应用程序可以做什么。它们只需要是不同的地址,因为现在您有两个进程正在侦听连接。

答案3

如果您的服务能够被套接字激活,那么您可以Accept=yes在套接字单元中使用。然后,将为每个连接执行一个新的服务实例,并在套接字关闭时停止。

相关内容