systemd 的 Restart=on-abnormal 不支持毫秒级拉起,实际延迟为100ms–2s;需用 Shell 守护进程(如循环健康检查 + exec)实现亚百毫秒响应,systemd 仅负责兜底与生命周期管理。

Systemd 的 Restart=on-abnormal 本身**不支持毫秒级拉起**,它受 systemd 自身调度机制、进程启动开销和依赖服务就绪时间限制,实际重启延迟通常在 100ms–2s 量级。所谓“毫秒级自动拉起”必须通过 Shell 守护进程(如循环检测 + 快速 exec)在应用层补足——systemd 负责兜底与生命周期管理,Shell 脚本负责低延迟响应。
理解 Restart=on-abnormal 的真实行为
该选项仅在进程因信号(如 SIGKILL、SIGSEGV)、非零退出码(非 0/EXIT_SUCCESS)、超时或被 OOM killer 终止时触发重启。它不会响应进程僵死、卡住、假活(如 hang 住但未退出)等场景。且 systemd 默认启用 RestartSec=100ms(最小可设为 10ms),但连续快速崩溃会触发退避策略(jitter + backoff),首次重启可能快,多次失败后会延至秒级。
Shell 守护进程实现亚百毫秒级响应
核心思路:用一个轻量、常驻的 shell 循环,持续检查目标进程状态(如端口连通性、PID 存活、健康接口返回),一旦异常立即 exec 替换自身启动新实例,避免 fork 开销。
示例守护脚本 /opt/bin/myapp-guard.sh:
#!/bin/bash APP_CMD="/opt/bin/myapp --config /etc/myapp/conf.yaml" HEALTH_CHECK="curl -sf http://127.0.0.1:8080/health | grep -q 'ok'" SLEEP_INTERVAL=0.05 # 50ms 检测间隔 <p>while true; do</p><h1>检查进程是否存活且健康</h1><p>if ! pgrep -f "$APP_CMD" >/dev/null || ! eval "$HEALTH_CHECK" 2>/dev/null; then</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/ai/991" title="绘蛙AI视频"><img src="https://img.php.cn/upload/ai_manual/001/503/042/68b6cf34a2e8c811.png" alt="绘蛙AI视频" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/ai/991" title="绘蛙AI视频" class="overflowclass">绘蛙AI视频</a> <p class="overflowclass">绘蛙AI视频是一款面向电商营销的图片转视频和模特动态视频生成工具。</p> </div> <a rel="nofollow" href="/ai/991" title="绘蛙AI视频" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div><h1>立即 exec 启动新实例(无 fork,零延迟重建)</h1><pre class="brush:php;toolbar:false;">exec $APP_CMD
fi sleep $SLEEP_INTERVAL done
关键点:
- 使用
exec而非$APP_CMD &,避免子进程残留和 PID 变更问题 - 健康检查必须具体(如 HTTP 接口、本地 socket 连通、文件锁存在),不能只靠
pgrep -
sleep 0.05在 bash 中实际精度受限于系统 timer resolution(通常 ≥10ms),但已远优于 systemd 默认 100ms 周期
Systemd Unit 文件协同设计
将守护脚本作为主进程交由 systemd 管理,利用其日志、资源限制、依赖注入能力:
[Unit] Description=MyApp with fast guard After=network.target <p>[Service] Type=simple ExecStart=/opt/bin/myapp-guard.sh Restart=on-abnormal RestartSec=10ms StartLimitIntervalSec=0</p><h1>关键:禁用 StartLimit 避免频繁崩溃被封禁</h1><p>KillMode=process</p><h1>防止守护脚本被误杀导致整个服务退出</h1><p>[Install] WantedBy=multi-user.target </p>
说明:
-
Type=simple:因守护脚本自身是常驻进程,无需 systemd 等待 ready 信号 -
StartLimitIntervalSec=0:关闭启动频率限制,确保崩溃后立即重试 -
KillMode=process:仅杀主进程(即 guard.sh),不波及被exec启动的 myapp 实例
线上部署注意事项
真实环境中需规避以下陷阱:
-
资源竞争:多个 guard 实例可能并发启动,用文件锁(
flock)或 systemd 的StartLimitBurst控制并发数 - 健康检查误判:避免检查路径过于敏感(如 /metrics 每秒刷屏),应选稳定、低开销 endpoint(如 /health)
-
日志爆炸:guard 脚本高频输出会撑爆 journal,建议仅在异常时
echo "restarting..." >&2,正常检测静默 - 冷启动延迟:若应用本身加载慢(如 JVM 初始化),毫秒级拉起无意义,需配合预热或 jvm -XX:TieredStopAtLevel=1 降级编译










