用 systemd 定时器给 Linux 服务做健康检查与日志轮转
很多小服务出问题时,并不是程序本身写错了,而是没有人及时发现,也没有可查的运行记录。把健康检查和日志轮转交给 systemd 定时器,可以让这两件事变得可观测、可重试、可回溯。
为什么优先用 systemd 定时器
第一,输出默认进入 journal,可以用 journalctl 按服务和时间过滤,不用自己再拼日志路径。第二,定时器支持错过补跑、随机延迟和依赖关系,比散落在各处的定时脚本更容易统一管理。第三,失败状态本身就是信号,配合服务单元可以看到最近一次是成功还是失败。
第一步:写一个只做一件事的健康检查脚本
脚本的职责要尽量单一:检查端口或健康接口,失败时尝试重启一次,并把结果写到系统日志。
#!/bin/bash
set -e
if curl -fsS --max-time 5 http://127.0.0.1:8080/health >/dev/null; then
logger -t app-health "health check ok"
exit 0
fi
logger -t app-health "health check failed, restarting app"
systemctl restart app.service
保存为 /usr/local/bin/app-health.sh,并执行 chmod +x。注意不要在脚本里写复杂的重试循环,否则一次卡住可能拖垮整个检查周期。
第二步:配一对 service 与 timer
服务单元只负责执行一次检查:
[Unit]
Description=App health check
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/app-health.sh
定时器单元负责触发节奏:
[Unit]
Description=Run app health check every 5 minutes
[Timer]
OnCalendar=*:0/5
Persistent=true
RandomizedDelaySec=30
Unit=app-health.service
[Install]
WantedBy=timers.target
把这两个文件分别保存为 /etc/systemd/system/app-health.service 和 app-health.timer,然后执行:
systemctl daemon-reload
systemctl enable --now app-health.timer
systemctl list-timers --all | grep app-health
Persistent=true 的意义是机器关机或休眠错过触发点后,下次启动会补跑一次,适合不需要严格准点的巡检任务。
第三步:把日志轮转也讲清楚
如果服务已经输出到 journal,优先控制 journal 的总量,例如在 /etc/systemd/journald.conf 中设置 SystemMaxUse=500M,并执行 systemctl restart systemd-journald。不要等磁盘满了才发现日志把空间吃光。
如果服务仍写普通日志文件,可以用 logrotate 做轮转:
/var/log/app/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}
copytruncate 使用方便,但截断瞬间可能丢少量日志。对日志完整性要求高的场景,更稳妥的做法是让应用支持重新打开日志文件,或者直接改用 journal。
排障时先看这三条命令
systemctl list-timers --all
systemctl status app-health.timer app-health.service
journalctl -u app-health.service --since today
如果时间表达式不确定,先用 systemd-analyze calendar “*:0/5” 验证解析结果,再上线。
适用边界
定时器适合短而确定的巡检任务,不适合长时间运行、需要复杂编排的作业。对超时、并发和失败通知要有明确预期:给 service 设置合理的 TimeoutStartSec,失败时先看日志再决定是否自动重启,避免把一次偶发故障放大成反复重启。
总结起来就是:检查要轻、记录要全、轮转要有上限、失败要能被看见。把这四点做扎实,小服务的半夜告警会少很多。
- 点赞
- 收藏
- 关注作者
评论(0)