study-http2
Описание
Проект для изучения HTTP/2, используя Spring Boot приложения
Языки
- Java95%
- Shell5%
Проект для изучения HTTP/2, используя Spring Boot приложения
Приложение 1, использующее HTTP/1.1
В приложении на Tomcat-е поднят HTTP/1.1 endpoint, который закрыт mTLS-ом (порт 8443).
При попытке получить сертификаты сервера, он выдаёт свой серверный сертификат и корневой, которым подписан:
openssl s_client -showcerts -connect localhost:8443
Обратиться к endpoint-у можно так:
cd ${projectRoot}/certificates
curl https://localhost:8443/http1-app/echo -v \
--cacert root/root-ca.pem --cert client/client.pem --key client/client.key --pass client \
--request POST --header "Content-Type: application/json" --data '{"data": "requestData"}'
В многословном ответе -а будет следующее подтверждение использования протокола HTTP/1.1:
* ALPN, server did not agree to a protocol
...
> POST /http1-app/echo HTTP/1.1
Приложение 2, использующее HTTP/2
В приложении на Tomcat-е поднят HTTP/2 endpoint, который закрыт mTLS-ом (порт 9443).
При попытке получить сертификаты сервера, он выдаёт свой серверный сертификат и корневой, которым подписан:
openssl s_client -showcerts -connect localhost:9443
Обратиться к endpoint-у можно так:
cd ${projectRoot}/certificates
curl https://localhost:9443/http2-app/echo -v \
--cacert root/root-ca.pem --cert client/client.pem --key client/client.key --pass client \
--request POST --header "Content-Type: application/json" --data '{"data": "requestData"}'
В многословном ответе -а будет следующее подтверждение использования протокола HTTP/2:
* ALPN, server accepted to use h2
* ...
* Using HTTP2, server supports multiplexing
...
> POST /http2-app/echo HTTP/2
Выводы
-
Достаточно добавить в
строку:application.ymlserver.http2.enabled=true
и Tomcat поднимет endpoint, используя протокол HTTP/2.
См. https://stackoverflow.com/questions/38612704/enable-http2-with-tomcat-in-spring-boot,
https://www.baeldung.com/spring-boot-http2-tomcat. -
Браузер по умолчанию держит несколько соединений для HTTP/1.1 и одно соединение для HTTP/2.
Нужно отправить из браузера GET-запросhttps://localhost:8443/http1-app/echo?data=requestData
или, проверяя установленные соединения командами:https://localhost:9443/http2-app/echo?data=requestData(i) По умолчанию браузер держит эти соединения 1 минуту, после чего обрывает, если нет других запросов.
(i) Чтобы из браузера доходили запросы, нужно закомментировать встрокуapplication.yml(т.е. переключиться с mTLS на односторонний TLS), а также добавить в доверенные сертификаты браузераclient-auth: need.${projectRoot}/certificates/root/root-ca.pem -
Curl закрывает соединения после каждого запроса (и для HTTP/1.1, и для HTTP/2).
-
Время жизни соединения HTTP/2 может быть ограничено только сервером.
Для этого через бинможно найти объектTomcatConnectorCustomizerметодомHttp2Protocolи вызвать у него методConnector.findUpgradeProtocols().setKeepAliveTimeout( <value in millis> )
В Apache HttpClient v5 не удалось найти способ ограничить keepAlive или timeToLive (ни через, ни черезConnectionConfig, ни черезRequestConfig, ни черезIOReactorConfig). Если сервер жив и отвечает, то клиент не прерывает даже idle соединение.evictIdleConnections()
(!) Единственный способ закрыть HTTP/2 соединение на клиенте - закрыть экземпляр HttpClient-а. -
Выводы по экспериментам с запросами/ответами в 1 КБ (+ 300 Б заголовков):
- На HTTP/2 без pool-а:
- latency в 6,8 раза меньше, чем на HTTP/1.1
- throughput в 12,7 раза больше, чем на HTTP/1.1 (утилизация CPU ~ равна 50%, на HTTP/2 была даже меньше, т.к. не удалось загрузить сильнее)
- На HTTP/2 с pool-ом соединений из библиотеки Apache HttpClient v5:
- latency такая же, как на HTTP/1.1
- throughput в 2,9 раза больше, чем на HTTP/1.1 (утилизация CPU ~ равна 50%)
- На HTTP/2 с собственным pool-ом экземпляров HttpClient-а (таких, как в HTTP/2 без pool-а):
- latency в 6,8 раза меньше, чем на HTTP/1.1
- throughput в 22,9 раза больше, чем на HTTP/1.1 (утилизация CPU ~ равна 50%)
- Последний вариант использования HTTP/2 самый эффективный.
- На HTTP/2 без pool-а:
-
Выводы по экспериментам с запросами/ответами в 1 МБ (+ 300 Б заголовков):
- На HTTP/2 без pool-а:
- latency на 9,5% меньше, чем на HTTP/1.1
- (!) throughput в 2,4 раза меньше, чем на HTTP/1.1 (утилизация CPU ~ равна 50%, на HTTP/2 была сильно меньше, т.к. не удалось загрузить сильнее)
- На HTTP/2 с pool-ом соединений из библиотеки Apache HttpClient v5:
- latency на 1,6% меньше, чем HTTP/1.1
- throughput на 0,8% больше, чем на HTTP/1.1 (утилизация CPU ~ равна 50%)
- На HTTP/2 с собственным pool-ом экземпляров HttpClient-а (таких, как в HTTP/2 без pool-а):
- latency на 6,6% меньше, чем на HTTP/1.1
- (!) throughput на 11,2% больше, чем на HTTP/1.1 (утилизация CPU ~ равна 50%)
- Последний вариант использования HTTP/2 самый эффективный.
- Вывод о сравнении с запросами/ответами в 1 КБ:
На мегабайтных запросах/ответах у HTTP/2 хуже пропускная способность, чем у HTTP/1.1, используя connection pool.
Это не удивительно, поскольку клиент HTTP/2 использует только одно TCP-соединение, куда куча параллельных мегабайтов не влезает.
Пришлось помочь HTTP/2 закрыть этот недостаток, реализовав собственный pool экземпляров клиентов HTTP/2 (чтобы каждый поток брал только свободного клиента, либо создавал нового).
Использование HTTP/2 с таким custom clients pool-ом не только убрало проблему с пропускной способностью на 1 МБ, но и улучшило этот показатель на 1 КБ (не ухудшив остальное).
- На HTTP/2 без pool-а: