Кэшированные, 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 введите описание изображения здесь


Параллельные домены сгруппированы | http://webpagetest.org введите описание изображения здесь


Водопад Водопад | http://site-perf.com введите описание изображения здесь


Pingdom Tools Водопад | http://tools.pingdom.com

введите описание изображения здесь


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

введите описание изображения здесь


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

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

В частности, самые последние библиотеки jQuery и jQuery UI могут ссылаться на эти 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 в один файл.

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

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

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

В связи с этим: «Исправленный вариант с измененным кодом», поскольку условный запрос возвратил полный контент без изменений ». и мои комментарии.

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

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

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

  1. Есть ли заголовок HTTP_IF_MODIFIED_SINCE
  2. Последнее модифицированное время кешированной версии такое же, как 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 MYH: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 MYH:i:s",time() - 404800000) . " GMT"); 

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

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

 $date = 'D, d MYH: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 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Вы можете установить xdebug, чтобы просмотреть сценарий и посмотреть, где узкие места.

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

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

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

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

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

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

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

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

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

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

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

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

http://i.tinysrc.mobi/ [высота] / [ширина] /http://img.ruphp.com/php/path_to_img.jpg

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

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

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


Вопросы-Ответы

Что мне стоило tinySrc?

Ничего.

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

Теперь.

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

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

Как быстро?

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Удачи!

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

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

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

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

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

Это позволит исправить 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