← К библиотеке
Каскады Теория

Балансеры и автовыбор: как это работает

«Автовыбор» звучит просто, а на деле это четыре разных уровня и минимум пять стратегий, которые оптимизируют разное. И одна из них, самая популярная, под ТСПУ предсказуемо ломается. Разберу, где живёт балансировка, чем стратегии отличаются и почему leastPing «работает пару минут, потом заглохает». Без конфигов.

Перейти к практике

Две задачи балансировки

Балансировка решает не одну задачу, а две сразу, и их полезно держать в голове раздельно:

  1. Раздать нагрузку — чтобы клиенты не толпились на одной ноде, пока другие простаивают.
  2. Пережить падение — чтобы блок или смерть одной ноды не уронили сервис.

Разные механизмы решают эти задачи по-разному, и «автовыбор» на клиенте — только один из уровней. Всего их четыре, от клиента до транспортного фронта.

Четыре уровня

Уровень 1 — Xray-балансеры (серверные). Внутри одного Xray несколько выходных аутбаундов собираются в пул, и правило роутинга шлёт трафик не на конкретный outbound, а в балансер, который сам выбирает члена пула. Это то, что делает «нода веером на несколько выходов».

Уровень 2 — клиентский балансер через подписку. В подписку кладётся несколько серверов, и клиент сам тестирует их и выбирает быстрейший (канон — sing-box urltest, у Hiddify это «Auto»). Минус: бесшовного failover посреди соединения нет — при обрыве клиент перетестирует и переподключится.

Уровень 3 — транспортный фронт (HAProxy/nginx). L4-балансер перед нодами, который маршрутизирует по SNI, не расшифровывая TLS (Reality остаётся целым). Самый надёжный для коммерции. Важное ограничение: по SNI так балансируется только TCP — Hysteria2 (QUIC/UDP) этим способом не раскидать.

Уровень 4 — DNS round-robin / GeoDNS. Один домен → несколько A-записей. Работает для любого протокола, но грубо: нет проверки здоровья (мёртвая нода висит в ротации до правки DNS), а DNS вдобавок спуфят/блокируют. Только как крайний случай и грубое гео-направление, не как failover.

Четыре стратегии Xray-балансера

Внутри серверного балансера выбор члена пула определяет стратегия, и их четыре:

  • random — случайно. Дефолт, годится для однородных нод.
  • roundRobin — по кругу, поровну.
  • leastPing — наименьший пинг. Нужен наблюдатель (observatory), который периодически пингует членов пула.
  • leastLoad — стабильнейший под нагрузкой. Смотрит не на одну пробу, а на распределение задержек (baselines).

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

Почему leastPing «работает → заглохает»

Это самая частая жалоба, и она не случайна, а заложена в конструкцию. Разбираю по шагам, потому что понимание тут стоит дороже любого готового конфига:

  • leastPing выбирает член пула с минимальным пингом. В пуле обычно есть голый raw-TCP+Reality+Vision — у него минимальный фрейминг, значит минимальный пинг → leastPing всегда выбирает именно его.
  • ТСПУ по этому транспорту душит полосу — не рвёт коннект, а зажимает скорость почти в ноль.
  • А наблюдатель пингует крошечный generate_204 раз в несколько десятков секунд — и эта мелкая проба проходит даже на задушенном канале. Для балансера член выглядит здоровым.
  • Итог: leastPing никогда не понижает этот раздавленный raw-член, потому что по пробе он «быстрый». Реальная скорость — ноль. «Работает → заглохает».
  • Перезапуск приложения помогает случайно: новый коннект садится на ещё живой транспорт.

Замер это подтверждает: один и тот же ключ, серия проб connect→speedtest→hold — у vision-on-raw около трети удачных, у gRPC почти все. Отсюда две мысли, которые лечат балансер.

Что с этим делать (идеи, не команды)

  • Убрать raw+Vision из пула — оставить gRPC/xHTTP-члены. raw переживает блок хуже всех.
  • leastLoad вместо leastPing — он смотрит на распределение задержек, а не на мелкую пробу, и раскидывает шире, не залипая на одном раздавленном члене.
  • Прямые ноды в дефолтном пуле, каскад — в резерв. Каскад душит upload; для основного пула быстрее прямые ноды, каскад держат как обход/fallback.
  • Блок QUIC перед правилом балансера, иначе видео залипает в туннеле.

Что выбрать под VPN-сервис

Стратегии оптимизируют разное, и универсальной нет:

  • Failover (HAProxy/nginx backup) — про аптайм: основные ноды плюс горячий резерв, с проверкой здоровья.
  • Least-conn — про длинные сессии: у VPN соединения долгие, round-robin перегрузит «счастливчика», а least-conn раздаёт по числу активных.
  • Least-ping — про скорость для юзера в мультирегионе, но с оговоркой про залипание выше.
  • Least-load — про стабильность под нагрузкой и всплесками на разнокалиберных нодах.
  • Source-hash — про липкость: держит TCP и UDP одного клиента на одной ноде.

Рабочая связка для коммерции: фронт HAProxy/nginx по SNI + least-conn + backup-ноды (failover и длинные сессии), сверху клиентский urltest (юзер берёт быстрейший регион), а Xray leastLoad — когда одна нода веером уходит на несколько выходов.

Про здоровье нод

Одна ловушка, которую надо знать заранее: серверный observatory пингует с самой ноды, а нода может быть жива в мире, но зарезана для российских клиентов. Такую проблему observatory не увидит. Значит проверять здоровье надо из РФ, отдельным внешним воркером, а не только глобально. Это отдельная тема — вынесена в практику про healthcheck.

Дальше — в практике: как собрать боевой leastPing/leastLoad автовыбор, как задаётся пул тегами хостов и главные грабли доставки шаблона. Пошагово — в статье «Автовыбор leastPing: собираем».

Следующий гайд Автовыбор leastPing: собираем → Не понравилась статья или что-то непонятно? Напишите мне — помогу или поправлю. @notrealvpn →
Материал носит образовательный характер и посвящён инженерии сетевой инфраструктуры. Вы отвечаете за соблюдение законов своей юрисдикции.