Всем привет, сегодня я расскажу о том, как настроил server push на своём сайте и добился увеличения скорости рендеринга страниц. Для начала о том, что же такое server push в HTTP/2. Это технология, позволяющая серверу «протолкнуть» дополнительные данные клиенту, в момент запроса основного документа. То есть в обычной ситуации запрашивает браузер html-страничку, затем обрабатывает её и приходит к выводу, что ему для корректного отображения необходимо подгрузить дополнительные файлы: стили, скрипты, изображения. После чего скачивает их и отображает конечный результат. Server push позволяет отправить дополнительные файлы уже в момент получения основного документа, и они уже будут иметься в кэше, когда они потребуются браузеру. За счёт этого возрастает скорость загрузки сайта.
На этот раз схема будет следующая:
Теперь непосредственно о самой реализации. В данный момент nginx в режиме HTTP/2 не поддерживает технологию server push. Для этих целей я буду использовать nghttp2 — именно его используют в CloudFlare для реализации push'ей для своих клиентов. nghttp2 — это набор инструментов, реализующих HTTP/2 протокол. А именно: standalone-сервер, клиент и обратный прокси-сервер. Нас интересует часть, реализующая прокси-сервер, программа называется nghttpx.
Устанавливаем nghttp2:
Настраиваем nghttpx. Файл конфигурации /etc/nghttpx/nghttpx.conf приводим к виду
Проверяем что сайт работает. Теперь для того, чтобы «запушить» файл стилей в браузер клиенту достаточно передать на nghttpx с бэкенда заголовок вида:
Для JS-файла заголовок будет таким:
Я добавил 14 таких заголовков, реализовав это на PHP. В файл index.php добавил строки:
и перезапустил Varnish для сброса всего кэша.
После этого в браузере загрузил главную страницу своего сайта и увидел пушнутые файлы:
А вот так выглядит загрузка с отключенными пушами:
Файл, который был отправлен с помощью server push имеет соответствующий заголовок.
Вот в виде сравнения скорости рендеринга главной страницы при push'е файлов со стилями и JS и без push'ей:
Замеры проводились инструментом WebPagetest/, о котором я узнал от своего коллеги. Проект open-source, доступна куча метрик, настроек и тестовых серверов. Всем советую!
Также в процессе работы я накодил мини-сервис, позволяющий быстро проверить список пушаемых файлов, введя url сайта. Может быть кому пригодится — webshake.ru/services?http2push
Технология server push'ей позволила сократить загрузку и отрисовку моего сайта с 1.7 до 1.4 секунд, а это аж 17%! Это работает и должно быть использовано.
Напоследок еще немного метрик с WebPagetest.
На этот раз схема будет следующая:
Теперь непосредственно о самой реализации. В данный момент nginx в режиме HTTP/2 не поддерживает технологию server push. Для этих целей я буду использовать nghttp2 — именно его используют в CloudFlare для реализации push'ей для своих клиентов. nghttp2 — это набор инструментов, реализующих HTTP/2 протокол. А именно: standalone-сервер, клиент и обратный прокси-сервер. Нас интересует часть, реализующая прокси-сервер, программа называется nghttpx.
Настройка
Устанавливаем nghttp2:
apt-get install nghttp2
Настраиваем nghttpx. Файл конфигурации /etc/nghttpx/nghttpx.conf приводим к виду
frontend=93.170.104.204,443 #IP и порт нашей веб-морды
backend=127.0.0.1,6081 #IP и порт бэкенд-сервера
private-key-file=/etc/ssl/ssl.webshake.ru.key #Закрытый ключ
certificate-file=/etc/ssl/ssl.webshake.ru.pem #Файл с сертификатом сайта и сертификатами УЦ, аналогично nginx
http2-proxy=no #Иначе server push будет недоступен
workers=1 #Число воркеров
Проверяем что сайт работает. Теперь для того, чтобы «запушить» файл стилей в браузер клиенту достаточно передать на nghttpx с бэкенда заголовок вида:
Link: /path/to/file.css; rel=preload; as=stylesheet
Для JS-файла заголовок будет таким:
Link: /path/to/file.js; rel=preload; as=script
Я добавил 14 таких заголовков, реализовав это на PHP. В файл index.php добавил строки:
<?php
header("link: </wp-content/themes/shootingstar/style.css>; rel=preload; as=stylesheet", false);
header("link: </wp-content/themes/shootingstar/css/elegantfont.css?ver=4.5.3>; rel=preload; as=stylesheet", false);
header("link: </wp-content/plugins/google-captcha/css/gglcptch.css?ver=1.23>; rel=preload; as=stylesheet", false);
header("link: </wp-content/plugins/crayon-syntax-highlighter/css/min/crayon.min.css?ver=_2.7.2_beta>; rel=preload; as=stylesheet", false);
header("link: </wp-content/plugins/crayon-syntax-highlighter/themes/github/github.css?ver=_2.7.2_beta>; rel=preload; as=stylesheet", false);
header("link: </wp-includes/js/wp-emoji-release.min.js?ver=4.5.3>; rel=preload; as=script", false);
header("link: </wp-includes/js/wp-embed.min.js?ver=4.5.3>; rel=preload; as=script", false);
header("link: </wp-content/themes/shootingstar/js/responsive.js?ver=1.0>; rel=preload; as=script", false);
header("link: </wp-content/themes/shootingstar/js/selectnav.js?ver=0.1>; rel=preload; as=script", false);
header("link: </wp-content/themes/shootingstar/js/menubox.js?ver=1.0>; rel=preload; as=script", false);
header("link: </wp-content/themes/shootingstar/js/scroll-to-top.js?ver=1.0>; rel=preload; as=script", false);
header("link: </wp-content/themes/shootingstar/js/placeholders.js?ver=2.0.8>; rel=preload; as=script", false);
header("link: </wp-includes/js/jquery/jquery-migrate.min.js?ver=1.4.1>; rel=preload; as=script", false);
header("link: </wp-includes/js/jquery/jquery.js?ver=1.12.4>; rel=preload; as=script", false);
и перезапустил Varnish для сброса всего кэша.
Результат
После этого в браузере загрузил главную страницу своего сайта и увидел пушнутые файлы:
А вот так выглядит загрузка с отключенными пушами:
Файл, который был отправлен с помощью server push имеет соответствующий заголовок.
Вот в виде сравнения скорости рендеринга главной страницы при push'е файлов со стилями и JS и без push'ей:
Замеры проводились инструментом WebPagetest/, о котором я узнал от своего коллеги. Проект open-source, доступна куча метрик, настроек и тестовых серверов. Всем советую!
Также в процессе работы я накодил мини-сервис, позволяющий быстро проверить список пушаемых файлов, введя url сайта. Может быть кому пригодится — webshake.ru/services?http2push
Вывод
Технология server push'ей позволила сократить загрузку и отрисовку моего сайта с 1.7 до 1.4 секунд, а это аж 17%! Это работает и должно быть использовано.
Напоследок еще немного метрик с WebPagetest.
Поделиться с друзьями
Комментарии (9)
dmitry_ch
30.06.2016 08:48Очень интересно: в nginx (который с 1.9.5 с http2 дружит, хотя модуль и экспериментальный) подобные push-ы, вроде как, можно сотворить путем отправки заголовков
add_header 'Link' '</asset/to/push.js>; rel=preload; as=script';
Вы же используете nghttp2 — вот в чем разница, nginx или nghttp2, если больше ничего на nghttp2 вы как бы и не настроили?vovochka404
30.06.2016 09:21Да, nginx дружит, но как автор и написал, не полностью.
Вот ананс 1.9.5 и там четко сказано:
HTTP/2’s ‘Server Push’ feature is not supported in this release.
Воз и ныне там вроде как.
vovochka404
Безусловно интересный опыт, но есть пара моментов.
У вас в developer tools стоит «disabel cache». А без кеша смотреть на загрузку статики не серьезно.
Так же, с учетом кеша, возникает вопрос, а стоит ли пушать при каждом запросе такое количество статики, если она у пользователя уже есть?
Увеличение передаваемых данных скорее сделает все только хуже.
TomskDiver
Наверное вы правы. Вот здесь Announcing Support for HTTP/2 Server Push как раз написано что пушить желательно некэшируемый контент, иначе пушинг может давать негативное влияние.
mantyr
Очевидно что статья лишь пример технологии. Дальше уже бизнс логика — что пушить, когда и при каких условиях.
Например
— если зашли на главную и не видим сессии — однозначно пушить всё
— если зашли на главную и видим что пользователь уже известен и заходил не давно — можно не пушить то что не поменялось
— если зашли на главную и видим что пользователь был до обновления продакшина — пушить то что обновилось или всё, в зависимости от того какие данные в удобном виде доступны
— если зашли не на главную, но в какой-то специализированный раздел где некоторые данные критичны — пушить
— если зашли на страницу где есть динамически обновляемые данные, например графики — пушить графики
И так далее и тому подобное.
ivashkevitch
Да, эффект в основном должен создаваться при первом посещении, нарулить это можно тучей способов — отправлять/резать заголовки, кому как нравится.
Есть другой веб-сервер, тоже поддерживающий http/2, называется H2O. Там вообще из коробки функционал проверки наличия файлов в кэше браузера и на основе этого происходит пуш.
ivashkevitch
https://h2o.examp1e.net/configure/http2_directives.html#http2-casper — вот эта директива