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

PHP 根據 URL 自動生成縮略圖並解決高併發問題

     編輯:PHP 相關知識

在 Web 開發中,縮略圖的生成時機通常有兩種策略:上傳時生成與訪問時生成。兩者各有優劣,選擇哪種取決於具體業務場景。

兩種生成策略對比

1. 上傳時生成

優點: 圖片上傳時即預先生成所需尺寸,讀取時無需判斷邏輯,減少 CPU 運算開銷,響應速度快。

缺點: 當縮略圖尺寸需求變更或新增尺寸時,必須重新遍歷所有原圖批量生成,維護成本高,佔用存儲空間大。

2. 訪問時生成(按需生成)

優點:

  • 只有被訪問的圖片才會生成,未被訪問的不佔用空間,節省存儲資源。
  • 尺寸調整靈活,只需修改配置參數,無需重新生成歷史圖片。

缺點: 高併發訪問同一張尚未生成的縮略圖時,會觸發多進程重複生成,導致服務器資源耗盡、響應超時甚至宕機。

綜合來看,訪問時生成策略在靈活性和空間效率上更優,關鍵在於解決高併發下的重複生成問題。

高併發解決方案:臨時標記文件鎖機制

核心思路:利用文件系統的原子性操作,在生成縮略圖前創建唯一標記文件,其他請求檢測到標記存在則進入等待,直到生成完成並刪除標記。

實現邏輯

  1. 判斷目標縮略圖是否存在,不存在則準備生成。
  2. 在 /tmp/ 目錄創建標記文件,命名規則:thumb_{md5(目標文件路徑)}。
  3. 若標記文件不存在,當前進程創建標記並執行生成邏輯;若已存在,進入等待循環。
  4. 等待進程定期輪詢(如 300ms),超時(如 5 秒)則放棄輸出。
  5. 生成完成後刪除標記文件,等待進程檢測到標記消失,直接輸出已生成的圖片。

關鍵代碼實現(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';
$source_path = WWW_PATH.'/upload/';
$dest_path = WWW_PATH.'/supload/';

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

// 解析請求路徑,獲取類型與配置
$relative_url = str_replace($dest_path, '', WWW_PATH.$path);
$type = substr($relative_url, 0, strpos($relative_url, '/'));
$config = isset($thumb_config[$type]) ? $thumb_config[$type] : '';
if (!$config || !isset($config['fromdir'])) exit();

$source = str_replace('/'.$type.'/', '/'.$config['fromdir'].'/', $source_path.$relative_url);
$dest = $dest_path.$relative_url;

if (!file_exists($source)) exit(); // 原圖不存在

// --- 高併發鎖機制 ---
$processing_flag = '/tmp/thumb_'.md5($dest);
$is_wait = 0;
$wait_timeout = 5;
$starttime = time();

if (!file_exists($processing_flag)) {
    file_put_contents($processing_flag, 1, LOCK_EX); // 原子寫入
} else {
    $is_wait = 1;
}

if ($is_wait) {
    while (file_exists($processing_flag)) {
        if (time() - $starttime > $wait_timeout) exit(); // 超時退出
        usleep(300000); // 休眠 300ms
    }
    // 生成完成,直接輸出
    if (file_exists($dest)) {
        ob_clean();
        header('Content-Type: '.mime_content_type($dest));
        exit(file_get_contents($dest));
    } else {
        exit(); // 生成失敗
    }
}

// --- 執行生成 ---
$obj = new PicThumb($logfile);
$obj->set_config($config);
$create_flag = $obj->create_thumb($source, $dest);

unlink($processing_flag); // 釋放鎖

if ($create_flag) {
    ob_clean();
    header('Content-Type: '.mime_content_type($dest));
    exit(file_get_contents($dest));
}
?>

方案優勢與注意事項

  • 輕量級: 無需引入 Redis、Memcached 等外部依賴,利用本地文件系統即可實現進程間同步。
  • 防死鎖: 設置超時機制,避免生成進程異常退出導致標記文件殘留,造成永久阻塞。
  • 原子操作: file_put_contents(..., LOCK_EX) 確保標記創建的原子性。
  • 適用場景: 單機或共享存儲的多機部署環境;若為分佈式無共享存儲,建議改用 Redis 分佈式鎖。

通過這種「首次請求生成,並發請求等待」的機制,有效解決了縮略圖按需生成時的高併發衝突,兼顧了存儲效率與系統穩定性。

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