Spec-Zone.ru › Apache HTTP Server

Руководство по HTTP/2

Это руководство по реализации HTTP/2 в Apache httpd. Эта функция находится в стадии готовой к производству, и вы можете ожидать, что интерфейсы и директивы останутся неизменными в выпусках.

Протокол HTTP/2

HTTP/2 — это эволюция самого успешного протокола прикладного уровня в мире, HTTP. Он фокусируется на более эффективном использовании сетевых ресурсов. Он не меняет фундаментальные принципы HTTP, семантику. По-прежнему есть запросы и ответы, заголовки и всё такое. Поэтому, если вы уже знаете HTTP/1, вы также знаете 95% о HTTP/2.

О HTTP/2 и о том, как он работает, написано много. Наиболее нормативным, конечно же, является его RFC 7540 (также доступно в более удобочитаемом формате, результаты могут варьироваться). Там вы найдёте все детали.

Однако, как и RFC, это не лучшая вещь для первого прочтения. Лучше сначала понять, что хочет сделать нечто, а затем прочитать RFC о том, как это делается. Гораздо лучшим документом для начала является http2 explained Дэниела Стэнберга, автора curl. Он также доступен на всё возрастающем списке языков!

Слишком долго, не читал: при чтении этого документа необходимо помнить о некоторых новых терминах и тонкостях:

  • HTTP/2 — это бинарный протокол, в отличие от HTTP 1.1, который является текстовым. Последний предназначен для чтения человеком (например, для перехвата сетевого трафика), в то время как первый — нет. Более подробная информация в официальном разделе вопросов и ответов вопрос.
  • h2 — это HTTP/2 через TLS (переговоры о протоколе через ALPN).
  • h2c — это HTTP/2 через TCP.
  • Кадр — это наименьшая единица связи в соединении HTTP/2, состоящая из заголовка и переменной последовательности октетов, структурированных в соответствии с типом кадра. Более подробная информация в официальном документе раздел.
  • Поток — это двусторонний поток кадров в соединении HTTP/2. Соответствующее понятие в HTTP 1.1 — обмен сообщениями запроса/ответа. Более подробная информация в официальном документе раздел.
  • HTTP/2 может выполнять несколько потоков данных по одному и тому же TCP-соединению, избегая классической проблемы HTTP 1.1 с блокировкой запросов и избегая повторного создания TCP-соединений для каждого запроса/ответа (KeepAlive исправил проблему в HTTP 1.1, но не решил её полностью).

HTTP/2 в Apache httpd

Протокол HTTP/2 реализован собственным модулем httpd, с говорящим названием mod_http2. Он реализует полный набор функций, описанных в RFC 7540, и поддерживает HTTP/2 по открытому тексту (http:), а также по защищённому (https:) соединению. Вариант открытого текста называется 'h2c', а защищённый — 'h2'. Для h2c он позволяет режим прямого доступа и Upgrade: посредством начального запроса HTTP/1.

Одной из особенностей HTTP/2, которая предоставляет новые возможности веб-разработчикам, является Server Push. Обратитесь к этому разделу, чтобы узнать, как использовать её в вашем веб-приложении.

Сборка httpd с поддержкой HTTP/2

mod_http2 использует библиотеку nghttp2 в качестве своей базовой реализации. Для сборки mod_http2 вам потребуется как минимум версия 1.2.1 библиотеки libnghttp2 на вашей системе.

При сборке исходного кода Apache httpd вам необходимо добавить параметр '--enable-http2' для запуска модуля. Если ваша libnghttp2 находится в необычном месте (что угодно на вашей операционной системе), вы можете указать её местоположение, используя '--with-nghttp2=<path>' для configure.

Хотя это должно сработать для большинства, есть люди, которые предпочитают статически связанную nghttp2 в этом модуле. Для них существует опция --enable-nghttp2-staticlib-deps. Она работает примерно так же, как и статическая компоновка OpenSSL для mod_ssl.

Говоря об SSL, вы должны знать, что большинство браузеров поддерживают HTTP/2 только по https: URL, поэтому вам нужен сервер с поддержкой SSL. Но не только это, вам понадобится библиотека SSL, которая поддерживает расширение ALPN. Если вы используете OpenSSL, вам нужна версия не ниже 1.0.2.

Базовая настройка

При построении httpd с поддержкой mod_http2 вам нужна базовая настройка для его активации. Первое, как и для любого модуля Apache, — это его загрузка:

LoadModule http2_module modules/mod_http2.so

Вторая директива, которую нужно добавить в вашу конфигурацию сервера, — это

Protocols h2 http/1.1

Это позволяет h2, защищённому варианту, быть предпочтительным протоколом на ваших серверных соединениях. Если вы хотите включить все варианты HTTP/2, просто напишите:

Protocols h2 h2c http/1.1

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

Protocols http/1.1
<VirtualHost ...>
    ServerName test.example.org
    Protocols h2 http/1.1
</VirtualHost>

Это позволяет использовать только HTTP/1 на подключениях, за исключением SSL-подключений к test.example.org, которые предлагают HTTP/2.

Выберите сильный SSLCipherSuite

SSLCipherSuite необходимо настроить с сильным набором шифров TLS. Текущая версия mod_http2 не навязывает никаких шифров, но большинство клиентов это делают. Указание браузера на сервер с поддержкой h2 с неподходящим набором шифров приведёт к отказу и возврату к HTTP 1.1. Это распространённая ошибка при первой настройке httpd для HTTP/2, поэтому имейте это в виду, чтобы избежать длительных сессий отладки! Если вы хотите быть уверены в выборе набора шифров, избегайте тех, которые указаны в списке отбрасываемых наборов шифров TLS HTTP/2.

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

Protocols http/1.1 h2

предпочтительным протоколом является HTTP/1, и он всегда будет выбран, если клиент только поддерживает h2. Поскольку мы хотим говорить по протоколу HTTP/2 с клиентами, которые его поддерживают, лучшим порядком будет

Protocols h2 h2c http/1.1

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

ProtocolsHonorOrder Off

делает порядок, в котором вы написали протоколы, несущественным, и только порядок клиента будет определять выбор.

И последнее: протоколы, которые вы настраиваете, не проверяются на правильность или правописание. Вы можете указать несуществующие протоколы, поэтому нет необходимости защищать Protocols какими-либо <IfModule> проверками.

Для более подробных советов по настройке см. раздел модулей о размерности и как управлять несколькими хостами с одним сертификатом.

Настройка MPM

HTTP/2 поддерживается во всех модулях многопроцессорной обработки, которые поставляются с httpd. Однако, если вы используете модуль prefork mpm, будут существенные ограничения.

В prefork, mod_http2 будет обрабатывать только один запрос за раз на одно соединение. Но клиенты, такие как браузеры, отправляют множество запросов одновременно. Если обработка одного из этих запросов занимает много времени (или это запрос с длительным опросом), остальные запросы будут приостановлены.

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

Если ваша установка способна справиться с этим, настройка модуля event mpm в настоящее время является лучшим вариантом (если он поддерживается на вашей платформе).

Если вы действительно застряли с prefork и хотите обрабатывать несколько запросов, вы можете настроить H2MinWorkers для этого. Однако, если это сломается, вы сами несёте ответственность за обе части.

Клиенты

Практически все современные браузеры поддерживают HTTP/2, но только по защищённым SSL-соединениям: Firefox (v43), Chrome (v45), Safari (с версии v9), iOS Safari (v9), Opera (v35), Chrome для Android (v49) и Internet Explorer (v11 на Windows10) (источник).

Другие клиенты, а также серверы, перечислены в вики-странице Implementations, среди них реализации для c, c++, общего Lisp, Dart, Erlang, Haskell, Java, Node.js, PHP, Python, Perl, Ruby, Rust, Scala и Swift.

Некоторые из внебраузерных реализаций поддерживают HTTP/2 по открытому тексту, h2c. Самым универсальным из них является curl.

Полезные инструменты для отладки HTTP/2

Первый инструмент, который следует упомянуть, — это, конечно, curl. Убедитесь, что ваша версия поддерживает HTTP/2, проверив её Features:

    $ curl -V
    curl 7.45.0 (x86_64-apple-darwin15.0.0) libcurl/7.45.0 OpenSSL/1.0.2d zlib/1.2.8 nghttp2/1.3.4
    Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 [...] 
    Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2
    

Примечания для домашнего использования Mac OS

brew install curl --with-openssl --with-nghttp2

А для глубокого анализа wireshark.

Пакет nghttp2 также включает в себя клиенты, такие как:

  • nghttp — полезно для визуализации кадров HTTP/2 и лучшего понимания протокола.
  • h2load — полезно для стресс-тестирования вашего сервера.

Chrome предлагает подробные журналы HTTP/2 для подключений на странице net-internals. Также есть интересная расширение для Chrome и Firefox для визуализации использования HTTP/2 вашим браузером.

Server Push

Протокол HTTP/2 позволяет серверу отправлять клиенту ответы, которые он никогда не запрашивал. Диалог такой: "вот запрос, которого вы не отправляли, и ответ на него придёт вскоре..."

Однако есть ограничения: клиент может отключить эту функцию, и сервер может отправлять PUSH только по запросу, исходящему от клиента.

Цель состоит в том, чтобы позволить серверу отправлять клиенту ресурсы, которые ему, скорее всего, понадобятся: CSS или JavaScript-ресурсы, относящиеся к странице HTML, которую запросил клиент. Набор изображений, на которые ссылается CSS и т. д.

Преимущества для клиента заключаются в экономии времени на отправку запроса, которое может составлять от нескольких миллисекунд до полусекунды, в зависимости от местоположения обоих участников на земном шаре. Недостаток заключается в том, что клиенту могут быть отправлены вещи, которые уже есть в его кэше. Конечно, HTTP/2 позволяет предвосхитительно отменять такие запросы, но всё равно тратятся ресурсы.

В качестве резюме: нет единой оптимальной стратегии использования этой функции HTTP/2, и все ещё ведутся эксперименты. Так как же можно провести эксперименты с ней в Apache httpd?

mod_http2 проверить заголовок ответа на Link заголовки в определённом формате:

Link </xxx.css>;rel=preload, </xxx.js>; rel=preload

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

<Location /xxx.html>
    Header add Link "</xxx.css>;rel=preload"
    Header add Link "</xxx.js>;rel=preload"
</Location>

Если вы хотите использовать preload ссылки без запуска PUSH, вы можете использовать параметр nopush, как в

Link </xxx.css>;rel=preload;nopush

или вы можете полностью отключить PUSH для своего сервера с помощью директивы

H2Push Off

И есть ещё:

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

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

Другой экспериментальный проект, реализованный в mod_http2 — это Заголовок поля Accept-Push-Policy, где клиент может для каждого запроса определить, какие PUSHы он принимает.

PUSH не всегда приводит к ожидаемому или желаемому результату в отношении запроса/ответа/производительности. В сети есть многочисленные исследования на эту тему, в которых объясняются преимущества и недостатки, а также влияние различных функций клиента и сети на результат. Например: то, что сервер PUSHит ресурс, не означает, что браузер действительно использует эти данные.

Главный фактор, влияющий на то, будет ли ответ PUSHнут, — это запрос, который был смоделирован. URL запроса для PUSH задаётся приложением, но откуда берутся заголовки запроса? Например, будет ли PUSH запрашивать заголовок accept-language и если да, то с каким значением?

Apache будет рассматривать исходный запрос (тот, который запустил PUSH) и копировать следующие заголовки в запросы PUSH: user-agent, accept, accept-encoding, accept-language, cache-control.

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

Предварительные подсказки

Альтернативой PUSH ресурсов является отправка заголовков Link клиенту до того, как ответ будет готов. Это использует функцию HTTP под названием «Предварительные подсказки» и описана в RFC 8297.

Для этого необходимо явно включить его на сервере с помощью

H2EarlyHints on

(По умолчанию он не включен, так как некоторые старые браузеры реагировали на такие ответы некорректно.)

Если эта функция включена, можно использовать директиву H2PushResource для запуска предварительных подсказок и PUSH ресурсов:

<Location /xxx.html>
    H2PushResource /xxx.css
    H2PushResource /xxx.js
</Location>

Это отправит клиенту ответ "103 Early Hints" как только сервер начнёт обработку запроса. Это может произойти намного раньше, чем будут определены первые заголовки ответа, в зависимости от вашего веб-приложения.

Если H2Push включено, это также запустит PUSH сразу после ответа 103. Однако, если H2Push отключено, ответ 103 всё равно будет отправлен клиенту.

© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/howto/http2.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API