首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 定時任務實現思路全景指南:從虛擬主機到 Kubernetes 的演進之路

     編輯:PHP 相關知識

核心矛盾:PHP 無原生定時能力,需外部調度器介入

PHP 是「請求-響應」模型,無事件循環、無線程、無信號處理。實現定時任務的本質是:由外部調度器在特定時間觸發 PHP CLI 執行腳本。根據環境約束(權限、架構、併發),方案演進路徑清晰。

第一層級:擁有服務器控制權(VPS/雲服務器/物理機)

方案 A:系統 Cron + PHP CLI(黃金標準)

# 1. 編輯 crontab
crontab -e

# 2. 添加任務(建議使用 flock 防重複)
* * * * * flock -xn /tmp/lock.scheduler -c '/usr/bin/php /var/www/artisan schedule:run >> /dev/null 2>&1'

# 3. 直接腳本調度
0 2 * * * flock -xn /tmp/lock.daily -c '/usr/bin/php /var/www/scripts/daily_report.php --env=prod >> /var/log/daily.log 2>&1'

關鍵優勢

  • 系統級可靠性,開機自啟,無內存洩漏風險。
  • 標準日誌輪轉(logrotate)、標準監控(Prometheus node_exporter + 文本檔案收集器)。
  • 支援並行任務、隨機延遲(sleep $((RANDOM\%60)))避免驚群。

進階:分布式鎖防止多機重複執行

# 利用 Redis SETNX 實現分布式鎖(需 Redis 可用)
* * * * * /usr/bin/php /var/www/scripts/distributed_task.php --lock-key=sync_orders --lock-ttl=300
// distributed_task.php 核心邏輯
$redis = new Redis(); $redis->connect('127.0.0.1', 6379);
$lockKey = "cron_lock:{$argv[1]}"; $ttl = $argv[2] ?? 300;
$lockVal = gethostname() . '_' . getmypid() . '_' . uniqid();

if (!$redis->set($lockKey, $lockVal, ['NX', 'EX' => $ttl])) {
    exit("鎖佔用中,退出\n");
}
register_shutdown_function(function() use ($redis, $lockKey, $lockVal) {
    $lua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    $redis->eval($lua, 1, $lockKey, $lockVal);
});

// 核心業務邏輯
echo "獲得鎖,執行任務...\n";

第二層級:Windows 服務器環境

方案:任務計劃程式 + 批處理腳本

:: cron.bat
@echo off
D:\php\php.exe -q D:\www\scripts\task.php >> D:\logs\task.log 2>&1
  1. 控制面板 → 系統和安全 → 管理工具 → 任務計劃程式。
  2. 創建基本任務 → 觸發器(每日/每週/每月/自定義)。
  3. 操作 → 啟動程式:cmd.exe,參數:/c D:\scripts\cron.bat。
  4. 條件/設置:勾選「如果任務已在運行,則不啟動新實例」。

第三層級:虛擬主機/共享主機(無 Shell、無 Cron 權限)

方案 A:偽 Cron - 借用用戶訪問觸發(WordPress WP-Cron 模式)

// 原理:每次請求檢查是否有到期任務,有則異步執行
// 缺點:流量低時任務延遲;高流量時並發衝突;無法精確控制時間

// 改進:異步觸發(fsockopen/curl 非阻塞)
function triggerCronAsync(string $url): void {
    $parsed = parse_url($url);
    $host = $parsed['host'];
    $path = $parsed['path'] . ($parsed['query'] ? '?' . $parsed['query'] : '');
    $fp = fsockopen($host, 80, $errno, $errstr, 1); // 1 秒超時
    if ($fp) {
        $req = "GET $path HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";
        fwrite($fp, $req);
        fclose($fp); // 立即關閉,不等待響應
    }
}

// 業務代碼中
if (shouldRunCron()) {
    triggerCronAsync('https://mysite.com/cron_endpoint.php');
}

方案 B:第三方定時服務跳板(推薦)

服務免費額度特點
cron-job.org無限任務,最小 1 分鐘Web 界面、日誌、郵件通知、支援 HTTP Basic Auth
EasyCron1 個任務/天簡單易用、支援 POST/Headers/Cookie
GitHub Actions免費額度大Cron 語法、完整日誌、可運行腳本/容器
GitLab CI/CD免費Pipeline 排程、支援手動觸發
雲函數定時觸發各廠商免費額度SCF/FC/CloudRun 等,支援 HTTP 觸發
# GitHub Actions 範例 .github/workflows/cron.yml
name: Daily Cron
on:
  schedule:
    - cron: '0 2 * * *'  # UTC 時間
  workflow_dispatch:     # 手動觸發
jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger PHP Cron
        run: |
          curl -fsS --max-time 30 \
            -H "Authorization: Bearer ${{ secrets.CRON_TOKEN }}" \
            "https://mysite.com/api/cron/daily"

方案 C:長連接 Sleep 循環(極不推薦,僅作理論了解)

// 核心缺陷:佔用 FPM 進程、內存洩漏、無法優雅停止、部署失效
// 僅適合:本地測試、極低流量個人項目、無任何其他選擇
ignore_user_abort(true);
set_time_limit(0);
$interval = 3600; // 1 小時
$nextRun = strtotime('tomorrow 02:00');

while (true) {
    $wait = max(0, $nextRun - time());
    sleep($wait);
    
    // 檢查開關文件
    if (!file_exists(__DIR__ . '/cron_switch')) break;
    
    // 執行任務
    require __DIR__ . '/cron_task.php';
    
    $nextRun += 86400; // 下一天
}

第四層級:容器化/雲原生環境

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: php-daily-report
spec:
  schedule: "0 2 * * *"
  concurrencyPolicy: Forbid  # 禁止並行
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: php-task
            image: my-php-cli:8.2
            command: ["php", "/var/www/scripts/daily_report.php"]
            env:
            - name: APP_ENV
              value: "production"
            resources:
              requests:
                memory: "128Mi"
                cpu: "100m"
              limits:
                memory: "256Mi"
                cpu: "500m"

Sidecar 模式(應用容器內運行 Supercronic)

# Dockerfile
FROM php:8.2-cli
RUN curl -fsSL https://github.com/aptible/supercronic/releases/download/v0.2.1/supercronic-linux-amd64 -o /usr/local/bin/supercronic \
    && chmod +x /usr/local/bin/supercronic
COPY crontab /etc/crontab
CMD ["supercronic", "/etc/crontab"]

# crontab
* * * * * php /var/www/artisan schedule:run

演進路線圖與選型決策

┌─────────────────────────────────────────────────────────────┐
│  你有服務器 Root/管理員權限?                                  │
└─────────────────────┬───────────────────────────────────────┘
                      │
        ┌─────────────┴─────────────┐
        ▼                           ▼
       是                           否
        │                           │
        ▼                           ▼
┌───────────────┐         ┌───────────────────────┐
│ Linux/Unix?  │         │ 虛擬主機/共享主機?     │
└───────┬───────┘         └───────────┬───────────┘
        │                             │
   ┌────┴────┐                  ┌──────┴──────┐
   ▼         ▼                  ▼             ▼
  Linux    Windows            有流量?      無流量/極低
   │         │                  │             │
   ▼         ▼                  ▼             ▼
系統 Cron  任務計劃        第三方 Cron    GitHub Actions/
(首選)    程式 + bat      服務跳板       雲函數定時
   │         │                  │             │
   ▼         ▼                  ▼             ▼
┌─────────────────────────────────────────────────────────────┐
│  進階需求:秒級/毫秒級、高併發、分布式協調、可視化監控?       │
└─────────────────────┬───────────────────────────────────────┘
                      │
              ┌───────┴───────┐
              ▼               ▼
             是               否
              │               │
              ▼               ▼
    Swoole/Workerman/    當前方案足夠
    Hyperf/消息佇列/     專注業務開發
    K8s CronJob

通用最佳實踐清單(跨環境)

  1. 單一職責:每個腳本只做一件事,通過參數控制行為。
  2. 冪等性:任務可安全重試,不產生副作用(唯一索引、狀態機、去重表)。
  3. 配置外部化:數據庫連接、API Key、路徑全部用環境變量或配置文件。
  4. 結構化日誌:JSON 格式,含 timestamp、level、task_name、trace_id、duration_ms、status。
  5. 監控三件套:執行成功率、執行耗時、最後執行時間 → 推送到 Prometheus/Grafana/雲監控。
  6. 告警規則:連續 2 次失敗、超時未執行、執行時間異常增長 → 即時通知。
  7. 優雅停機:捕獲 SIGTERM,完成當前單元後退出,釋放鎖、關閉連接。

總結

PHP 定時任務的本質是外部調度 + CLI 執行。根據環境約束選型:

  • 有服務器權限 → 系統 Cron + flock/Redis 鎖(最穩健、成本最低)。
  • Windows 服務器 → 任務計劃程式 + bat 腳本。
  • 虛擬主機 → 第三方 Cron 服務(cron-job.org、GitHub Actions)跳板觸發 HTTP 端點。
  • 容器化/雲原生 → Kubernetes CronJob 或 Sidecar Supercronic。
  • 秒級/高併發/長連接 → Swoole/Hyperf/Workerman 常駐進程 + 內建定時器。

永遠不要在生產環境使用 ignore_user_abort() + sleep() 死循環。投資於正確的調度架構,將為後期維護節省無數工時。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved