一、为什么需要定时任务

运维工作中大量工作带有"周期性":日志切割、数据备份、缓存清理、监控巡检、证书续期检查。靠人工每天重复执行既不现实也不可靠,定时任务就是把这类工作自动化托管给系统的核心手段。Linux 下主流方案有两个:Crontab(传统、普及、简单)和 Systemd Timer(现代、可控、适合服务化场景),本文从入门到生产实践逐一讲透。

二、Crontab 基础:语法与常用写法

# 编辑当前用户的定时任务
crontab -e

# 查看当前用户的定时任务
crontab -l

# 删除所有定时任务
crontab -r

Crontab 每行由"时间表达式 + 命令"组成,时间表达式共 5 个字段:

分 时 日 月 周    命令
*  *  *  *  *    /usr/local/bin/backup.sh

常用示例:

# 每天凌晨 2:30 执行备份
30 2 * * * /opt/scripts/backup.sh

# 每 10 分钟执行一次健康检查
*/10 * * * * /opt/scripts/healthcheck.sh

# 每天 8-18 点之间每隔 2 小时执行
0 8-18/2 * * * /opt/scripts/sync.sh

# 每周一至周五早上 9 点执行
0 9 * * 1-5 /opt/scripts/report.sh

# 每月 1 号和 15 号凌晨执行
0 0 1,15 * * /opt/scripts/cleanup.sh

注意:crontab -e 编辑的是当前用户的表;系统级任务放在 /etc/crontab(多一个"用户"字段)或 /etc/cron.d/ 目录下,root 权限即可管理全局任务。

三、Crontab 进阶:环境变量、日志与常见坑

1. 环境变量问题(最高频的坑):cron 执行时的 PATH 极其精简,很多命令找不到。脚本内务必使用绝对路径,或脚本开头显式声明环境:

#!/bin/bash
# 脚本内推荐写法
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export LANG=en_US.UTF-8

2. 输出与日志:默认 cron 把输出用邮件发给用户(多数服务器没配邮件,输出就丢了),建议手动重定向:

30 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1

3. 脚本要有锁,防止上次没跑完下次又启动

#!/bin/bash
LOCKFILE=/tmp/backup.lock
if [ -f "$LOCKFILE" ]; then
    echo "已有备份任务在运行,退出"
    exit 1
fi
touch "$LOCKFILE"
trap 'rm -f "$LOCKFILE"' EXIT
# 业务逻辑...
sleep 600

4. 注意系统时区:cron 按系统时区执行,服务器时区不一致会导致任务时间错乱,务必统一 timedatectl set-timezone Asia/Shanghai

四、Systemd Timer:更现代的替代方案

Systemd Timer 由两个单元组成:service 单元(定义要执行的任务)和 timer 单元(定义触发时间)。优点:支持精确到秒、支持随机延迟避免风暴、支持依赖与资源限制、日志统一走 journald。

# /etc/systemd/system/backup.service
[Unit]
Description=Daily Backup

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=60
Persistent=true

[Install]
WantedBy=timers.target
# 启用并查看
systemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers

几个关键指令:Persistent=true 表示错过的任务在开机后补跑;RandomizedDelaySec 随机延迟防止多机同时执行造成负载尖峰;OnCalendar 支持 Mon..Fri 09:00*/15min 等人类可读写法,比 cron 表达式直观得多。

五、Crontab vs Systemd Timer 如何选择

选 Crontab:任务简单、追求兼容性(老系统/容器内无 systemd)、只想要一行表达式。

选 Systemd Timer:需要精确控制(秒级、随机延迟、错过后补跑)、希望日志统一进 journald、任务较多需要独立管理,或者任务依赖某个服务启动状态。生产环境建议:系统级维护任务尽量迁移到 Systemd Timer,业务脚本按团队习惯保持 Crontab 亦可,但务必统一规范。

六、生产环境最佳实践清单

1. 所有脚本路径、命令用绝对路径,避免环境变量坑
2. 输出必须落日志文件,并配置 logrotate 防止日志撑爆磁盘
3. 耗时任务加锁防重入
4. 关键任务(备份、同步)执行后做结果校验并告警,例如失败时发送通知
5. 定时任务变更走版本管理(脚本入库),禁止在服务器上直接裸改
6. 定期用 crontab -l 和 systemctl list-timers 审计服务器上的全部定时任务
7. 服务器时区统一,避免因时区导致任务时间漂移

定时任务是运维自动化的基石,把"人肉执行"变成"系统托管",再配合监控告警,就能把重复劳动彻底释放掉。掌握 Crontab 与 Systemd Timer,是每个运维工程师的基本功。