Кэшированные, PHP генерируемые миниатюры загружаются медленно

Вопрос Часть A ▉ (100 баунти, награжден)
Главный вопрос заключался в том, как сделать этот сайт, загружать быстрее. Сначала нам нужно было прочитать эти водопады. Спасибо всем за ваши предложения по анализу водопада. Очевидным из различных графиков водопада, показанных здесь, является основное узкое место: созданные миниатюрами PHP. Невозможность загрузки jQuery с CDN, предложенная Дэвидом, получила мою щедрость, хотя мой сайт был всего на 3% быстрее в целом и не отвечал на основное узкое место сайта. Время для разъяснения моего вопроса, и, еще одна награда:

Вопрос Часть B ▉ (100 баунтов, награжденных)
Новый фокус теперь заключался в решении проблемы, которая имела 6 изображений в формате jpg, которые вызывают большую часть задержки загрузки. Эти 6 изображений представляют собой миниатюры, генерируемые PHP, крошечные и только 3 ~ 5 kb, но загружаются относительно медленно. Обратите внимание на "время до первого байта" на разных графиках. Проблема осталась нерешенной, но щедрость пошла к Джеймсу, который исправил ошибку заголовка, которую RedBot подчеркивал: "If-Modified-Since возвращен условный запрос полный контент не изменился".

Вопрос Часть C ▉ (моя последняя щедрость: 250 баллов)
К сожалению, после исправления ошибки заголовка REdbot.org задержка, вызванная изображениями, генерируемыми PHP, осталась нетронутой. Что же это за крошечные пьяные 3 ~ 5Kb эскизы? Вся эта информация заголовка может отправлять ракеты на Луну и обратно. Любые предложения об этом узком месте очень ценятся и рассматриваются как возможный ответ, так как я застрял в этой узкой проблеме уже семь месяцев. Заранее благодарю.

[Некоторая справочная информация на моем сайте: CSS находится наверху. JS внизу (JQuery, JQuery UI, купил меню awm/menu.js движки, вкладки js engine, video swfobject.js) Черные линии на втором изображении показывают, что инициирует загрузку. Злой робот - мой питомец "ZAM". Он безвреден и часто счастливее.]


Загрузить водопад: хронологический | http://webpagetest.org enter image description here


Параллельные домены сгруппированы | http://webpagetest.org enter image description here


Водопад-Перф | http://site-perf.com enter image description here


Pingdom Tools Waterfall | http://tools.pingdom.com

enter image description here


Водопад GTmetrix | http://gtmetrix.com

enter image description here


Ответ 1

Во-первых, использование этих нескольких доменов требует нескольких поисков DNS. Вам лучше объединить многие из этих изображений в спрайт вместо распространения запросов.

Во-вторых, когда я загружаю вашу страницу, я вижу большую часть блокировки (~ 1.25) на all.js. Я вижу, что начинается с (старой версии) jQuery. Вы должны ссылаться на это с CDN Google, а не на уменьшить время загрузки, но полностью исключить HTTP-запрос для него.

В частности, самые последние библиотеки пользовательского интерфейса jQuery и jQuery можно ссылаться на эти URL-адреса (см. этот пост, если вам интересно, почему я опустил http:):

//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js

//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js

Если вы используете одну из стандартных тем пользовательского интерфейса jQuery, вы также можете вытащить свои CSS и изображения из CDN Google.

При оптимизированном хостинге jQuery вы также должны объединить awmlib2.js и tooltiplib.js в один файл.

Если вы обращаетесь к этим вещам, вы должны увидеть значительное улучшение.

Ответ 2

У меня была аналогичная проблема несколько дней назад, и я нашел head.js. Это Javascript Plugin, который позволяет загружать все паралины JS файлов. Надеюсь, что это поможет.

Ответ 3

Я далек от эксперта, но...

Относительно этого: "Условный запрос If-Modified-Since возвратил полный контент без изменений". и мои комментарии.

Код, используемый для создания Thumbnails, должен проверять следующее:

  • Есть ли кешированная версия миниатюры.
  • Является ли кешированная версия более новой, чем исходное изображение.

Если любое из них ложно, миниатюра должна быть сгенерирована и возвращена независимо от того, что. Если они оба верны, необходимо выполнить следующую проверку:

  • Есть ли заголовок HTTP_IF_MODIFIED_SINCE
  • Является ли время кеша последней модификации таким же, как HTTP_IF_MODIFIED_SINCE

Если любое из них ложно, нужно вернуть кэшированную миниатюру.

Если оба из них верны, возвращается 304 http-статус. Я не уверен, что это необходимо, но я также лично возвращаю заголовки Cache-Control, Expires и Last-Modified вместе с 304.

Что касается GZipping, мне сообщили, что нет необходимости в изображениях GZip, поэтому игнорируйте эту часть моего комментария.

Изменить: я не заметил вашего дополнения к вашему сообщению.

session_cache_limiter('public');
header("Content-type: " . $this->_mime);
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 2419200) . " GMT");
// I'm sure Last-Modified should be a static value. not dynamic as you have it here.
header("Last-Modified: " . gmdate("D, d M Y H:i:s",time() - 404800000) . " GMT");

Я также уверен, что ваш код должен проверять заголовок HTTP_IF_MODIFIED_SINCE и реагировать на него. Просто установите эти заголовки, и ваш файл .htaccess не даст требуемого результата.

Я думаю, вам нужно что-то вроде этого:

$date = 'D, d M Y H:i:s T'; // DATE_RFC850
$modified = filemtime($filename);
$expires = strtotime('1 year'); // 1 Year

header(sprintf('Cache-Control: %s, max-age=%s', 'public', $expires - time()));
header(sprintf('Expires: %s', date($date, $expires)));
header(sprintf('Last-Modified: %s', date($date, $modified)));
header(sprintf('Content-Type: %s', $mime));

if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified) {
        header('HTTP/1.1 304 Not Modified', true, 304);
        // Should have been an exit not a return. After sending the not modified http
        // code, the script should end and return no content.
        exit();
    }
}
// Render image data

Ответ 4

Ничего себе, трудно объяснить вещи, используя этот образ. Но здесь некоторые попытки:

  • 33-36 загружаются, потому что они динамически загружаются в swf, а swf (25) сначала загружается полностью, прежде чем загружает какой-либо дополнительный контент.
  • файлы 20 и 21 могут быть (я не знаю, потому что я не знаю ваш код), которые загружаются с помощью all.js(11), но для выполнения 11 он ждет всю страницу ( и активы) для загрузки (вы должны изменить это на domready)
  • файлы 22-32 загружаются этими двумя библиотеками, снова после того, как они полностью загружены.

Ответ 5

Просто угадайте, потому что для такого анализа требуется много тестов A/B: ваш .ch-домен кажется труднодоступным (длинные зеленые полосы перед первым байтом).

Это означает, что либо веб-сайт .ch плохо размещен, либо что у вашего провайдера нет хорошего маршрута к ним.

Учитывая диаграммы, это может объяснить большой успех.

На стороне примечания есть этот классный инструмент cuzillion, который поможет вам разобраться в зависимости от вашего заказа загрузки ressource.

Ответ 6

Попробуйте выполнить тесты Y! Slow и Page Speed ​​на вашем сайте/странице и следуйте инструкциям, чтобы разобраться в возможных узких местах производительности. Вы должны получать огромные выигрыши в производительности, если вы набрали больше очков в Y! Slow или Page Speed.

Эти тесты расскажут вам, что не так и что изменить.

Ответ 7

Итак, ваш PHP script генерирует миниатюры при каждой загрузке страницы? Во-первых, если изображения, которые отображаются на миниатюре, часто не меняются, вы можете настроить кеш таким образом, чтобы их не нужно анализировать каждый раз, когда загружается страница? Во-вторых, ваш PHP скрипт использует что-то вроде imagecopyresampled() для создания эскизов? То, что нетривиальный downsample и PHP скрипт ничего не вернут, пока не закончится его сокращение. Использование imagecopymerged() вместо этого уменьшит качество изображения, но ускорит процесс. И сколько сокращения вы делаете? Являются ли эти миниатюры 5% размером исходного изображения или 50%? Вероятно, больший размер исходного изображения приводит к замедлению, так как PHP скрипт должен получить исходное изображение в памяти, прежде чем он сможет сжать его и вывести меньший миниатюру.

Ответ 8

Я нашел URL вашего сайта и проверил отдельный файл jpg с домашней страницы. В то время как время загрузки сейчас разумно (161 мс), он ждет 126 мс, что слишком много.

Ваши последние измененные заголовки настроены на Sat, 01 января 2011 12:00:00 GMT, который выглядит слишком "круглым", чтобы быть реальной датой генерации; -)

Так как Cache-control является "public, max-age = 14515200", произвольные заголовки с последним изменением могут вызвать проблему через 168 дней.

Во всяком случае, это не настоящая причина задержек.

Вы должны проверить, что делает ваш генератор миниатюр, когда миниатюра уже существует, и что может потребовать столько времени, чтобы проверять и доставлять изображение.

Вы можете установить xdebug для профайла script и посмотреть, где узкие места.

Возможно, вся вещь использует фреймворк или подключается к какой-то базе данных ни для чего. Я видел очень медленные mysql_connect() на некоторых серверах, главным образом потому, что они соединялись с использованием TCP, а не сокета, иногда с некоторыми проблемами DNS.

Я понимаю, что вы не можете публиковать свой платный генератор здесь, но я боюсь, что существует слишком много возможных проблем...

Ответ 9

Если нет действительно веской причины (обычно нет), ваши изображения не должны вызывать интерпретатор PHP.

Создайте правило перезаписи для вашего веб-сервера, который напрямую загружает изображение, если оно находится в файловой системе. Если это не так, перенаправите ваш PHP script, чтобы сгенерировать изображение. Когда вы редактируете изображение, измените имя файла изображений, чтобы заставить пользователей, у которых есть кэшированная версия, получить недавно отредактированное изображение.

Если он не работает, по крайней мере, теперь вы не будете иметь никакого отношения к способу создания и проверки изображений.

Ответ 10

Изучите использование данных сеанса PHP. Возможно (возможно,), создающий изображение PHP script ждет, чтобы получить блокировку данных сеанса, которая заблокирована главной страницей неподвижного рендеринга или другими сценариями рендеринга изображений. Это сделало бы всю оптимизацию JavaScript/браузера практически неактуальной, поскольку браузер ожидает сервер.

PHP блокирует данные сеанса для каждого запускаемого script с момента начала обработки сеанса до момента завершения script или когда вызывается session_write_close(). Это эффективно сериализует вещи. Просмотрите страницу PHP на сеансах, особенно комментарии, такие как этот.

Ответ 11

Это просто дикая догадка, так как я не смотрел на ваш код, но я подозреваю, что сеансы могут играть роль здесь, из статьи PHP Manual на session_write_close():

Данные сеанса обычно сохраняются после ваш script завершен без необходимо вызвать session_write_close(), но поскольку данные сеанса заблокированы предотвращать одновременную запись только одной script может работать на сеансе при любом время. При использовании наборов фреймов вместе с сеансами вы из-за этого замок. Вы можете сократить время необходимо загрузить все завершение сеанса, как только все изменения переменных сеанса сделал.

Как я уже сказал, я не знаю, что делает ваш код, но эти графики кажутся странно подозрительными. У меня была аналогичная проблема, когда Я закодировал функцию обслуживания нескольких файлов, и у меня была та же проблема. При обслуживании большого файла я не мог заставить работать многостраничную функциональность, и не мог открыть другую страницу до завершения загрузки. Вызов session_write_close() исправлен и мои проблемы.

Ответ 12

Пробовали ли вы заменять php-созданные thumnails регулярными изображениями, чтобы увидеть, есть ли разница? Проблема может быть вокруг - ошибка в вашем php-коде, приводящая к регенерации миниатюры при каждом вызове сервера - задержка в вашем коде (sleep()?), связанная с проблемой часов - проблема с жестким диском, вызывающая очень плохое состояние гонки, поскольку все миниатюры загружаются/генерируются в одно и то же время.

Ответ 13

Я думаю, вместо того, чтобы использовать этот миниатюрный генератор script, вы должны дать TinySRC попытку быстрого быстрого и облачного эскиза поколение. Он имеет очень простой и простой в использовании API, который можно использовать как: -

http://i.tinysrc.mobi/ [высота]/ [ширина]/http://domain.tld/path_to_img.jpg

[ширина] (необязательно): - Это ширина в пикселях (что переопределяет адаптивный или семейный размер). Если префикс "-" или "x", он вычитает или уменьшает процент от определенного размера.

[высота] (необязательно): - Это высота в пикселях, если также присутствует ширина. Он также переопределяет адаптивную или семейную калибровку и может иметь префикс "-" или "x".

Вы можете проверить резюме API здесь


FAQ

Что мне дорого стоило tinySrc?

Ничего.

Когда я могу начать использовать tinySrc?

Теперь.

Насколько надежна служба?

Мы не гарантируем услугу tinySrc. Однако он работает с основной облачной инфраструктурой, поэтому он обеспечивает высокую доступность во всем мире. Этого должно быть достаточно для всех ваших потребностей.

Насколько это быстро?

tinySrc кэширует размер изображений в памяти и в нашем хранилище данных до 24 часов, и он не будет получать ваше исходное изображение каждый раз. Это делает услуги невероятно быстрыми с точки зрения пользователей. (И уменьшает нагрузку на сервер как хороший побочный эффект.)


Удачи. Просто предложение, так как u не показывает нам код: p

Ответ 14

Как только некоторые браузеры загружают только 2 параллельных загрузки на домен, не могли бы вы добавить дополнительные домены в очертить запросы от двух до трех разных имен хостов. например 1.imagecdn.com 2.imagecdn.com

Ответ 15

Прежде всего, вам нужно обрабатывать запросы If-Modified-Since и так надлежащим образом, как сказал Джеймс. Эта ошибка гласит, что: "Когда я спрашиваю ваш сервер, изменилось ли это изображение с момента последнего раза, оно отправляет целое изображение вместо простого да/нет".

Время между соединением и первым байтом - это, как правило, время, которое выполняет ваш PHP script. Очевидно, что что-то происходит, когда запускается script.

  • Рассматривали ли вы его профилирование? У него могут быть некоторые проблемы.
  • В сочетании с вышеупомянутой проблемой ваш script может работать гораздо больше, чем необходимо. В идеале, он должен генерировать большие пальцы только в том случае, если исходное изображение изменено и отправляет кешированные большие пальцы для каждого другого запроса. Вы проверили, что script генерирует изображения без необходимости (например, для каждого запроса)?

Создание правильных заголовков через приложение немного сложно, плюс они могут быть перезаписаны сервером. И вы подвергаетесь злоупотреблениям, поскольку любой, кто отправляет некоторые заголовки запросов без кэша, заставит ваш генератор миниатюр работать непрерывно (и увеличивать нагрузку). Поэтому, если это возможно, попробуйте сохранить эти сгенерированные большие пальцы, вызовите сохраненные изображения непосредственно со своих страниц и управляйте заголовками из .htaccess. В этом случае вам не понадобится ничего в вашем .htaccess, если ваш сервер настроен правильно.

Кроме этого, вы можете применить некоторые из ярких идей оптимизации от исполнительных частей этого общего приятного SO-вопроса на как правильно сделать веб-сайты, например разделяя ваши ресурсы на куки-поддомены и т.д. Но, во всяком случае, изображение 3k не должно занимать второе место для загрузки, это очевидно по сравнению с другими элементами на графиках. Перед оптимизацией следует попытаться определить проблему.

Ответ 16

Вы пытались настроить несколько поддоменов под веб-сервер NGINX специально для обслуживания статических данных, таких как изображения и таблицы стилей? Что-то полезное можно было бы найти в этом разделе.

Ответ 17

Что касается отложенных эскизов, попробуйте поместить вызов flush() сразу после последнего вызова header() в генерации миниатюр script. После этого восстановите свой график водопада и посмотрите, есть ли задержка на корпусе вместо заголовков. Если это так, вам нужно долго смотреть на логику, которая генерирует и/или выводит данные изображения.

script, который обрабатывает миниатюры, должен с надеждой использовать какое-то кеширование, чтобы любые действия, которые выполняются с изображениями, которые вы обслуживаете, будут возникать только тогда, когда это абсолютно необходимо. Похоже, что некоторая дорогостоящая операция выполняется каждый раз, когда вы обслуживаете миниатюры, которые задерживают любой вывод (включая заголовки) из script.

Ответ 18

Большая часть медленной проблемы - ваш TTFB (время до первого байта) слишком высокий. Это сложный вопрос, не связанный с конфигурационными файлами вашего сервера, кодом и базовым оборудованием, но я могу видеть его безудержным при каждом запросе. У вас слишком много зеленых баров (плохо) и очень маленькие синие бары (хорошие). Возможно, вам захочется немного прекратить оптимизацию интерфейса, так как я считаю, что вы много сделали в этой области. Несмотря на то, что " 80% -90% времени отклика конечного пользователя тратится на интерфейс", я считаю, что ваш бэкенд.

TTFB - это бэкэнд-материал, материал сервера, предварительная обработка перед выходом и подтверждение связи.

Время выполнения кода для поиска медленных файлов, таких как медленные запросы к базе данных, время ввода и выхода из функций/методов для поиска медленных функций. Если вы используете php, попробуйте Firephp. Иногда бывает, что во время запуска или инициализации запускается один или два медленных запроса, например, вытягивание информации о сеансе или проверка подлинности, а что нет. Оптимизация запросов может привести к некоторым хорошим перфомансам. Иногда код запускается с использованием php prepend или spl автозагрузки, чтобы они работали на всех. В других случаях это может быть настроенный apache conf и настройка, которая экономит день.

Ищите неэффективные циклы. Ищите медленные вызовы кэшей или медленные операции ввода-вывода, вызванные неправильными дисками или большим дисковым пространством. Ищите использование памяти и то, что используется и где. Запустите повторный тест webpagetest из 10 прогонов на одном изображении или файле, используя только первый вид из разных мест по всему миру, а не в том же месте. И прочитайте свои журналы доступа и ошибок, слишком много разработчиков игнорируют их и полагаются только на выводимые на экран ошибки. Если ваш веб-хост имеет поддержку, попросите их о помощи, если они, возможно, не вежливо попросят их о помощи в любом случае, это не повредит.

Вы можете попробовать DNS Prefetching для борьбы со многими доменами и ресурсами, http://html5boilerplate.com/docs/DNS-Prefetching/

Является ли ваш сервер хорошим/достойным сервером? Иногда лучший сервер может решить множество проблем. Я поклонник " аппаратное обеспечение дешево, программисты дорогие, если у вас есть шанс и деньги на обновление сервера. И/Или используйте CDN, например maxcdn или cloudflare или аналогичный.

Удачи!

(p.s. я не работает ни для одной из этих компаний. Также ссылка на cloudflare выше будет утверждать, что TTFB не так важен, я бросил это там, чтобы вы могли получить еще один вариант.)

Ответ 19

К сожалению, вы предоставляете несколько данных. И у вас уже были хорошие предложения.

Как вы обслуживаете эти изображения? Если вы передаете их через PHP, вы делаете очень плохо, даже если они уже созданы.

НИКОГДА НЕ СНИМАЙТЕ ИЗОБРАЖЕНИЯ С PHP. Это замедлит ваш сервер, независимо от того, как вы его используете.

Поместите их в доступную папку со значимым URI. Затем вызовите их непосредственно с их реальным URI. Если вам нужно поколение на лету, вы должны поместить .htaccess в каталог изображений, который перенаправляет на генератор php- script только в случае отсутствия изображения запроса. (это называется стратегией кэша по запросу).

Выполнение этого исправляет php-сеанс, браузер-прокси, кеширование, ETAGS, все сразу.

WP-Supercache использует эту стратегию при правильной настройке.

Я написал это некоторое время назад (http://code.google.com/p/cache-on-request/source/detail?r=8), последние версии нарушены, но я думаю, 8 или меньше должны работать, и вы можете возьмите .htaccess в качестве примера, чтобы проверить все (хотя есть более эффективные способы настройки .htaccess, чем я использовал).

Я описал эту стратегию в этом блоге (http://www.stefanoforenza.com/need-for-cache/). Это, вероятно, плохо написано, но это может помочь прояснить ситуацию.

Дополнительная литература: http://meta.wikimedia.org/wiki/404_handler_caching