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

При росте нагрузки HTTPS-сервис может начать отдавать 502 и увеличивать задержку ещё до того, как приложение упрётся в CPU. Первым обычно ломается не само шифрование, а один из соседних ресурсов: TLS-рукопожатия съедают процессор, балансировщик исчерпывает соединения, а повторное шифрование между прокси и бэкендом удваивает работу. Ниже — разбор для Linux, Nginx 1.25+ и OpenSSL 3.x с TLS 1.2/1.3: что измерять, где находится настоящая цена TLS и как не лечить её увеличением числа серверов вслепую.
Из чего складывается цена TLS
У HTTPS есть несколько разных расходов, и их нельзя смешивать в один показатель «CPU на шифрование». Криптография выполняется в разных точках запроса и с разной частотой.
- Рукопожатие. Клиент и сервер договариваются о версии протокола, наборе алгоритмов и ключах. Это дорогая операция, которая происходит при создании соединения.
- Шифрование записей. После рукопожатия HTTP-данные шифруются блоками. При долгоживущем соединении TLS 1.3 стоимость этого этапа обычно распределяется по большему числу запросов.
- Проверка сертификата. Клиент может проверять цепочку сертификатов и статус отзыва. На стороне сервера важнее не столько эта проверка, сколько подготовка и отправка полной цепочки.
- Проксирование. Если TLS завершается на балансировщике, он расшифровывает входящий поток. При новом TLS-соединении до приложения тот же узел или соседний прокси снова шифрует данные.
Ключевой параметр — не только количество HTTP-запросов в секунду, но и число новых TLS-соединений в секунду. Тысяча запросов в секунду по нескольким долгоживущим соединениям и тысяча коротких соединений — это разные нагрузки.
Смотрите на TLS как на конвейер: рукопожатия нагружают CPU рывками, шифрование записей расходует CPU пропорционально трафику, а прокси добавляет очереди и копирование данных.
Сноска. TLS-терминация — точка, в которой прокси или балансировщик принимает HTTPS, расшифровывает запрос и передаёт его дальше. Если внутренний участок тоже защищён HTTPS, это уже отдельная TLS-сессия, а не продолжение клиентской.
Что ломается первым
1. CPU на рукопожатиях
Первый симптом — растёт время установления соединения, хотя обработка самого HTTP-запроса остаётся быстрой. На графиках появляются всплески CPU, увеличивается доля системного времени, а клиенты начинают получать тайм-ауты на этапе подключения. Такое часто происходит при отключённом keep-alive, агрессивном health check или за балансировщиком, который не сохраняет соединения с клиентами.
TLS 1.3 сокращает число сетевых обменов по сравнению с прежними сценариями TLS 1.2, но не делает новые соединения бесплатными. Повторное подключение всё равно требует криптографических операций и выделения ресурсов. Сессионное возобновление снижает стоимость повторных подключений, однако его эффективность зависит от клиента, настроек прокси и того, сохраняется ли состояние, необходимое для возобновления.
2. Очередь соединений и исчерпание дескрипторов
Если CPU ещё не достиг предела, а новые клиенты получают connection timeout или 502, проверьте число открытых файлов, очередь accept и лимиты самого балансировщика. TLS-терминация держит состояние соединения дольше, чем обычный короткий TCP-прокси: нужны сокеты, буферы, структуры сессии и память под незавершённые рукопожатия.
Опасный сценарий — всплеск новых подключений. Даже если средняя нагрузка за минуту выглядит нормальной, короткий пик может заполнить очередь и оставить приложение без новых соединений. В этот момент увеличение worker-процессов Nginx не всегда помогает: каждый процесс также потребляет дескрипторы и память.
3. Бэкенд получает больше соединений, чем может обработать
Терминация на внешнем прокси позволяет клиентам держать долгие HTTP/2-соединения, но это не означает, что к приложению можно бесконечно открывать новые HTTP/1.1-соединения. Если прокси не использует подходящий keep-alive к upstream, число соединений между слоями растёт, а приложение тратит ресурсы на их создание и закрытие.
Признак — внешний TLS-слой отвечает быстро, но время ожидания upstream увеличивается. В журналах прокси полезно разделять время получения заголовков от общего времени запроса. Иначе задержка бэкенда выглядит как «медленный HTTPS», хотя криптография уже завершилась.
4. Двойная терминация и лишнее копирование
Схема «клиент — CDN — балансировщик — сервис» может содержать две или три TLS-сессии. Это оправдано, если внутренний трафик проходит через недоверенную сеть или нужны отдельные границы доступа. Но в закрытом сегменте без ясной модели угроз вы платите дополнительным CPU, задержкой, памятью и усложнением сертификатов.
Не следует автоматически отключать внутреннее шифрование: доступ к сети не равен доверию к каждому узлу. Сначала зафиксируйте, какие данные проходят между компонентами, кто может прослушивать сегмент и какие требования предъявляет аудит. Оптимизация не должна превращаться в потерю конфиденциальности.
Три схемы терминации и их цена
| Схема | Что выигрывает | За что платите | Где искать узкое место |
|---|---|---|---|
| TLS на внешнем балансировщике | Централизованные сертификаты, меньше криптографической работы на приложениях | Балансировщик становится критической точкой и должен выдерживать пики | CPU, новые соединения, лимиты сокетов и очереди |
| TLS на каждом приложении | Шифрование сохраняется до конечного сервиса, меньше доверия к прокси | Сертификаты и настройки размножаются по узлам | CPU приложений, распределение сертификатов, число соединений |
| Двойная терминация на внешнем и внутреннем прокси | Отдельные зоны доверия и шифрование между сегментами | Две сессии, больше рукопожатий, буферов и точек отказа | Очереди между слоями, upstream keep-alive, CPU обоих прокси |
Выбор определяется не скоростью шифрования в вакууме, а границами доверия. Для одного закрытого кластера централизованная терминация может быть проще. Для нескольких зон, разных команд и чувствительных данных внутренний TLS часто оправдан, но его нужно считать как отдельный слой нагрузки.
Как измерять, а не угадывать
До изменения конфигурации зафиксируйте базовую линию. Нужны как минимум продолжительность теста, число одновременных клиентов, доля новых соединений, размер ответа, версия TLS, HTTP/1.1 или HTTP/2, тип виртуальной машины и число ядер. Без этих условий цифры «TLS добавил 10% CPU» ничего не значат.
- Разделите новый трафик и повторные запросы. В одном тесте используйте долгоживущие соединения, в другом — короткие. Сравнивайте p50, p95 и p99 задержки, а не только среднее значение.
- Снимите профиль CPU по процессам. Отдельно смотрите прокси, приложение и системное время. Если прокси упирается в CPU при малом upstream-time, проблема находится до приложения.
- Проверьте соединения по каждому участку. Считайте клиентские и upstream-соединения отдельно. Большое число входящих HTTP/2-сессий не должно автоматически превращаться в такое же число соединений к приложению.
- Измерьте память и дескрипторы. Наблюдайте открытые файлы, ошибки accept, размер очередей и число соединений в состояниях ожидания. Следите за моментом, когда растёт latency до исчерпания CPU.
- Повторите тест после одной перемены. Сначала включите или проверьте keep-alive, затем отдельно оцените TLS-сессию и только после этого меняйте число worker-процессов. Иначе вы не узнаете, что именно сработало.
Для локальной оценки криптографической части применяйте инструменты бенчмаркинга OpenSSL подходящей версии, а для реального вывода — нагрузочный тест через тот же прокси и с теми же сертификатами. Синтетический тест алгоритмов не учитывает очереди сокетов, HTTP/2, журналирование и задержку приложения.
Граничные случаи и типичные ошибки
- Тест идёт из одного клиента. Он может стать узким местом раньше сервера. Используйте несколько источников нагрузки или убедитесь, что генератор не ограничивает число соединений.
- Сертификатная цепочка неполная. Часть клиентов подключается, часть — нет. Сервер должен отправлять корректную цепочку, а не только сертификат сайта. Проверяйте это отдельными клиентами и средствами диагностики TLS.
- Сессионное возобновление принимают за keep-alive. Возобновление удешевляет новое TLS-рукопожатие, но не заменяет повторное использование уже открытого TCP-соединения.
- HTTP/2 включён только снаружи. Это может сократить число клиентских соединений, но не решает проблему, если прокси создаёт новое соединение к upstream для каждого запроса.
- Аппаратное ускорение считают гарантированным. Наличие инструкций CPU или ускорителя не означает, что конкретная сборка OpenSSL, виртуальная машина и путь данных используют их эффективно. Это нужно проверять измерением.
Есть и пределы оптимизации. Если задержка растёт из-за блокировки базы данных или внешнего API, ускорение TLS почти не изменит p99. Если же проблема вызвана штормом новых соединений, увеличение пропускной способности канала тоже не поможет: узкое место находится в рукопожатиях, очереди или лимитах процессов.
Что проверить следующим шагом
Начните с графика новых TLS-соединений в секунду рядом с CPU прокси, количеством открытых дескрипторов и временем до первого байта от upstream. Затем сравните два сценария: долгоживущие соединения и короткие подключения. Если разница большая, сначала исправляйте жизненный цикл соединений и настройки проксирования, а не покупайте более мощный сервер.
После этого отдельно решите вопрос внутреннего TLS: какие сегменты должны быть зашифрованы, где хранятся сертификаты, как выполняется их ротация и какой запас CPU нужен на пиковую долю новых соединений. Под нагрузкой наблюдайте не только среднее CPU, но и p99 задержки, ошибки рукопожатия, тайм-ауты upstream и заполнение очередей. Именно эти показатели показывают, что сломается следующим.
Создатель презентаций: Структура и текст каждого слайда: заголовки-утверждения, одна мысль на слайд, заметки докладчику.
Спросить за 150 ₽Источники: Nginx HTTP SSL module documentation, OpenSSL speed command documentation
Частые вопросы
TLS всегда заметно замедляет сервис?
Что обычно ломается раньше: CPU или сеть?
Нужно ли шифровать трафик между балансировщиком и приложением?
Поможет ли увеличить число worker-процессов Nginx?
Что делать, если после оптимизации TLS всё ещё растёт p99?
Можно ли оценить эффект TLS только по тесту OpenSSL?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.