« 上一篇下一篇 »

在Linux系统中使用systemd 设置定时器,让服务器启动1分钟后才运行游戏服务器

   我们知道了如何手动的、在开机与关机时、在启用某个设备时、在文件系统发生改变时 启用与禁用 systemd 服务。定时器增加了另一种启动服务的方式,基于……时间。尽管与定时任务很相似,但 systemd 定时器稍微地灵活一些。让我们展开本系列前两篇文章中你所设置的 Minetest 服务器作为如何使用定时器单元的第一个例子。如果你还没有读过那几篇文章,可以现在去看看。

  你将通过创建一个定时器来“改进” Minetest 服务器,使得在服务器启动 1 分钟后运行游戏服务器而不是立即运行。这样做的原因可能是,在启动之前可能会用到其他的服务,例如发邮件给其他玩家告诉他们游戏已经准备就绪,你要确保其他的服务(例如网络)在开始前完全启动并运行。

最终,你的 minetest.timer 单元看起来就像这样:

  1. # minetest.timer

  2. [Unit]

  3. Description=Runs the minetest.service 1 minute after boot up

  4.  

  5. [Timer]

  6. OnBootSec=1 m

  7. Unit=minetest.service

  8.  

  9. [Install]

  10. WantedBy=basic.target

一点也不难吧。

如以往一般,开头是 [Unit] 和一段描述单元作用的信息,这儿没什么新东西。[Timer] 这一节是新出现的,但它的作用不言自明:它包含了何时启动服务,启动哪个服务的信息。在这个例子当中,OnBootSec 是告诉 systemd 在系统启动后运行服务的指令。

其他的指令有:

  • OnActiveSec=,告诉 systemd 在定时器启动后多长时间运行服务。

  • OnStartupSec=,同样的,它告诉 systemd 在 systemd 进程启动后多长时间运行服务。

  • OnUnitActiveSec=,告诉 systemd 在上次由定时器激活的服务启动后多长时间运行服务。

  • OnUnitInactiveSec=,告诉 systemd 在上次由定时器激活的服务停用后多长时间运行服务。

继续 minetest.timer 单元,basic.target 通常用作后期引导服务late boot services同步点synchronization point。这就意味着它可以让 minetest.timer 单元运行在安装完本地挂载点local mount points或交换设备,套接字、定时器、路径单元和其他基本的初始化进程之后。就像在第二篇文章中 systemd 单元里解释的那样,targets 就像旧的运行等级old run levels一样,可以将你的计算机置于某个状态,或像这样告诉你的服务在达到某个状态后开始运行。

在前两篇文章中你配置的 minetest.service 文件最终看起来就像这样:

  1. # minetest.service

  2. [Unit]

  3. Description= Minetest server

  4. Documentation= https://wiki.minetest.net/Main_Page

  5.  

  6. [Service]

  7. Type= simple

  8. User=

  9.  

  10. ExecStart= /usr/games/minetest --server

  11. ExecStartPost= /home//bin/mtsendmail.sh "Ready to rumble?" "Minetest Starting up"

  12.  

  13. TimeoutStopSec= 180

  14. ExecStop= /home//bin/mtsendmail.sh "Off to bed. Nightie night!" "Minetest Stopping in 2 minutes"

  15. ExecStop= /bin/sleep 120

  16. ExecStop= /bin/kill -2 $MAINPID

  17.  

  18. [Install]

  19. WantedBy= multi-user.target

这儿没什么需要修改的。但是你需要将 mtsendmail.sh(发送你的 email 的脚本)从:

  1. #!/bin/bash

  2. # mtsendmail

  3. sleep 20

  4. echo $1 | mutt -F /home/<username>/.muttrc -s "$2" my_minetest@mailing_list.com

  5. sleep 10

改成:

  1. #!/bin/bash

  2. # mtsendmail.sh

  3. echo $1 | mutt -F /home/paul/.muttrc -s "$2" pbrown@mykolab.com

你做的事是去除掉 Bash 脚本中那些蹩脚的停顿。Systemd 现在来做等待。

让它运行起来

确保一切运作正常,禁用 minetest.service:

  1. sudo systemctl disable minetest

这使得系统启动时它不会一同启动;然后,相反地,启用 minetest.timer:

  1. sudo systemctl enable minetest.timer

现在你就可以重启服务器了,当运行 sudo journalctl -u minetest.* 后,你就会看到 minetest.timer 单元执行后大约一分钟,minetest.service 单元开始运行。

图 1:minetest.timer 运行大约 1 分钟后 minetest.service 开始运行

时间的问题

minetest.timer 在 systemd 的日志里显示的启动时间为 09:08:33 而 minetest.service 启动时间是 09:09:18,它们之间少于 1 分钟,关于这件事有几点需要说明一下:首先,请记住我们说过 OnBootSec= 指令是从引导完成后开始计算服务启动的时间。当 minetest.timer 的时间到来时,引导已经在几秒之前完成了。

另一件事情是 systemd 给自己设置了一个误差幅度margin of error(默认是 1 分钟)来运行东西。这有助于在多个资源密集型进程resource-intensive processes同时运行时分配负载:通过分配 1 分钟的时间,systemd 可以等待某些进程关闭。这也意味着 minetest.service 会在引导完成后的 1~2 分钟之间启动。但精确的时间谁也不知道。

顺便一提,你可以用 AccuracySec= 指令修改误差幅度。

你也可以检查系统上所有的定时器何时运行或是上次运行的时间:

  1. systemctl list-timers --all

图 2:检查定时器何时运行或上次运行的时间

最后一件值得思考的事就是你应该用怎样的格式去表示一段时间。Systemd 在这方面非常灵活:2 h,2 hours 或 2hr 都可以用来表示 2 个小时。对于“秒”,你可以用 seconds,second,sec 和 s。“分”也是同样的方式:minutes,minute,min 和 m。你可以检查 man systemd.time 来查看 systemd 能够理解的所有时间单元。

方法/步骤
1
检查你的Linux系统使是否使用Systemd服务
如果你的Linux发行版是否使用systemd还不能确定,打开一个终端窗口,运行以下命令。 这说明在Linux系统上你systemd的版本号:systemd -version

2
分析引导过程
该systemd-analyze命令允许你查看你的启动过程中,信息等过了多长时间,哪些服务(和其他进程)增加了最多的时间来启动进程。
要查看一般启动过程中的信息,运行以下命令:
systemd-analyze
要查看每个进程所用的时间来启动,运行以下命令:systemd-analyze blame

3
查看Units
Systemd用Units作为一个单元,它可以是服务(.service),挂载点(.mount),设备(.device), 同样systemctl命令管理所有这些类型的单位。要查看系统上所有可用的单元文件:systemctl list-unit-files
要列出所有正在运行的单位:systemctl list-units

4
管理服务
要查看启用和禁用服务的列表,您可以使用相同systemctl命令同上,但是它只列出存在的服务:systemctl list-unit-files –type=service

5
该systemctl命令可以启动,停止或重新启动服务。 你也可以告诉服务为“刷新”它的配置。
status命令是这里唯一的行动,将打印输出到终端。 其他命令会悄悄地生效。
systemctl start name.service
systemctl stop name.service

6
使用systemctl enable命令启动systemd自动启动服务
systemctl enable name.service
systemctl disable name.service