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

PHP 依 URL 自動生成縮圖並解決高併發衝突的實作方案

     編輯:PHP 相關知識

縮圖生成時機的兩大策略對比

策略優點缺點
上傳時生成 讀取時無需判斷、CPU 開銷極低、回應最快 尺寸變更或新增規格時,需重刷全量歷史圖片,維護成本高
訪問時生成(按需生成) 1. 無訪問不生成,節省儲存空間
2. 尺寸調整只需改配置,無需重刷歷史
3. 部署彈性高,適合多規格、不確定需求場景
高併發下首次生成會造成 CPU/IO 暴衝,導致服務雪崩

綜合權衡,「訪問時生成」優勢明顯,關鍵在於解決高併發下的重複生成問題。

高併發解決方案:臨時標記檔 + 等待機制

核心邏輯:

  1. 判斷需生成縮圖時,在 /tmp/ 建立唯一標記檔(檔名 = md5(目標路徑))。
  2. 若標記檔已存在,代表有其他進程正在生成,當前進程進入等待迴圈(usleep(300ms)),直到標記檔消失。
  3. 等待超時(預設 5 秒)則放棄輸出,避免阻塞過久。
  4. 生成完成者刪除標記檔,喚醒等待進程直接讀取成品輸出。

核心程式碼實作 (createthumb.php)

<?php
define('WWW_PATH', dirname(dirname(__FILE__)));
require WWW_PATH . '/PicThumb.class.php';
require WWW_PATH . '/ThumbConfig.php';

$logFile     = WWW_PATH . '/createthumb.log';
$sourceRoot  = WWW_PATH . '/upload/';
$destRoot    = WWW_PATH . '/supload/';

$path = $_GET['path'] ?? '';
if (!$path) exit();

// 解析相對路徑與類型
$relativeUrl = str_replace($destRoot, '', WWW_PATH . $path);
$type        = substr($relativeUrl, 0, strpos($relativeUrl, '/'));
$config      = $thumb_config[$type] ?? null;

if (!$config || empty($config['fromdir'])) exit();

$sourceFile = str_replace('/' . $type . '/', '/' . $config['fromdir'] . '/', $sourceRoot . $relativeUrl);
$destFile   = $destRoot . $relativeUrl;

if (!file_exists($sourceFile)) exit();

// ====== 高併發鎖機制 ======
$processingFlag = '/tmp/thumb_' . md5($destFile);
$isWait         = false;
$waitTimeout    = 5;
$startTime      = time();

if (!file_exists($processingFlag)) {
    file_put_contents($processingFlag, 1, LOCK_EX); // 原子建立
} else {
    $isWait = true;
}

if ($isWait) {
    while (file_exists($processingFlag)) {
        if (time() - $startTime > $waitTimeout) exit('timeout');
        usleep(300000); // 300ms
    }
    // 等待結束,直接輸出成品
    if (file_exists($destFile)) {
        ob_clean();
        header('Content-Type: ' . mime_content_type($destFile));
        exit(file_get_contents($destFile));
    }
    exit('generation failed');
}

// ====== 實際生成縮圖 ======
$thumb = new PicThumb($logFile);
$thumb->set_config($config);
$success = $thumb->create_thumb($sourceFile, $destFile);

unlink($processingFlag); // 釋放鎖

if ($success) {
    ob_clean();
    header('Content-Type: ' . mime_content_type($destFile));
    exit(file_get_contents($destFile));
}
exit('create failed');

關鍵細節補充

  • 原子建立鎖:file_put_contents(..., LOCK_EX) 確保同一時刻只有一個進程成功建立標記檔。
  • 目錄權限:/tmp/ 需可寫;$destRoot 需 Web 使用者寫入權限。
  • 超時保護:防止生成進程異常退出導致永久等待,5 秒可依圖片大小調整。
  • 清理機制:可搭配 Cron 定期清理殘留標記檔(如超過 10 分鐘未刪除)。
  • 擴展性:高流量場景建議改用 Redis SETNX 或 Memcached add 實現分散式鎖,效能更優。

適用場景與遷移建議

本方案適合中小型專案、單機部署。若已遷移至雲端或微服務架構,建議改用 物件儲存(S3/OSS)+ CDN 回源處理 或 影像處理服務,徹底卸載應用伺服器壓力。

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