如何创建和管理 Systemd 定时器单元
通过实际的`.timer`、`.service`、`systemctl`和`journalctl`示例,创建、启用、监控和排查systemd定时器单元问题。
如何创建和管理Systemd定时器单元
Systemd定时器单元可以在Linux上安排任务,无需依赖cron。如果你需要服务器在预定时间运行备份、清理任务、健康检查或报告,systemd定时器集调度、服务隔离、依赖处理和日志记录于一体。
核心思想很简单:.timer文件定义何时运行,.service文件定义运行什么。这种分离使得定时器易于通过systemctl检查,也易于通过journalctl调试。
理解Systemd定时器单元结构
一个systemd定时器单元总是与一个对应的服务单元(或其他单元类型)配对,该服务单元是定时器要激活的。定时器单元本身定义了何时激活关联单元,而服务单元定义了执行什么操作。两个单元通常位于同一目录中,自定义单元通常放在/etc/systemd/system/。
典型的定时器单元文件扩展名为.timer,其关联的服务单元文件扩展名为.service。例如,如果要调度mytask.service中定义的任务,需要创建一个mytask.timer文件。
示例:mytask.timer
[Unit]
Description=每天运行我的自定义任务
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
我们来分解关键部分:
[Unit]部分:Description:定时器的人类可读描述。有助于在状态输出中识别。
[Timer]部分:这是定时器单元的核心,定义了调度。OnCalendar=daily:此指令指定定时器何时激活。daily是每天午夜的简写。其他示例包括:hourly:每小时。weekly:每周(相当于Mon *-*-* 00:00:00)。Sun *-*-* 10:00:每周日上午10点。*-*-15 14:30:每月15日下午2:30。Mon..Fri *-*-* 09:00:工作日上午9点。
Persistent=true:如果设置为true,当系统关闭期间错过了事件,定时器将尽快激活。对于OnCalendar定时器,这意味着如果系统在预定时间关闭,定时器将在系统启动并激活后立即触发。OnBootSec=:在系统启动后指定时间激活定时器。例如,OnBootSec=15min将在启动后15分钟触发。OnUnitActiveSec=:在它激活的单元上次激活后指定时间激活定时器。例如,OnUnitActiveSec=1h在关联服务上次激活后1小时安排另一次运行。OnUnitInactiveSec=:在它激活的单元上次变为非活动状态后指定时间激活定时器。AccuracySec=:指定定时器的精度。Systemd仅在事件处于此时间窗口内时尝试唤醒系统执行定时器,有助于节省电量。默认为1min。RandomizedDelaySec=:为定时器触发添加随机延迟,最多到指定时长。用于分散负载。
[Install]部分:此部分定义如何启用定时器单元。WantedBy=timers.target:此指令确保启用定时器时,它成为timers.target的一部分,这是一个包含所有活动定时器的标准目标。这意味着定时器启用后将在启动时自动启动。
示例:mytask.service
[Unit]
Description=我的自定义任务服务
[Service]
Type=oneshot
ExecStart=/usr/local/bin/my_custom_script.sh
User=myuser
Group=mygroup
[Install]
WantedBy=multi-user.target
[Unit]部分:Description:服务的描述。
[Service]部分:定义服务本身。Type=oneshot:适用于运行一次然后退出的任务。其他类型用于长时间运行的守护进程。ExecStart:要执行的命令。确保脚本具有执行权限。User/Group:指定命令运行的用户和组。除非绝对必要,否则不要以root身份运行任务。
[Install]部分:对于仅由定时器启动的oneshot服务,通常不需要此部分。启用定时器,而不是服务。
创建和启用定时器单元
按照以下步骤创建和管理systemd定时器单元:
创建服务单元文件:在
.service文件中定义任务。将其放在/etc/systemd/system/(或用户特定定时器的~/.config/systemd/user/)。sudo nano /etc/systemd/system/mytask.service粘贴上面的示例服务内容并保存。
创建定时器单元文件:在对应的
.timer文件中定义调度。将其放在与服务文件相同的目录中。sudo nano /etc/systemd/system/mytask.timer粘贴上面的示例定时器内容并保存。
重新加载Systemd守护进程:创建或修改单元文件后,需要通知systemd重新加载配置。
sudo systemctl daemon-reload启用定时器:要使定时器在启动时自动启动,请启用它。
sudo systemctl enable mytask.timer注意:如果服务文件仅由定时器触发,则不要启用它。
启动定时器:立即启动定时器。它将根据其调度运行。
sudo systemctl start mytask.timer
管理和监控定时器单元
Systemd提供了几个systemctl命令来管理和监控定时器:
列出所有定时器:查看所有活动和非活动定时器。
systemctl list-timers此命令输出如下:
NEXT LEFT LAST PASSED UNIT ACTIVATES Tue 2023-10-27 08:00:00 UTC 10h left Wed 2023-10-26 08:00:00 UTC 14h ago mytask.timer mytask.service显示定时器下次计划运行的时间、距离运行还有多久、上次运行时间以及激活的服务。
列出特定单元的定时器:如果要查看与特定服务相关的定时器。
systemctl list-timers --all | grep mytask.service检查定时器状态:获取特定定时器的详细信息。
systemctl status mytask.timer将显示定时器是否活动、下次计划运行时间以及最近的日志条目。
查看服务日志:要查看定时器执行任务的输出和状态,请检查关联服务的日志。
journalctl -u mytask.service也可以实时跟踪日志:
journalctl -f -u mytask.service停止定时器:如果需要临时禁用定时器。
sudo systemctl stop mytask.timer禁用定时器:防止定时器在启动时启动,如果正在运行则停止它。
sudo systemctl disable --now mytask.timer
高级定时器配置
设置特定间隔
除了daily或hourly,可以定义更精确的间隔:
- 每N分钟:
OnUnitActiveSec=15min(服务上次激活后15分钟运行)。 - 特定时间:
OnCalendar=*-*-* 02:30:00(每天凌晨2:30运行)。 - 组合条件:
OnCalendar=Mon..Fri *-*-* 08:00:00(工作日上午8点运行)。
使用AccuracySec节省电量
如果任务不需要在精确时刻运行,考虑使用AccuracySec。例如,AccuracySec=5min告诉systemd在预定时间的5分钟内唤醒系统即可。这允许systemd合并定时器事件,可能使系统更长时间处于低功耗状态。
[Timer]
OnCalendar=hourly
AccuracySec=5min
Persistent与WakeSystem
Persistent=true确保如果由于系统关闭而错过了OnCalendar事件,它将在下次启动时运行一次。这对于不能跳过的任务至关重要。WakeSystem=true要求systemd在系统和硬件支持的情况下,为定时器从挂起状态唤醒系统。这与机器是否使用交流电源或电池无关。
定时器与Cron对比
| 特性 | Systemd定时器 | Cron |
|---|---|---|
| 集成度 | 与systemd服务、目标深度集成 | 独立工具 |
| 调度 | 灵活(日历、相对、基于启动) | 主要基于时间的表达式 |
| 日志记录 | 通过journalctl集中管理 |
分散(/var/log/syslog、/var/log/cron.log) |
| 错误处理 | 可以将操作绑定到服务失败 | 基本邮件通知 |
| 依赖关系 | 可以依赖其他服务处于活动状态 | 有限 |
| 执行 | 可以以特定用户、组运行 | 可以通过crontab以特定用户运行 |
| 电源管理 | 可优化省电(AccuracySec) |
直接控制较少 |
何时选择Systemd定时器:
- 需要与其他systemd服务更紧密集成时。
- 集中日志记录和更易调试是优先事项时。
- 需要更高级的调度选项(例如,自上次运行以来的时间)。
- 与系统状态或电源管理相关的任务。
何时可能仍首选Cron:
- 对于非常简单的独立任务,且系统未完全采用systemd。
- 为了跨不同Linux发行版和旧系统的最大兼容性。
常见问题排查
- 任务未运行:
- 检查定时器状态:
systemctl status mytask.timer。查找Active: active和Triggered...消息。 - 检查服务日志:
journalctl -u mytask.service。确保脚本可执行且无错误。 - 验证
OnCalendar语法:使用systemd-analyze calendar 'your-calendar-string'测试。 - 确保定时器已启用并启动:
systemctl list-timers --all。
- 检查定时器状态:
- 任务运行过早/过晚:
- 检查
AccuracySec和RandomizedDelaySec。 - 确保系统时钟准确(
timedatectl status)。
- 检查
- 权限错误:
- 确认
.service文件中指定的User和Group对脚本及其访问的文件具有必要权限。 - 如果未指定用户,默认为root。谨慎使用root权限。
- 确认
总结
当任务属于机器的服务层时使用systemd定时器:备份、清理任务、监控检查、证书续订钩子和其他运维工作。先创建服务,再创建定时器,运行systemctl daemon-reload,启用并启动定时器,然后使用systemctl list-timers --all和journalctl -u your.service验证。