SSH и высокая задержка: почему привычный протокол плохо масштабируется через WAN

795
SSH и высокая задержка: почему привычный протокол плохо масштабируется через WAN

Есть протоколы, недостатки которых проявляются сразу. У SSH всё наоборот. На одном сервере, в локальной сети или при ручном администрировании почти невозможно заметить архитектурную особенность, которая становится дорогой при работе через WAN. SSH требует серии последовательных обменов до того момента, когда приложение получает возможность выполнить полезную работу.

Именно последовательность здесь важнее объёма трафика. Можно иметь канал на гигабит, отправлять команды размером в десятки байт и всё равно ждать секунды. Если удалённая площадка находится в 150 мс RTT, каждый дополнительный цикл «отправил запрос, дождался ответа» превращается в заметную паузу. Для одного администратора пауза терпима. Для системы, которая регулярно опрашивает тысячи маршрутизаторов, коммутаторов и межсетевых экранов, задержка превращается в часть архитектуры.

SSH тратит время ещё до первой полезной команды

Когда пользователь запускает:

ssh admin@router.example

визуально кажется, что клиент просто «подключается». На самом деле до приглашения командной строки происходит целая цепочка событий.

Сначала TCP создаёт соединение. Затем стороны сообщают версии SSH, договариваются об алгоритмах, проводят обмен ключами, проверяют сервер, включают шифрование, переходят к аутентификации пользователя и открывают канал. Если клиенту нужен интерактивный терминал, добавляются запрос псевдотерминала и запуск оболочки.

Сетевые средства автоматизации часто идут дальше. После подключения программа ждёт приглашение CLI, определяет режим устройства, отключает постраничный вывод, иногда меняет ширину терминала и только затем отправляет команду, ради которой вообще создавалось соединение.

Исследование Бретта Лыкинса, представленное на NANOG 97, хорошо показало цену такой последовательности. В зависимости от сценария SSH требует примерно 6–10 сетевых обменов до рабочего канала, а полноценная интерактивная CLI-сессия с подготовкой терминала может приблизиться к 10–15 циклам обмена до результата первой команды. Подробное разложение автор приводит в своём эксперименте, а наблюдения с конференции независимо описаны в материале APNIC.

Цифры нельзя превращать в универсальное правило. SSH не обязан всегда тратить ровно 10 или 15 RTT. Количество обменов зависит от алгоритма обмена ключами, метода аутентификации, реализации сервера, необходимости PTY и поведения конкретного клиента.

Но сама зависимость никуда не исчезает. Чем больше последовательных стадий и чем дальше находится устройство, тем сильнее расстояние влияет на время запуска операции.

Для грубой оценки можно взять RTT, который показывает ping. Такой замер не равен задержке SSH один к одному, поскольку ICMP и TCP могут проходить и обрабатываться немного по-разному, но порядок величины понять позволяет.

RTT до устройства 10 последовательных обменов 15 последовательных обменов
5 мс 50 мс 75 мс
30 мс 300 мс 450 мс
100 мс 1 с 1,5 с
150 мс 1,5 с 2,25 с
250 мс 2,5 с 3,75 с

Таблица не показывает время выполнения команды, DNS, внешнюю AAA-аутентификацию, загрузку процессора маршрутизатора и потери пакетов. Реальная сессия может стартовать как быстрее, так и заметно медленнее.

Зато хорошо видно другое. Повышение пропускной способности почти не помогает. Если клиент обязан дождаться ответа перед следующим шагом, проблему определяет задержка, а не ширина канала.

Почему проблема почти незаметна человеку и хорошо видна автоматике

Представим инженера, который подключается к удалённому маршрутизатору один раз и работает внутри SSH-сессии десять минут. Даже две секунды на первоначальное соединение почти ничего не меняют. После установки защищённого канала команды выполняются внутри уже существующей сессии.

Теперь поменяем сценарий. Центральная платформа каждые несколько минут собирает показатели с 5000 устройств. Скрипт подключается, выполняет одну или две команды, забирает вывод и закрывает соединение.

Такой дизайн каждый раз заново оплачивает TCP, SSH handshake, аутентификацию и подготовку оболочки. При большой географии инфраструктуры стоимость начинает определять уже не команда, а запуск сессии.

Можно просто открыть сотни соединений параллельно. Подход действительно сокращает общее время обхода сети, но переносит нагрузку в другое место. Система получает множество одновременных обменов ключами, SSH-процессов, сессий AAA и открытых TCP-соединений. У части сетевого оборудования лимиты на управляющие сессии довольно скромные, а управляющий процессор обычно не рассчитан на поведение, похожее на сервер приложений.

Есть и другая проблема, не связанная напрямую с RTT. CLI создавался для человека.

Автоматизатор обычно получает не аккуратную структуру данных, а текст:

router01# show interface status
 ... 
 router01#

Программе приходится понимать, где закончился вывод, распознавать приглашение оболочки, учитывать разные режимы конфигурации, выключать пагинацию и обрабатывать вопросы подтверждения. Изменение формата CLI после обновления прошивки способно сломать парсер, хотя данные на устройстве остались теми же.

Поэтому сравнивать SSH и API только по времени установления соединения слишком узко. Машинные интерфейсы выигрывают ещё и тем, что возвращают структурированные данные и дают приложению явные границы запроса и ответа.

REST здесь не волшебная таблетка

На первый взгляд решение очевидно. Берём HTTPS и получаем намного более короткую процедуру установки соединения. Для нового TCP-соединения с TLS 1.3 грубая схема выглядит так:

TCP                        около 1 RTT
 TLS 1.3                    около 1 RTT
 HTTP-запрос и ответ         около 1 RTT

При RTT 150 мс первая операция в простом случае укладывается примерно в 450 мс. На фоне полутора или двух секунд SSH разница впечатляет.

Но вывод «REST быстрее SSH» слишком примитивен.

Если приложение создаёт новое HTTPS-соединение перед каждым запросом, не использует пул соединений и выполняет десятки мелких вызовов последовательно, задержки снова начинают складываться. Хорошая реализация HTTP обычно держит соединение открытым и отправляет через него множество запросов.

SSH умеет делать похожую вещь. Самая простая оптимизация старой системы состоит не в смене протокола, а в отказе от постоянного переподключения.

OpenSSH, например, поддерживает мультиплексирование:

Host router-*
     ControlMaster auto
     ControlPath ~/.ssh/cm-%C
     ControlPersist 10m

Первый сеанс проходит полную процедуру установления SSH. Последующие подключения используют уже созданный транспорт. В специализированных библиотеках тот же принцип реализуют через постоянные сессии и пулы соединений.

Поэтому я бы не начинал оптимизацию сетевой автоматики с лозунга «убираем SSH». Сначала полезнее снять трассировку и посмотреть, сколько соединений реально создаёт система.

Если одна сессия живёт долго и выполняет сотни операций, стартовый handshake почти перестаёт влиять на итоговое время. Если ради каждого show открывается новый SSH, программа сама создаёт основную часть проблемы.

Машинные протоколы тоже устроены разнообразнее, чем иногда представляют. RESTCONF обычно использует HTTP, gNMI работает поверх gRPC и HTTP/2, а NETCONF широко применяется поверх SSH. Переход от CLI к структурированному API вовсе не обязательно означает отказ от SSH как транспорта.

Поэтому я бы разделял две задачи. Первая заключается в снижении количества сетевых обменов. Вторая состоит в переходе от текстового интерфейса для человека к интерфейсу, который удобно обрабатывать программе.

Самый интересный вариант вообще не требует менять маршрутизаторы

Есть ещё один способ посмотреть на проблему. Если старое оборудование поддерживает только SSH, необязательно тянуть интерактивный SSH через всю страну.

Можно разместить управляющий шлюз рядом с устройствами:

Центральная система управления
              |
              | HTTPS / другой компактный протокол
              | WAN, RTT 100–200 мс
              |
              v
       локальный агент
              |
              | SSH
              | RTT 1–3 мс
              |
              v
        сетевое оборудование

Устройство продолжает работать ровно так же, как раньше. Изменяется место, где запускается SSH. Многоступенчатый диалог происходит внутри площадки с минимальным RTT, а по дорогому WAN-участку передаются уже более крупные запросы и ответы.

Такой приём интересен ещё и тем, что хорошо работает с устаревшим оборудованием. Не нужно ждать новую прошивку с REST API или менять парк маршрутизаторов только ради автоматизации.

Цена тоже есть. Локальный агент становится привилегированным компонентом. Компрометация такого узла может дать атакующему доступ сразу к группе сетевых устройств. Придётся отдельно решать хранение ключей, разграничение полномочий, журналирование, обновления и отказоустойчивость.

SSH, туннели, прокси и удалённое управление нужно применять только в собственной инфраструктуре или с разрешения её владельца. Следует соблюдать законодательство своей страны, включая требования России, и правила используемых сервисов. Такие механизмы нельзя применять для несанкционированного доступа, слежки, взлома или незаконного обхода ограничений.

Для меня главный вывод из всей истории вообще не про недостатки SSH. Гораздо полезнее смотреть на протокол как на последовательность ожиданий.

На локальной сети один дополнительный RTT почти ничего не стоит. Между Москвой и удалённой площадкой, дата-центрами на разных континентах или через спутниковый канал тот же обмен превращается в десятки или сотни миллисекунд. Если приложение повторяет такой цикл много раз, время складывается независимо от мощности серверов и пропускной способности линии.

Поэтому при проектировании распределённого мониторинга я бы сначала считал не мегабиты, а количество последовательных запросов. Затем проверил бы, можно ли держать соединения открытыми, объединять несколько операций в один запрос или перенести разговорчивую часть протокола ближе к оборудованию.

SSH после такого анализа нередко остаётся на месте. Просто перестаёт использоваться как одноразовый транспорт для каждой мелкой операции. Именно такой случай хорошо показывает разницу между протоколом, удобным человеку, и архитектурой, которая должна работать в масштабе.

Alt text
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.
серая зона: медицина / допинг
Эффект есть.
Вопрос — чем за него платить
Открыть разбор
в разборе:
  • кофеин
  • модафинил
  • метилфенидат
  • фенилпирацетам
  • креатин
  • мелатонин
Реклама