Linux 上的任務排程:cron 與 systemd timer 比較

在 Linux 系統管理中,"何時" 執行任務與"執行什麼" 同樣重要。 最古老的工具是 cron,而在許多現代發行版中則廣泛使用 systemd timer。 本文將比較兩者,並整理在不同情境下應選擇哪一種。


1. 為什麼要比較 cron 與 systemd timer?



大多數 Linux 伺服器都會遇到以下需求。

  • 每天凌晨 3 點執行備份
  • 每 5 分鐘執行健康檢查腳本
  • 每週日壓縮並整理日誌
  • 開機後 1 分鐘執行一次初始化工作

傳統上,所有這些都用 cron 處理,但隨著許多發行版將 systemd 作為預設 init 系統,"timer unit (systemd timer)" 也成為強大的替代方案。


2. cron 基本概念

2.1 cron 是什麼?

cron 是一個古老的 Unix/Linux 排程器。 它根據設定的時間/週期執行命令,設定主要透過 crontab 檔案管理。

2.2 cron 設定位置

  • 系統全域:/etc/crontab/etc/cron.d/
  • 使用者:crontab -e 編輯 per-user crontab

例如,設定每天凌晨 3 點執行備份腳本:

0 3 * * * /usr/local/bin/backup.sh

欄位意義如下。

分  時  日  月  週  命令
0   3   *   *   *    /usr/local/bin/backup.sh

2.3 cron 的優點

  • 可靠且經過驗證的工具
  • 大多數 Unix/Linux 系統共通概念
  • 設定語法簡單,範例豐富
  • 在 systemd 之前的系統也可使用

2.4 cron 的限制

  • 與服務分離,難以追蹤「與哪個服務相關」
  • 狀態/日誌確認不方便(散落於 syslog、郵件等)
  • 依賴性管理(如需先啟動其他服務)較弱
  • 相對時間排程(如「開機後 5 分鐘執行一次」)不直觀

3. systemd timer 基本概念



3.1 systemd timer 是什麼?

systemd timer 是 systemd 的「timer unit」。 它根據特定條件(時間、開機後經過時間等)啟動另一個 systemd service

結構總是成對出現。

  • myjob.service → 真正執行的工作
  • myjob.timer → 何時執行

3.2 service + timer 基本範例

以每天凌晨 3 點執行備份為例,使用 systemd timer 如下。

(1) 服務單元:/etc/systemd/system/backup.service

[Unit]
Description=Daily backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

(2) 時間單元:/etc/systemd/system/backup.timer

[Unit]
Description=Run daily backup at 3:00

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

啟用:

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

3.3 systemd timer 的優點

  • 明確與服務關聯:結構清晰,易於辨識
  • 日誌管理簡單journalctl -u backup.service 等查看
  • 靈活的觸發條件
  • OnCalendar=:類似 cron 的時間表達
  • OnBootSec=:開機後 X 秒
  • OnUnitActiveSec=OnUnitInactiveSec= 等:最後一次執行後的時間
  • 依賴性處理:可在 service 的 After=Requires= 等設定
  • 與 systemd 生態整合:systemctl list-timerssystemctl status

3.4 systemd timer 的缺點

  • 相較於 cron 學習曲線較陡(需兩個檔案)
  • 依賴 systemd(舊系統或非 systemd 環境不支援)
  • 對於簡單的一行任務可能顯得「過度」

4. cron vs systemd timer:功能比較

4.1 大圖比較表

項目 cron systemd timer
設定位置 /etc/crontabcrontab -e /etc/systemd/system/*.service/*.timer
執行對象 任意命令/腳本 systemd service
時間表達 cron 表達式(5 欄) OnCalendarOnBootSec 等多種選項
開機後 X 秒/分/時 限制,需額外腳本 OnBootSecOnStartupSec 直接支援
失敗/重試管理 需自行實作 透過 service unit 設定部分可行
日誌確認 syslog、郵件等 journalctl -u <service>
依賴性(網路/檔系統) After=Requires= 等單元選項
與系統整合 高(systemd 全域)
可攜性(跨 OS) 受 systemd 依賴

5. 以範例看差異

5.1 每天凌晨 3 點備份:cron vs timer

cron 版本

0 3 * * * /usr/local/bin/backup.sh

systemd timer 版本

# backup.service
[Unit]
Description=Daily backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# backup.timer
[Unit]
Description=Run daily backup at 3:00

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

5.2 開機後 5 分鐘執行一次

cron 中通常需要 @reboot + sleeprc.local 等技巧。

systemd timer 實作

# init-job.service
[Unit]
Description=Run custom init job after boot

[Service]
Type=oneshot
ExecStart=/usr/local/bin/init-job.sh
# init-job.timer
[Unit]
Description=Run init job 5 minutes after boot

[Timer]
OnBootSec=5min
AccuracySec=1min

[Install]
WantedBy=timers.target

這樣,開機後 5 分鐘會執行一次 init-job.service


6. 如何選擇?

6.1 仍使用 cron 的情況

  • 已有大量 cron 任務且不需要 systemd 整合
  • 需要在非 systemd 環境(容器、BSD、舊版 OS)執行
  • 只有少量簡單排程

6.2 選擇 systemd timer 的情況

  • 系統已使用 systemd 管理大部分服務
  • 想在單一地方查看日誌與狀態
  • 需要相對時間排程(開機後 X 時間、最後一次執行後 Y 時間)
  • 需要依賴性(如網路、資料庫)控制
  • 在 CI/CD、製造環境中需要一致的可觀測性

7. 將現有 cron 任務遷移到 systemd timer 的技巧

  1. 列出現有 cron 任務 * crontab -l * 檢查 /etc/crontab/etc/cron.d/*
  2. 拆分為「服務 + 時間」 * 「執行什麼」 → .service * 「何時執行」 → .timer
  3. 轉換時間表達式 * 0 3 * * *OnCalendar=*-*-* 03:00:00 * */5 * * * *OnCalendar=*:0/5
  4. 測試 * systemctl start myjob.service 先手動執行 * systemctl start myjob.timersystemctl list-timers
  5. 停用舊 cron * 新 timer 穩定後,將原 cron 設定註解或刪除

8. 總結:共存亦可

總結來說:

  • cron 仍是簡單且可攜的排程器
  • systemd timer 在現代 Linux 環境中提供服務導向、可觀測、靈活觸發的強大功能

兩者並非互斥;已存在的 cron 任務不必全部遷移,僅在需要更高整合度或依賴性控制時考慮使用 systemd timer。

image