ADG Оставить заявку
Блог Инфраструктура 4 мин чтения

HAProxy 1.6: HTTP/2 для публичных API и минус 30% времени загрузки на мобильных клиентах

Обновили балансировщики до HAProxy 1.6 с нативным HTTP/2 и улучшенным SSL offloading. Мобильные клиенты почувствовали разницу - мультиплексирование убирает очереди запросов.

Контекст момента

HAProxy 1.6 выпущен с нативной поддержкой HTTP/2 и улучшенным SSL offloading

HAProxy 1.6 вышел на прошлой неделе, и мы его уже раскатили на нескольких клиентских балансировщиках. Главное в релизе - нативная поддержка HTTP/2 на фронтенде и переработанный SSL offloading. Для нас это был повод закрыть задачу, которую откладывали месяца три: перевести публичные API одного из клиентов на HTTP/2 без дополнительного слоя терминации.

Зачем вообще HTTP/2 для API

У клиента - мобильное приложение, которое при запуске делает серию коротких запросов к API: профиль пользователя, список уведомлений, текущий баланс, настройки. Запросы независимые, идут последовательно - не потому что так задумано архитектурно, а потому что HTTP/1.1 создаёт очередь на одном соединении, и клиент так или иначе упирается в head-of-line blocking.

С HTTP/2 все эти запросы идут параллельно по одному TCP-соединению за счёт мультиплексирования. На мобильных сетях, где установка каждого нового TCP-соединения - это заметная задержка (handshake + TLS handshake), это ощутимо. По нашим замерам - время от запуска приложения до готового экрана сократилось примерно на 30%.

Оговорюсь сразу: цифра - это конкретный кейс, конкретное приложение, конкретная аудитория с определённым профилем сети. Бенчмарк «HTTP/2 быстрее HTTP/1.1 на X%» в вакууме - бессмысленный. Важно понять, есть ли у вас те самые условия: много мелких запросов, мобильная аудитория, задержки на установку соединений.

Почему HAProxy, а не nginx

Мы уже писали про nginx как TLS-терминатор - он там хорошо справляется. Но на этом клиенте HAProxy уже стоял как балансировщик перед nginx-бэкендами, и добавлять ещё один слой ради HTTP/2 не хотелось. HAProxy 1.6 решил вопрос: теперь он сам может терминировать HTTP/2 на фронтенде и проксировать дальше в HTTP/1.1.

Бэкенды при этом менять не нужно - они не знают про HTTP/2 и не должны. HAProxy транслирует. Это принципиально с точки зрения раскатки: обновили балансировщик, включили alpn h2, приложение не трогаем.

Что пришлось поменять в конфиге

Конфиг HAProxy 1.5 в целом совместим с 1.6, но для HTTP/2 нужно явно включить поддержку при сборке с USE_OPENSSL=1 и указать протоколы в bind. Вот что изменилось в нашем фронтенд-блоке:

frontend public_api
    bind *:443 ssl crt /etc/haproxy/certs/api.pem alpn h2,http/1.1
    mode http
    option forwardfor
    option http-server-close
    default_backend api_servers

backend api_servers
    balance roundrobin
    option http-server-close
    server app1 10.0.1.10:8080 check
    server app2 10.0.1.11:8080 check

alpn h2,http/1.1 - это TLS ALPN-расширение, которое говорит клиенту «я умею HTTP/2 и HTTP/1.1, выбирай». Браузеры и современные HTTP-клиенты выбирают h2. Старые клиенты без ALPN получают HTTP/1.1 как и раньше. Обратная совместимость полная.

option http-server-close на бэкенде - важная деталь. HAProxy не держит постоянных соединений к бэкендам при этой опции, что при HTTP/2 на фронтенде означает: один клиент с мультиплексированием не монополизирует соединение к бэкенду.

SSL offloading: что улучшилось

В 1.6 переработали обработку SSL-сессий. Конкретно - появилась поддержка общего кеша SSL-сессий через tune.ssl.cachesize и tune.ssl.lifetime, что при нескольких процессах HAProxy (несколько CPU) позволяет не делать полный TLS handshake при переключении между процессами.

На нашей установке - 4 процесса, трафик балансируется между ними. До 1.6 часть клиентов при попадании на другой процесс делала повторный handshake. Сейчас сессия резьюмится. На нагруженных API с мобильными клиентами, которые переподключаются часто, это снижает CPU на балансировщике.

Также появилась директива ssl-dh-param-file для явного задания параметров DH под Diffie-Hellman key exchange - раньше HAProxy использовал встроенные параметры 1024 бит, что для 2015 года уже не очень. Сгенерировали 2048-битные, подключили.

Что осталось на nginx

Nginx никуда не делся - он стоит за HAProxy и отдаёт статику, проксирует на приложение. HTTP/2 с клиентом разговаривает HAProxy, nginx получает HTTP/1.1. Это нас устраивает: разделение ответственности понятное, отлаживать проще.

Если бы задача была проще (один инстанс, без L4-балансировки, только статика + проксирование), мы бы, наверное, обошлись nginx 1.9.5, у которого HTTP/2 тоже уже есть. Но там свои нюансы с конфигурацией сети на уровне ядра, и в связке HAProxy + nginx всё оказалось аккуратнее.

Текущее состояние

Раскатка прошла без даунтайма - HAProxy в 1.6 меняли через systemctl reload, конфиг проверяли через -c. На мобильных клиентах разница в скорости загрузки заметна, метрики собираем, через пару недель будет более полная картина по p95/p99 latency.

HAProxy 1.6 в целом выглядит как аккуратный релиз - API конфига не сломан, апгрейд без сюрпризов. Для managed-инфраструктуры это именно то, что нужно: новые возможности, которые можно включить поверх существующей конфигурации, без переписывания всего с нуля.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.