Эта статья является частью серии по созданию примера приложения — блога галереи с несколькими изображениями — для оценки производительности и оптимизации. (Посмотреть репо здесь.)
В этой статье мы проанализируем наше приложение галереи, используя инструменты, которые мы объяснили в предыдущем руководстве, и рассмотрим возможные пути дальнейшего повышения его производительности.
Как и в предыдущем посте , пожалуйста, настройте Ngrok и канал к локально размещенному приложению через него или разместите приложение на своем собственном демонстрационном сервере. Этот статический URL позволит нам тестировать наше приложение с помощью внешних инструментов, таких как GTmetrix и Pingdom Tools.
Мы пошли и отсканировали наш сайт с GTmetrix, чтобы увидеть, как мы можем улучшить его. Мы видим, что результаты, хотя и не катастрофически плохие, все же имеют место для улучшения.
Первая вкладка — PageSpeed - содержит список рекомендаций от Google . Первый элемент на вкладке PageSpeed - предупреждение о непротиворечивом URL — относится к нашему приложению, которое выводит изображения в случайном порядке, поэтому мы пропустим этот элемент. Следующее, что мы можем сделать, это кэширование в браузере.
Кэширование браузера
Мы видим, что существует файл main.css
для которого требуется установить заголовки Expires
, и изображения в галерее нуждаются в том же. Теперь первая идея для этих статических файлов — установить это в нашей конфигурации Nginx:
location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { expires 14d; }
Мы можем просто поместить это в наш блок server
и оставить это Nginx, верно?
Ну не совсем. Это позаботится о наших статических файлах, таких как CSS, но изображения /raw
нас предупреждают, на самом деле не такие статичные. Так что этот фрагмент в нашей конфигурации Nginx не так легко решит эту проблему. Для наших изображений у нас есть фактический контроллер, который создает их на лету, поэтому было бы идеально, если бы мы могли установить наши заголовки ответа прямо там, в контроллере. По некоторым причинам, они не были установлены должным образом Glide .
Возможно, мы могли бы установить нашу директиву Nginx таким образом, чтобы включать raw
ресурсы, но мы чувствовали, что подход к контроллеру более перспективен. Это потому, что мы не уверены, какой другой контент может в конечном итоге получить raw
суффикс — возможно, некоторые видео или даже аудиофайлы.
Итак, мы открыли /src/ImageController.php
в нашем приложении галереи изображений и serveImageAction()
эти две строки внутри нашего serveImageAction()
, перед тем как строка return $response
:
// cache for 2 weeks $response->setSharedMaxAge(1209600); // (optional) set a custom Cache-Control directive $response->headers->addCacheControlDirective('must-revalidate', true);
Это изменит наши динамические ответы на изображения, добавив соответствующие заголовки Cache Control
и Expires
.
Symfony имеет более полные возможности для кэширования ответов, как описано здесь .
Перезапустив Nginx, мы повторно протестировали наше приложение в GTmetrix, и вот:
компрессия
Затем GTmetrix дал нам предупреждение о размере и сжатии наших ресурсов:
В производстве это незначительная вещь, и улучшение в этом не будет иметь большого значения в данном конкретном случае, если сэкономить всего пару килобайт. Но так как эти руководства здесь, чтобы показать путь с другими, более существенными приложениями, мы также рассмотрим это улучшение.
Изображения можно оптимизировать заранее, но поскольку это динамические изображения, созданные с помощью Glide , о которых мы рассказывали в другой статье , мы не будем этого делать. Фактически, Glide предоставляет способы установить качество изображения. Но иногда мы не будем использовать Glide для обработки наших изображений, поэтому сначала попробуем другой подход.
Внутри нашего server
блока Nginx мы добавим пару строк, которые инструктируют Nginx сжимать наш контент:
gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 9; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/jpeg;
Объяснение каждого из этих параметров будет выходить за рамки данной статьи. Каждый из этих пунктов описан на веб-сайте Nginx , но стоит обсудить одну вещь — gzip_comp_level
.
С компрессией распространено мнение, что есть компромисс. Мы немного увеличиваем пропускную способность сети, уменьшая размер наших файлов, но затем теряем некоторые циклы ЦП нашего сервера, необходимые для включения и выключения наших ресурсов при каждом запросе. Или, как написано в этом блоге Cloudflare (к которому мы еще вернемся):
Существует компромисс между скоростью сжатия и скоростью передачи. Увеличение коэффициента сжатия выгодно только в том случае, если вы можете уменьшить количество байтов, которое вам нужно передать, быстрее, чем вы бы их фактически передали.
Вот почему люди редко устанавливают gzip_comp_level
на максимум 9, как мы. Они обычно соглашаются на что-то вроде 6. Таким образом, посетители по-прежнему получают сжатые ресурсы, но ЦП по-прежнему не подвергается большой нагрузке, особенно во время скачков трафика.
Но мы не будем следовать этому общему совету по двум причинам: во-первых, в производственных условиях, скорее всего, мы будем развертывать наше приложение на CDN , что полностью снимет нагрузку с нашего сервера, и, во-вторых, даже если мы не используем CDN, мы будем использовать кеширование страниц, так что это сжатие, осуществляемое нашим сервером, будем надеяться, будет выполняться только один раз для каждого ресурса. И при полном кэшировании в нашем браузере даже эти кэшированные сжатые ресурсы не будут запрашиваться так часто.
Итак, это обоснование для установки нашего gzip_comp_level
9, но в случае, если мы не собираемся использовать кэширование страниц / HTTP, мы, вероятно, установили бы это меньшее значение.
Сделав это, мы смогли улучшить наш результат gzip
:
Однако мы не смогли добиться такого же улучшения с нашими изображениями. Итак, мы вернулись к документации Glide и выяснили, как контролировать качество наших изображений: внутри нашего serveImageAction()
внутри нашего ImageController
мы нашли строку:
$cachePath = $glide->getGlide()->makeImage($file, ['w' => $size]);
Мы добавили качественный аргумент во второй аргумент массива makeImage()
:
$cachePath = $glide->getGlide()->makeImage($file, ['w' => $size, 'q' => 60]);
Мы не хотели устанавливать качество изображения ниже этого, потому что это не выглядело бы хорошо:
Затем мы удалили все изображения в нашей папке /var/uploads/cache
и провели повторное тестирование. Наши результаты на GTmetrix показали, что мы смогли улучшить на 5%:
Есть еще возможности для улучшения, но в 99% случаев, предпринятых нами шагов по улучшению наших изображений будет достаточно.
Мы также пошли в Pingdom Tools, чтобы проверить наш веб-сайт — и мы были удивлены, увидев, что мы получили 100% баллов. Хотя время загрузки страницы было не таким, каким оно должно быть, это было значительное улучшение по сравнению с 92%, которые мы получили раньше:
Эти рекомендации являются полезным руководством, но наш 100% -ный показатель был бы просто метрикой тщеславия, если бы наше время загрузки оставалось равным 4,21 секунды, поэтому мы включили кэширование Nginx, о котором писали в разделе «Оптимизация на стороне сервера», с помощью Nginx и pm-static . С включенным кэшированием наш результат теперь стал 100% по всем показателям, а время загрузки было менее 1 секунды:
Мы прилагаем файл HAR этого теста .
Вывод
Хотя мы достигли 100 из 100 с помощью инструментов Pingdom, есть показатели, которые не удовлетворены на 100% как по YSlow, так и по PageSpeed (GTmetrix). Однако эти вещи не в наших руках, как минимизация ресурсов (jQuery и Bootstrap), обслуживаемых другими CDN. Мы могли бы загрузить и минимизировать их, но сомнительно, насколько это было бы полезно, учитывая, что большинство людей уже загрузили их в свой браузер из-за широкого распространения ресурсов.
Есть вещи, которые мы не рассмотрели в этой статье, и которые будут рекомендованы в производстве — или, по крайней мере, заслуживают изучения — например, сжатие Brotli. Люди из Cloudflare написали интересный пост в блоге о своих результатах с этим алгоритмом сжатия. Как и во всем остальном, перед фактической реализацией необходимо тщательно протестировать ее на различных ресурсах и соединениях посетителей. По нашему мнению, при включенном HTTP-кэшировании даже затраты на сжатие ЦП, связанные с высокой степенью сжатия, все равно окупятся, потому что это единовременные затраты.
Модуль Nginx для сжатия Brotli можно найти здесь . Эта тема более подробно рассматривается в этой статье .
Если вам известны какие-либо другие улучшения, которые могут существенно повлиять на производительность, сообщите нам!