定时任务与巡检脚本
脚本只有被稳定执行,才真的算自动化。
自动化结构
graph LR
A[cron / systemd.timer] --> B[巡检/备份脚本]
B --> C[日志落地]
C --> D{执行成功?}
D -->|否| E[告警通知]
D -->|是| F[记录成功时间]
cron 常用任务调度
# 编辑当前用户的 crontab
crontab -e
# 格式:分 时 日 月 周 命令
# ┌───────────── 分钟 (0-59)
# │ ┌─────────── 小时 (0-23)
# │ │ ┌───────── 日 (1-31)
# │ │ │ ┌─────── 月 (1-12)
# │ │ │ │ ┌───── 星期 (0-7, 0和7都是周日)
# │ │ │ │ │
# * * * * * 命令
# 实际任务示例
0 2 * * * /opt/scripts/backup_db.sh >> /var/log/backup.log 2>&1 # 每日 2:00 备份
*/5 * * * * /opt/scripts/check_disk.sh >> /var/log/disk_check.log 2>&1 # 每 5 分钟磁盘检查
0 3 * * 0 /opt/scripts/cleanup_logs.sh # 每周日 3:00 清理日志
0 1 1 * * /opt/scripts/monthly_report.sh # 每月 1 日 1:00 月报
巡检任务频率建议:
| 任务 | 频率 | 原因 |
|---|---|---|
| 磁盘空间检查 | 每 5–15 分钟 | 磁盘满会导致服务立即崩溃 |
| 健康检查 | 每 1–5 分钟 | 及早发现进程崩溃 |
| 数据库备份 | 每日 | RPO 通常是 24 小时 |
| 日志清理 | 每日或每周 | 防止磁盘被日志撑满 |
| SSL 证书检查 | 每日 | 提前 30 天告警,避免证书过期 |
实用巡检脚本示例
#!/usr/bin/env bash
# check_health.sh — 应用健康巡检(适合放入 cron 每 5 分钟)
set -euo pipefail
HEALTH_URL=http://127.0.0.1:3000/health
DISK_WARN_PCT=80
ALERT_WEBHOOK="${ALERT_WEBHOOK:-}" # Slack/飞书 Webhook(可选)
LOG=/var/log/myapp/health_check.log
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; }
alert() {
log "[ALERT] $*"
[[ -n "$ALERT_WEBHOOK" ]] && \
curl -sf -X POST -H 'Content-type: application/json' \
-d "{\"text\":\"[ALERT] $*\"}" "$ALERT_WEBHOOK" || true
}
# 1. 应用健康检查
if ! curl -sf --max-time 5 "$HEALTH_URL" > /dev/null; then
alert "应用健康检查失败: $HEALTH_URL"
else
log "应用健康检查 OK"
fi
# 2. 磁盘空间检查
DISK_PCT=$(df / --output=pcent | tail -1 | tr -d ' %')
if (( DISK_PCT >= DISK_WARN_PCT )); then
alert "磁盘使用率 ${DISK_PCT}%,超过阈值 ${DISK_WARN_PCT}%"
else
log "磁盘使用率 ${DISK_PCT}% OK"
fi
# 3. 关键进程检查
if ! systemctl is-active --quiet myapp; then
alert "myapp 服务未运行"
fi
cron vs systemd.timer 对比
| 特性 | cron | systemd.timer |
|---|---|---|
| 配置位置 | crontab -e / /etc/cron.d/ | /etc/systemd/system/*.timer |
| 错过执行(机器宕机期间) | 丢失,不补跑 | Persistent=true 开机后补跑 |
| 日志 | 重定向到文件(自行管理) | journalctl -u myservice |
| 依赖管理 | 无 | 支持 After=, Requires= |
| 随机延迟(防止雷同) | 不支持 | RandomizedDelaySec= |
| 现代推荐程度 | 传统,仍广泛使用 | 推荐(Ubuntu 16.04+) |
systemd.timer 示例(备份任务):
# /etc/systemd/system/backup.service
[Unit]
Description=Database Backup
[Service]
Type=oneshot
User=root
ExecStart=/opt/scripts/backup_db.sh
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 02:00
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true # 机器宕机后开机补跑
RandomizedDelaySec=5min # 随机延迟 0–5 分钟,防止多台机器同时备份
[Install]
WantedBy=timers.target
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer # 查看下次执行时间
journalctl -u backup.service -n 20 # 查看上次执行日志
常见误区
| 误区 | 正确做法 |
|---|---|
cron 任务没有 2>&1 重定向 | stderr 默认通过 sendmail 发送,没有 sendmail 则静默丢失 |
| cron 脚本使用相对路径 | cron 环境没有 PATH,必须用绝对路径(/usr/bin/python3 而非 python3) |
| 任务失败了没人知道 | 加告警通知(Webhook)或检查 cron 日志(/var/log/cron) |
systemd.timer 不加 Persistent=true | 机器维护期间的备份窗口将被永久跳过 |
本节执行清单
- [ ] 把至少一个脚本(备份或巡检)加入 cron 定时执行
- [ ] 确认定时任务日志落地(
>> /var/log/xxx.log 2>&1) - [ ] 验证 cron 脚本中所有路径均为绝对路径
- [ ] 考虑用 systemd.timer 替换关键任务(支持 Persistent 补跑)
下一节:幂等性、重试与日志规范——自动化脚本也需要工程质量。