Если вы используете Nginx для терминации TLS-трафика, то можете улучшить время ответа сервера с помощью патчей от Cloudflare. Подробности под катом.
TLS и TCP
Как известно, данные в Интернете передаются с использованием многослойного стека протоколов. Сейчас нас интересует взаимодействие TCP и TLS. Основная задача TCP — надёжная доставка пакетов в исходном порядке. Если у нас есть сервис, использующий TLS (HTTPS-сайт), то все зашифрованные TLS данные будут отправляться с помощью TCP.
На уровне TCP: cразу после подключения, сервер может отправить не больше, чем initcwd пакетов (для старых систем это 3 пакета, для новых — 10). Далее сервер будет ждать подтверждения (ACK) от клиента и постепенно количество пакетов в окне отправки будет расти, а соединение будет увеличивать свою пропускную способность.
В случае с обычным HTTP-трафиком все отлично: с каждым новым пакетом приходят данные, которые браузер может использовать.
Проблема c TLS
Если мы используем TLS, то Nginx использует специальный буфер (размер задаётся директивой ssl_buffer_size), который управляет размером TLS record size. Браузер (клиент) может использовать данные только после получения TLS record полностью. При этом максимальный (и дефолтный в Nginx) размер ssl_buffer_size составляет 16k.
Так как начальное окно для отправки пакетов = 10, то мы можем получить примерно 14k трафика, что меньше TLS record (16k). Это может вызывать задержки в получении полезного контента.
А если вы используете HTTP/2, то стоит обратить внимание на настройку http2_chunk_size (по умолчанию 8k) — она устанавливает максимальный размер части, на которое делится тело ответа. При этом используется только одно подключение к серверу, поэтому в этом TCP соединении передаётся одновременно множество ресурсов, что увеличивает вероятность возникновения задержек.
Что можно сделать?
Самое простое, что можно сделать — уменьшить ssl_buffer_size, например до 8k или 12k. Это можно сделать в стандартной версии Nginx. Однако, при пересылке большого количества данных эффективность будет ниже (выше накладные расходы).
Получается, что идеального ssl_buffer_size не существует.
Динамический размер TLS record
Здесь на помощь приходит Cloudflare со своим набором патчей.
С использованием этих патчей мы получаем поддержку динамического размера TLS record.
На свежих соединениях размер записи устанавливается не больше размера одного пакета, после прохождения некоторого количества записей размер можно увеличить до 3 TCP-пакетов, а далее уже до максимального размера (16k). После простоя соединения процесс начинается снова. Все параметры этого процесса настраиваются.
Применение патчей
Чтобы получить новую функциональность, нужно применить патчи и собрать Nginx. О сборке Nginx с OpenSSL я уже писал ранее, поэтому остановимся на процессе применения патчей.
Для применения патчей нужно зайти на страницу github.
На этой странице нужно вычленить отдельные патчи для каждого файла. Запись самого патча начинается так:
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
Из этой записи понятно, к чему относится этот патч (в данном случае это src/event/ngx_event_openssl.c).
Копируем текст патча в файл (например, openssl.c.patch) и кладём рядом с файлом исходника.
Применяем патч следующей командой:
patch ngx_event_openssl.c < openssl.c.patch
Так проходимся по всем файлам патча (всего должно быть 4 файла).
Ну и собираем Nginx как обычно (я использовал 1.11.2, всё получилось).
Настройка Nginx
С патчем приходят новые настройки. Получаем примерно такие значения:
# Начальный размер записи, примерно 1 пакет
ssl_dyn_rec_size_lo 1369;
# Промежуточный размер записи, 3 пакета
ssl_dyn_rec_size_hi 4229;
# Количество записей для перехода к следующему размеру
ssl_dyn_rec_threshold 20;
# Время простоя для сброса размера до начального
ssl_dyn_rec_timeout 10;
# Стандартный буфер, ставим максимальное значение
ssl_buffer_size 16k;
Подробно можно почитать в исходной статье блога Cloudflare.
О самом принципе оптимизации TLS record size можно почитать в книге HPBN.
На этом у меня всё, пока внедрили у себя, тестируем. Если у вас уже есть опыт настройки, просьба поделиться в комментариях.
Автор: Nickmob