Как ускорить отдачу динамически генерируемых thumbnail'ов на PHP + GD?

Суть вопроса в следующем: есть проект, где загружается огромное количество фотографий с разным временем хранения. Это могут быть как небольшие изображения, так и фотографии с разрешением в 5000*5000. Из-за того, что изображения могут быть удалены хоть через секунду после загрузки, подумал, что создавать thumbnail - лишняя трата ресурсов и процессорного времени, так как этих тумбочек нужно примерно штук 5-6 разных размеров. Так как все изображения .jpg то решил использовать GD. Напилил примерно такой скриптец (thumb.php):
<?php
$from_name = dirname(__FILE__) . $_GET['name']; // для условности без проверок
$thumb_x = 280; // необходимая ширина, но я тоже передаю ее в параметре

if (!file_exists($from_name)) die("Source image does not exist!");

list($orig_x, $orig_y, $orig_img_type, $img_sizes) = @GetImageSize($from_name); // получаю нужные параметры

// тут высчитываю размеры эскиза с пропорциональным сжатием
$thumb_y = floor($orig_y * $thumb_x / $orig_x);
$per_x = $orig_x / $thumb_x;
$per_y = $orig_y / $thumb_y;
if($per_y < $per_x){
	$thumb_x = $orig_x / $per_y;
}
else{
	$thumb_y = $orig_y / $per_x;
}  

// создаю пустой холст, заливаю белым фоном и накладываю изображение
$ni = ImageCreateTrueColor($thumb_x,$thumb_y);
$white = imagecolorallocate($ni, 255, 255, 255);
imagefilledrectangle($ni, 0, 0, $thumb_x, $thumb_y, $white);
$im = ImageCreateFromJpeg($from_name);
imagepalettecopy($ni,$im);
imagecopyresampled($ni, $im, 0, 0, 0, 0, $thumb_x, $thumb_y, $orig_x, $orig_y);
header("Content-type: image/jpeg");
ImageJPEG($ni, NULL, 85); // последний параметр - качество (100-0)
?>


Со стороны клиента выглядит примерно так:
<a class="group" rel="group1" href="/photos/uploaded/8316e6749c40428ab140c79a7dbbf789.jpg">
    <img src="/thumb.php?name=/photos/uploaded/8316e6749c40428ab140c79a7dbbf789.jpg">
</a>


Если на странице 15-20 таких вставок, она получает все картинки > 5 секунд, не смотря на то, что размер каждой тумбочки ~10-15 кб.

Можно ли как-нибудь ускорить этот процесс? Если выставить качество на 100, то время отдачи может затянуться аж до 30+ секунд.
Есть ли выход изящнее и проще? Или все же сохранять эскизы и отдавать статикой?

UPD:
1) Если даже снизить качество до 5%, загрузка страницы занимает 2,5-3 секунды, что тоже очень долго. Учитывая, что все эскизы получаются не более 5 кб.
2) Статические изображения отдаются практически мгновенно, значит затык точно в долгой обработке.
  • Вопрос задан
  • 564 просмотра
Пригласить эксперта
Ответы на вопрос 5
@FanatPHP
Генери заранее только самую большую из превьюшек. на будет заведомом меньше монстра 5000х5000 и из нее првеьюшки будут генериться куда быстрее чем из исходной

вместо гд можно еше использовать имеджик - он покачественнее, пошустрее и поумнее
Ответ написан
ThunderCat
@ThunderCat Куратор тега PHP
{PHP, MySql, HTML, JS, CSS} developer
нужно примерно штук 5-6 разных размеров.
А нахуа вам их так много? 2, ну 3 предел, остальные просто скалить хтмлем под нужный размер. Хранить однозначно готовые.

UPD: webp юзайте для тумбов
Ответ написан
nokimaro
@nokimaro Куратор тега PHP
Генерация изображений по сути долгая так как упирается в ресурсы сервера (CPU) и ускорить тут (на лету) вряд ли особо получится.
Самый правильный вариант - кешировать сгенерированные превью на диск.
Можно оставить thumb.php как промежуточное звено, при первой генерации сохраняем резалт на диск, и при повторных запросах проверять что если файл thumbnail'а есть на диске - считывать и отдавать его.
Но самый быстрый и оптимальный вариант это всё-же кешировать и отдавать превью напрямую веб сервером, (без РНР), например при аплоаде сразу делать нужные размеры.

Можно обойтись вообще без РНР и использовать Модуль ngx_http_image_filter_module
https://habr.com/en/post/94435/
https://nginx.org/en/docs/http/ngx_http_image_filt...
Ответ написан
@AlexisKmetik
Кэш, используй кэш. Сгенируруй в наименее загруженное время, запиши на диск, потом клиентам из кэша отдавай. Под такую задачу цпу не напасешься.
Вообще не понимаю зачем столько мороки и каждый раз отдавать разные размеры? Просто интересно.
Ответ написан
OnYourLips
@OnYourLips
Нужно юзать кеш, но не локальный накопитель, а специализированный под это инструмент, например s3.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы