TLS-терминация: цена шифрования и оптимизация
TLS-терминация снимает шифрование с приложения, но не делает его бесплатным: CPU уходит на рукопожатия, память — на соединения, а неверная настройка добавляет задержки. Разбираем, что измерять и где оптимизировать.

TLS-терминация редко становится причиной проблем на стенде, но под нагрузкой быстро превращается в отдельный потребитель CPU и памяти. Особенно дорого обходятся не сами зашифрованные байты, а новые TLS-рукопожатия: если клиент открывает соединение на каждый запрос, балансировщик тратит ресурсы на криптографию вместо обработки трафика. Ниже — разбор для связки с TLS 1.3, OpenSSL 3.x и современным reverse proxy: где возникает цена, как её измерить и какие оптимизации не ломают безопасность.
Что именно оплачивает сервер
При TLS-терминации внешний прокси принимает HTTPS, расшифровывает запрос и передаёт дальше уже обычный HTTP или новый зашифрованный поток. Терминация может находиться на CDN, внешнем балансировщике, ingress-контроллере Kubernetes или на самом Nginx перед приложением.
У операции три разных вида затрат:
- Рукопожатие. Сервер согласует версию протокола, набор алгоритмов и ключи с клиентом. В TLS 1.3 полное рукопожатие обычно требует одного сетевого обмена между клиентом и сервером, но всё равно включает операции с открытым ключом.
- Шифрование записей. После установления сессии данные обрабатываются симметричным алгоритмом. На современных CPU это обычно дешевле рукопожатия, но стоимость растёт вместе с пропускной способностью.
- Состояние соединений. Каждая активная TCP- и TLS-сессия занимает память, файловые дескрипторы и служебные структуры прокси.
Поэтому два сервиса с одинаковым объёмом трафика могут иметь совершенно разную нагрузку. Сервис с длинными keep-alive-соединениями редко устанавливает TLS заново. Сервис с короткими соединениями платит за рукопожатие снова и снова.
Главная единица цены TLS — не только мегабайт трафика, но и число новых защищённых соединений в секунду.
Сессия TLS — состояние, позволяющее клиенту продолжить ранее установленное защищённое взаимодействие без полного рукопожатия. В TLS 1.3 для этого используются механизмы resumption и PSK (pre-shared key), а не повторная передача исходного закрытого ключа.
Где появляется узкое место
Рукопожатия против полезного трафика
На графике CPU TLS-нагрузка часто выглядит неожиданно: передача большого ответа может быть дешёвой, а короткие запросы с большим числом новых клиентов — дорогими. Поэтому показатель «гигабайты в секунду» без показателя «новые TLS-соединения в секунду» мало что говорит.
Для диагностики разделяйте как минимум:
- общее число активных TCP-соединений;
- число новых TCP-соединений в секунду;
- число новых TLS-рукопожатий в секунду;
- долю возобновлённых TLS-сессий;
- CPU отдельно на reverse proxy и на приложении;
- p95 и p99 времени установления соединения;
- ошибки handshake и разрывы соединений.
Если CPU растёт вместе с числом новых рукопожатий, увеличение количества worker-процессов само по себе проблему не решит. Оно может только распределить ту же работу по ядрам и быстрее упереться в общий лимит CPU.
Почему шифрование не всегда виновато
Прокси одновременно принимает TCP, ведёт TLS, разбирает HTTP, выбирает upstream и может выполнять компрессию. Высокая загрузка процесса не доказывает, что дорогим оказался именно TLS. Нужны раздельные метрики и контрольный тест: тот же маршрут с заранее прогретыми соединениями и тот же маршрут с принудительным созданием новых соединений.
Проверять стоит в условиях, близких к боевым: та же версия OpenSSL, те же типы сертификатов, число ядер, размер ответа, HTTP/1.1 или HTTP/2, а также реальная доля повторных подключений. Результат теста без этих условий нельзя переносить на продакшен.
Четыре рычага оптимизации
1. Уменьшить число новых соединений
Самый дешёвый TLS — тот, который не пришлось устанавливать заново. Долгоживущие соединения, keep-alive и HTTP/2 позволяют отправить больше запросов через уже созданный защищённый канал. На практике сначала проверьте таймауты прокси, балансировщика и клиента: слишком короткий idle timeout может отменить эффект остальных настроек.
Цена подхода — открытые соединения дольше удерживают файловые дескрипторы и память. Если клиентов много, лимиты нужно считать вместе с очередями, upstream-соединениями и соединениями между прокси.
2. Включить возобновление сессий
TLS 1.3 поддерживает возобновление сессии, но результат зависит от конфигурации терминатора и поведения клиентов. В кластере важно учитывать распределение запросов между узлами: состояние, доступное только одному экземпляру, снижает долю успешных возобновлений при частом переключении между балансировщиками.
Ключи и параметры возобновления должны иметь контролируемый срок жизни. Слишком агрессивное обновление снижает пользу механизма, а бесконтрольное хранение общего состояния усложняет отзыв и ротацию.
3. Выбрать аппаратно подходящие алгоритмы
Для TLS 1.3 наборы шифров ограничены современными вариантами AEAD, поэтому главный вопрос — не поиск экзотического cipher suite, а поддержка аппаратного ускорения и корректная версия криптографической библиотеки. На x86 это обычно означает проверку доступности AES-инструкций; на других платформах набор ускорений будет иным.
Не отключайте проверку сертификатов и не снижайте уровень протокола ради красивого показателя CPU. Экономия, полученная ценой слабой криптографии, превращается в риск для всех данных, которые проходят через терминатор.
4. Разнести TLS-терминацию
Внешний CDN или выделенный балансировщик может снять криптографическую работу с web-узлов. Но это не бесплатный перенос: появляется стоимость сервиса, дополнительный сетевой участок и новый набор настроек доверия между компонентами. Если между балансировщиком и приложением используется незашифрованный HTTP, нужно отдельно оценить границы доверенной сети; для недоверенных или мультиарендных сегментов обычно требуется TLS и на внутреннем участке.
| Подход | Что выигрываете | Цена и риск | Когда проверять |
|---|---|---|---|
| Длинные соединения и HTTP/2 | Меньше новых рукопожатий | Больше активного состояния и дескрипторов | Много небольших запросов от одних клиентов |
| Возобновление TLS-сессий | Дешевле повторные подключения | Нужно согласовать поведение нескольких узлов | Клиенты часто переподключаются |
| Аппаратное ускорение | Ниже CPU-цена симметричного шифрования | Зависимость от CPU, OpenSSL и сборки | Большой объём зашифрованных данных |
| CDN или отдельный балансировщик | Разгрузка web-серверов | Цена сервиса и дополнительный участок сети | Публичный трафик и несколько web-узлов |
Что ломается первым
Короткий таймаут и лавина рукопожатий
Если timeout на одном участке меньше, чем у клиента или соседнего прокси, соединения будут закрываться раньше ожидаемого. Клиент откроет новое соединение, а сервер получит дополнительное рукопожатие. Внешне это может выглядеть как случайные задержки, хотя причина — постоянное пересоздание сессий.
Общее состояние между узлами
После добавления второго терминатора процент возобновления может измениться. Смотрите на него по каждому узлу и по маршруту клиента. Если один балансировщик принимает начальное соединение, а следующий — продолжение, локальное состояние должно быть либо согласовано, либо не быть обязательным для выбранного механизма.
Неправильная граница доверия
Передача от CDN к origin по HTTP не делает систему автоматически небезопасной и не делает её автоматически безопасной. Важны сеть, контроль маршрутов, доступ к origin и состав данных. Отдельно проверьте, кто может обращаться к origin напрямую, минуя внешний терминатор.
Попытка лечить TLS настройкой воркеров
Большое число worker-процессов не компенсирует нехватку CPU или медленную криптографическую библиотеку. Оно также может увеличить потребление памяти. Сначала определите, ограничивает ли систему CPU, число дескрипторов, пропускная способность сети или upstream.
Как измерять эффект без самообмана
Соберите базовую линию до изменения конфигурации. Зафиксируйте версию прокси и OpenSSL, тип CPU, число ядер, размер запроса и ответа, долю HTTP/1.1 и HTTP/2, число параллельных клиентов, TLS-протокол и долю новых соединений. Затем меняйте один параметр за раз.
- Запишите CPU, RSS, число открытых соединений и ошибки TLS на терминаторе.
- Проведите тест с долгоживущими соединениями.
- Проведите отдельный тест с частым закрытием и созданием новых соединений.
- Сравните p95 и p99 задержки, а не только среднее значение.
- Повторите тест после изменения таймаутов, возобновления или места терминации.
Замер «до и после» без одинаковой модели клиентов ничего не доказывает. Если не удаётся получить аппаратное ускорение или статистику возобновления, это нужно зафиксировать как ограничение эксперимента, а не заменять предположением.
Что делать дальше
Начните с графика новых TLS-рукопожатий в секунду и его связи с CPU терминатора. Затем проверьте keep-alive, долю HTTP/2 и успешность возобновления сессий. Только после этого сравнивайте перенос TLS на CDN или отдельный балансировщик. Для конкретных директив сверяйтесь с документацией вашей версии прокси и OpenSSL: названия параметров, значения по умолчанию и поддержка алгоритмов меняются быстрее, чем сама архитектура.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: Nginx HTTP SSL module documentation, RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
Частые вопросы
TLS-терминация всегда должна находиться на CDN?
Что сильнее влияет на CPU: шифрование или рукопожатия?
Стоит ли отключать TLS 1.2 ради производительности?
Почему после включения HTTP/2 CPU не снизился?
Опасно ли передавать трафик от балансировщика к приложению по HTTP?
Что проверять после переноса TLS на другой узел?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.