Cron 是 Linux 系統核心的定時任務調度服務,廣泛用於數據庫維護、報表生成、郵件發送、緩存清理等自動化運維場景。本文系統講解 Crontab 配置語法、PHP 腳本調用要點、常見陷阱規避及生產環境最佳實踐。
crond,每分鐘檢查一次任務隊列crontab -e:編輯當前用戶任務(自動語法檢查)crontab -l:列出當前任務crontab -r:刪除所有任務(慎用)crontab -u user -e:以 root 權限編輯指定用戶任務* * * * * 執行命令
- - - - -
| | | └─ 星期幾 (0-7) (0 或 7 代表星期日)
| | └──── 月份 (1-12)
| └────── 日期 (1-31)
└──────── 小時 (0-23)
└──────── 分鐘 (0-59)
| 符號 | 含義 | 示例 | 說明 |
|---|---|---|---|
* | 任意值 | * * * * * | 每分鐘執行 |
, | 枚舉值 | 0,15,30,45 * * * * | 每小時的 0/15/30/45 分 |
- | 範圍值 | 0 9-18 * * 1-5 | 工作日 9-18 點整點 |
/ | 步長/間隔 | */10 * * * * | 每 10 分鐘 |
組合 | 混合使用 | 0-30/5 9 * * * | 9 點前 30 分每 5 分 |
# 使用 PHP 絕對路徑(關鍵!)
0 2 * * * /usr/bin/php -f /var/www/html/scripts/daily_report.php >> /var/log/cron/daily_report.log 2>&1
# 或使用 shebang 的腳本文件
0 2 * * * /var/www/html/scripts/daily_report.php >> /var/log/cron/daily_report.log 2>&1
# 錯誤 1:直接用 php 命令(cron 環境無 PATH)
0 2 * * * php -f /var/www/html/scripts/daily_report.php
# 錯誤 2:忽略輸出導致郵件堆積
0 2 * * * /usr/bin/php -f /var/www/html/scripts/daily_report.php
# 錯誤 3:相對路徑
0 2 * * * /usr/bin/php -f scripts/daily_report.php
<?php
// daily_report.php
// 1. 設置運行環境
define('APP_ROOT', dirname(__DIR__));
require_once APP_ROOT . '/bootstrap.php'; // 載入框架/配置
// 2. 防止重複執行(鎖機制)
$lockFile = sys_get_temp_dir() . '/daily_report.lock';
$fp = fopen($lockFile, 'w');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
error_log("[".date('c')."] 上一實例尚在運行,退出\n", 3, '/var/log/cron/daily_report.log');
exit(1);
}
// 3. 設置執行時間限制
set_time_limit(3600); // 1 小時
// 4. 異常捕獲與日誌
try {
// 業務邏輯
$report = new DailyReportService();
$result = $report->generate();
// 成功日誌
error_log("[".date('c')."] 執行成功: {$result}\n", 3, '/var/log/cron/daily_report.log');
} catch (Throwable $e) {
// 失敗日誌 + 告警
$msg = "[".date('c')."] 執行失敗: {$e->getMessage()}\n{$e->getTraceAsString()}\n";
error_log($msg, 3, '/var/log/cron/daily_report_error.log');
// 發送告警...
exit(1);
} finally {
flock($fp, LOCK_UN);
fclose($fp);
}
# 創建無登錄權限用戶
useradd -r -s /sbin/nologin -d /var/www/html -c "Cron PHP Runner" cronphp
# 編輯該用戶 crontab
crontab -u cronphp -e
mkdir -p /var/log/cron
chown cronphp:cronphp /var/log/cron
chmod 750 /var/log/cron
在 crontab 文件頭部聲明:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
# PHP 相關
PHP_INI_SCAN_DIR=/etc/php.d
# 應用相關
APP_ENV=production
DB_HOST=127.0.0.1
cronitor、healthchecks.io 或自建心跳檢測| 現象 | 原因 | 解決 |
|---|---|---|
| 任務不執行 | crond 未啟動/語法錯誤/權限不足 | systemctl status crond、crontab -l 驗證、檢查 /var/log/cron |
| PHP 提示擴展缺失 | CLI 與 FPM 使用不同 php.ini | php -i | grep php.ini 確認 CLI 配置,安裝缺失擴展 |
| 數據庫連接失敗 | 環境變量/配置文件路徑錯誤 | 腳本中使用絕對路徑載入配置 |
| 長時間運行被殺 | 系統 OOM Killer / systemd 限制 | 優化內存使用、調整 MemoryLimit、拆分任務 |
| 並發執行導致數據錯亂 | 無鎖機制 | 文件鎖/Redis 分布式鎖/數據庫樂觀鎖 |
系統級任務需指定執行用戶:
# /etc/cron.d/php-tasks (推薦:單獨文件便於管理)
# 格式:分 時 日 月 星期 用戶 命令
0 3 * * * cronphp /usr/bin/php -f /var/www/html/scripts/cleanup.php >> /var/log/cron/cleanup.log 2>&1
30 4 * * 0 cronphp /usr/bin/php -f /var/www/html/scripts/weekly_report.php >> /var/log/cron/weekly.log 2>&1
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| Crontab | 簡單、系統內置、無依賴 | 最小粒度 1 分鐘、無 Web 界面、無分布式協調 | 單機簡單任務 |
| systemd Timer | 精度秒級、依賴管理、日誌整合 | 配置相對複雜 | 現代 Linux 系統級任務 |
| Laravel Scheduler | 代碼定義任務、避免重疊、任務鏈、Web 監控 | 需框架支持、進程常駐 | Laravel 專案 |
| Celery Beat / XXL-Job | 分布式、可視化、重試、分片、多語言 | 架構複雜、維護成本高 | 微服務/大規模分布式 |
掌握 Crontab 核心在於「絕對路徑、環境隔離、輸出重定向、鎖防重、日誌可查」。建議將所有定時任務納入版本控制(/etc/cron.d/ 文件或 Ansible 管理),實現基礎設施即代碼。