| 策略 | 優點 | 缺點 |
|---|---|---|
| 上傳時生成 | 讀取時無需判斷、CPU 開銷極低、回應最快 | 尺寸變更或新增規格時,需重刷全量歷史圖片,維護成本高 |
| 訪問時生成(按需生成) | 1. 無訪問不生成,節省儲存空間 2. 尺寸調整只需改配置,無需重刷歷史 3. 部署彈性高,適合多規格、不確定需求場景 |
高併發下首次生成會造成 CPU/IO 暴衝,導致服務雪崩 |
綜合權衡,「訪問時生成」優勢明顯,關鍵在於解決高併發下的重複生成問題。
核心邏輯:
/tmp/ 建立唯一標記檔(檔名 = md5(目標路徑))。usleep(300ms)),直到標記檔消失。<?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 使用者寫入權限。本方案適合中小型專案、單機部署。若已遷移至雲端或微服務架構,建議改用 物件儲存(S3/OSS)+ CDN 回源處理 或 影像處理服務,徹底卸載應用伺服器壓力。