在 Linux 运维与后端开发面试中,定时任务调度是一个高频考点。很多候选人能熟练写出 crontab -e 的语法,但当面试官追问“systemd timer 和 crontab 有什么区别”“at 适合什么场景”时,往往答得不够系统。本文从面试回答的角度,把这三者的调度模型、适用场景和关键差异一次讲清楚。
一、先建立整体认知:三种调度器分别解决什么问题
Linux 中常见的定时任务方案主要有三类:
- crontab:传统 Unix 定时任务,适合“周期性、固定间隔”的任务。
- systemd timer:现代 systemd 体系下的定时单元,适合与系统服务深度集成、需要精细控制的场景。
- at:一次性定时任务,适合“未来某个时间点执行一次”的需求。
面试时可以先给出这句话作为总纲:crontab 管周期,systemd timer 管集成,at 管一次性。 然后分别展开。
二、crontab:最经典的周期调度
1. 调度模型
crontab 由 crond 守护进程驱动,按分钟粒度检查 /var/spool/cron/ 和 /etc/cron.d/ 等位置的配置。每条任务由五个时间字段加命令组成:
# 分 时 日 月 周 命令
30 2 * * * /usr/local/bin/backup.sh
它表达的是“在每个满足条件的时刻执行”,而不是“每隔多久执行一次”。这一点在面试中经常被用来区分候选人是否真正理解 cron。
2. 关键特点
- 最小粒度是分钟,不支持秒级调度。
- 环境变量极简,默认 PATH 很短,很多“手动能跑、cron 跑不了”的问题都源于此。
- 无依赖管理,不会等待网络、数据库等前置条件。
- 无内置日志,通常需要自己重定向输出或依赖系统邮件。
- 错过不补,如果机器在预定时间关机,任务不会在开机后自动补跑。
3. 适用场景
日志切割、定期备份、证书续期、缓存清理等标准周期任务。
三、systemd timer:更现代、更可控的调度方式
1. 调度模型
systemd timer 由一对单元组成:.timer 定义何时触发,.service 定义触发后做什么。例如:
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
启用后通过 systemctl enable --now backup.timer 生效,用 systemctl list-timers 查看下次触发时间。
2. 与 crontab 的核心差异
- 支持秒级和更丰富的时间表达式,如
OnCalendar=Mon..Fri *-*-* 09:00。 - Persistent=true 可补跑:如果系统在触发时间处于关机状态,开机后会立即执行一次。
- 依赖管理:可以通过
After=、Requires=控制服务启动顺序,确保网络就绪后再执行。 - 日志统一:输出进入 journald,用
journalctl -u backup.service直接查看。 - 资源控制:可结合 cgroup 限制 CPU、内存,适合重任务。
- 随机延迟:
RandomizedDelaySec=可避免多台机器同时触发造成雪崩。
3. 适用场景
需要与系统服务协同、需要可靠补跑、需要统一日志和资源隔离的现代生产环境。
四、at:一次性定时任务
1. 调度模型
at 由 atd 守护进程管理,用于在指定时间执行一次命令:
echo "/usr/local/bin/report.sh" | at 23:00
at -f script.sh 10:00 tomorrow
at now + 2 hours
用 atq 查看队列,atrm 删除任务。
2. 关键特点
- 只执行一次,执行后自动从队列移除。
- 支持自然语言时间,如
now + 1 hour、teatime tomorrow。 - 默认继承当前 shell 环境,比 cron 更接近交互式环境。
- 依赖 atd 服务,部分精简系统默认未安装。
- 不适合周期任务,虽然可以用脚本自我重新投递,但这不是它的设计目的。
3. 适用场景
延迟重启服务、临时提醒、一次性数据迁移、面试中常举的“下班前发一封邮件”等。
五、面试高频对比表
| 维度 | crontab | systemd timer | at |
|---|---|---|---|
| 调度类型 | 周期 | 周期/复杂日历 | 一次性 |
| 最小粒度 | 分钟 | 秒 | 分钟 |
| 错过补跑 | 不支持 | 支持(Persistent) | 不适用 |
| 依赖管理 | 无 | 有 | 无 |
| 日志 | 需自行处理 | journald | 邮件/自定义 |
| 资源控制 | 无 | cgroup | 无 |
| 环境继承 | 极简 | 可配置 | 较完整 |
六、面试回答示范
如果面试官问“你会怎么选择”,可以这样回答:
如果是标准的分钟级周期任务,比如每天凌晨备份,我会优先用 crontab,简单直接。如果任务需要可靠补跑、依赖网络或数据库、需要统一日志和资源限制,我会用 systemd timer。如果只是未来某个时间点执行一次,比如今晚重启某服务,我会用 at。实际生产中,新系统我倾向于 systemd timer,因为它把调度和服务管理统一在了一个体系里。
七、容易踩坑的追问点
- cron 的“每 5 分钟”怎么写?
*/5 * * * *,注意它不是“从上次执行后隔 5 分钟”,而是“分钟数能被 5 整除的时刻”。 - systemd timer 的 OnCalendar 和 OnUnitActiveSec 区别? 前者是日历时间,后者是相对于上次激活的间隔。
- at 任务为什么没执行? 检查 atd 是否运行、用户是否在
/etc/at.allow中、输出是否被邮件吞掉。 - cron 任务为什么手动能跑、自动不行? 九成是 PATH 或环境变量问题,建议在脚本里显式设置环境。
结语
crontab、systemd timer 和 at 并不是互相替代的关系,而是覆盖了不同的调度需求。面试中能说清“周期 vs 一次性”“简单 vs 集成”“是否补跑”这几条主线,基本就能给出一个有深度的回答。真正拉开差距的,不是记住语法,而是理解每种工具背后的调度模型和适用边界。
未经允许不得转载:任鹏个人博客 » Linux 定时任务三剑客:crontab、systemd timer 与 at 的调度差异详解

