На схеме два узла, оба зелёные. Один обслуживает офисную сеть, второй стоит рядом на случай беды. Выглядит спокойно, и именно здесь начинается самообман: зелёный цвет говорит, что узел на связи с управляющей частью. О том, переживёт ли ваш открытый сеанс отключение одного из них, он не говорит ничего. Это придётся выяснять опытом, и ниже описано, как поставить такой опыт, чтобы получить не ощущение, а наблюдение.
Второй путь и живое соединение — разные вещи
Начнём с различия, на котором держится вся проверка. Наличие второго routing peer означает, что у клиента есть запасной маршрут до сети. Восстановление соединения приложения означает, что пользователь, который час сидел в SSH или держал открытую выгрузку, продолжил работу без вмешательства. Первое не влечёт второго.
Документация NetBird о routing peers описывает это прямо. Одну сеть могут обслуживать несколько routing peers, выбор между ними делает клиент, а предпочтение отдаётся меньшей metric. То есть без вашего участия никто не «распределяет нагрузку»: это режим переключения, а не раздачи одного потока двум узлам. Там же сказано, что при masquerade переключение сбрасывает установленные TCP-соединения, и приложениям приходится подключаться заново. Для рекомендаций по размещению упомянуты разные failure domains.
Из этого получается рабочая гипотеза, которую и стоит проверять: новые подключения после отказа должны пойти через второй узел, а уже открытые TCP-сеансы, скорее всего, оборвутся. Вопрос не в том, верить ли этому, а в том, как это выглядит у вас: как быстро клиент перестраивается, как ведёт себя ваше приложение при обрыве, нужно ли что-то переподключать руками.
Что вообще наблюдать
Фраза «проверим отказоустойчивость» слишком широка, чтобы её измерять. Разные сервисы по-разному реагируют на потерю пути, поэтому выберите два принципиально разных наблюдаемых объекта.
- Короткий запрос. Например, HTTP-запрос к внутреннему сервису, который отвечает и закрывает соединение. Каждый запрос — новое подключение, и он должен подхватить новый маршрут сам.
- Длительный сеанс. Например, SSH на внутренний хост с запущенной командой, выводящей время раз в секунду, либо долгая передача файла. Это одно TCP-соединение, которое живёт долго и потому особенно чувствительно к смене узла.
Если у вас есть третий тип — база данных с пулом соединений, RDP, бухгалтерская программа с постоянным каналом — добавьте и его отдельной строкой. Каждый тип отвечает на свой вопрос, и усреднять их нельзя: пока веб-запросы «выживают», SSH может обрываться, а пул соединений зависеть от того, как клиентская библиотека реагирует на разрыв.
Для каждого объекта заранее решите, что считать «восстановлением». Для короткого запроса — первый успешный ответ после отключения. Для SSH — либо продолжение той же сессии, либо необходимость войти заново. Для передачи файла — докачка с места обрыва или повтор с начала. Не придумывайте ожидаемых цифр: никаких «обычно две-три секунды» здесь быть не должно, значения вы получите сами.
Разберём на условном примере (это не результат замера, а иллюстрация того, как читать журнал). Допустим, цикл коротких запросов печатает строку каждую секунду, а SSH-сеанс выводит время с тем же шагом. После отключения основного узла в журнале запросов появляется несколько строк с ошибкой, затем снова идут коды 200. В журнале SSH последняя метка времени остановилась ровно в момент отключения и дальше не движется. Это две разные картины одного события: запросы открывают новое соединение при каждой итерации и потому находят рабочий путь, как только клиент его выбрал, а SSH держится за одно соединение, которое при смене узла может быть сброшено.
Поэтому в журнале нужны минимум три отметки на каждый объект: момент отключения, момент последнего успешного обмена и момент первого успешного обмена после перерыва. Разность первой и второй показывает, насколько быстро проявился отказ, разность второй и третьей даёт длину перерыва. Для SSH добавляется четвёртая отметка: когда вы сами поняли, что сеанс мёртв. Без неё вы не отличите быстрое обнаружение обрыва от долгого ожидания в пустоту.
Сначала убедитесь, какой узел сейчас главный
Частая ошибка — отключить узел, который трафик и так не использовал. Тогда всё «прекрасно работает», и вы делаете вывод о надёжности, хотя ничего не проверили. Поэтому первый шаг — выяснить исходный маршрут.
Клиент выбирает узел по metric: меньшая предпочтительнее. Выпишите значения для обоих routing peers в настройках сети и определите, какой из них ожидаемо основной. Затем с клиентской машины проверьте, что работа идёт именно через него. Способ зависит от вашей топологии: можно посмотреть адрес источника в логах целевого сервиса или на самом узле заметить поток трафика стандартными средствами ОС. Выберите один и используйте его дважды: до и после.
Заодно проверьте то, что нередко упускают, — политики. По документации NetBird Networks, сеть объединяет ресурсы, routing peers и политики доступа, а ресурсом может быть один IP, CIDR или домен. Доступ к ресурсу за routing peer требует разрешающей политики, и ресурс можно ограничить одним хостом вместо всей подсети. Это важно для опыта: если политика привязана к ресурсу сети, а не к конкретному узлу, второй routing peer обслуживает тот же ресурс. Если же в вашей конфигурации что-то настроено иначе, это вскроется на отказе в самый неудобный момент, а лучше увидеть это сейчас.
Для самого теста разумно взять узкий ресурс — один тестовый хост, а не весь офисный диапазон. Так проще наблюдать и меньше риск зацепить чужую работу.
Есть ещё одна причина брать узкий ресурс: он делает наблюдение однозначным. Если ресурс описан одним хостом, любой трафик к нему в журнале целевого сервиса принадлежит вашему тесту, и адрес источника не смешается с чужими подключениями. Когда ресурсом служит целая подсеть, в тех же логах окажутся запросы коллег, и вы можете принять их успешные ответы за свои, а затянувшийся перерыв в собственном цикле списать на шум.
Перед отключением полезно один раз пройти по цепочке целиком: ресурс, к которому привязаны оба routing peer, разрешающая политика для вашей клиентской машины, значение metric у каждого узла. Если на любом звене что-то отличается от задуманного, например политика действует только для одной группы, а клиентская машина в неё не входит, отказ покажет не слабость переключения, а ошибку в настройке, и вы потратите опыт впустую. Лучше обнаружить это на спокойной проверке доступа, пока оба узла работают.
Протокол измерения до отказа
Подготовьте на клиентской машине два окна и запишите всё, что можно записать. Не нужно особых инструментов: достаточно метки времени.
- В первом окне запустите цикл коротких запросов к тестовому ресурсу с интервалом в секунду. Каждая строка вывода — время и результат: код ответа или ошибка.
- Во втором откройте SSH-сеанс на тестовый хост и запустите команду, которая раз в секунду печатает время. Так вы увидите момент, когда поток остановился.
- Если есть передача файла, запустите её третьей, на файле достаточного размера, чтобы она не закончилась раньше отключения.
- Зафиксируйте, через какой узел всё идёт, и сверьте часы клиента и узлов, если будете сопоставлять логи.
Пара минут контрольной работы без отказа тоже полезна: вы увидите, что в штатном режиме ошибок нет. Иначе потом непонятно, вызвана ли ошибка отключением или была всегда.
Убираем один узел
Теперь выключайте основной routing peer. Способ влияет на смысл результата, поэтому определитесь заранее и запишите, что выбрали.
- Остановить сервис NetBird на узле. Аккуратная имитация: узел перестаёт участвовать в сети, но машина жива.
- Выключить или перезагрузить сам сервер. Ближе к настоящему сбою, но и вреднее для остальных задач на этом сервере.
- Заблокировать сетевой доступ узла. Имитирует потерю связности, при которой процесс жив, а путь недоступен.
Эти варианты не эквивалентны. Клиент может по-разному определять, что узел исчез: корректная остановка и тихая потеря связи выглядят для остального мира по-разному. Поэтому результат одного способа нельзя выдавать за общую характеристику отказа. Если время позволяет, повторите опыт другим способом и сравните.
Момент отключения отметьте в журнале: по часам, а не по памяти. От него вы будете отсчитывать всё остальное.
Что увидеть в короткых запросах
Смотрите на цикл запросов. Возможны три картины, и все они информативны.
- Запросы практически не заметили отключения: ни одной ошибки. Это возможно, но проверьте, что вы действительно отключили узел, который был основным.
- Серия ошибок, затем возобновление успешных ответов. Длину серии измерьте по меткам времени, это и есть ваша характеристика для коротких запросов при данном способе отключения.
- Ошибки не прекращаются. Значит, второй путь не работает: ищите причину в политиках, в доступности второго узла до ресурса, в самой конфигурации сети.
Обратите внимание, что именно короткие запросы в рабочей схеме — самый вероятный выигрыш от второго узла: каждый открывает новое соединение, и ему не нужно «помнить» старый путь. Но выигрыш этот — гипотеза, пока вы не посмотрели на свой цикл.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.
Что увидеть в длительном сеансе
Теперь посмотрите на SSH. Согласно описанному в документации поведению при masquerade, установленные TCP-соединения при переключении сбрасываются, и приложение должно подключиться заново. Проверьте, так ли это у вас, и разберите, что именно происходит.
- Вывод команды остановился и сеанс завис. Сколько он висит и закрывается ли сам или остаётся «мёртвым» до таймаута — это уже свойство клиента SSH и настроек keepalive, а не NetBird.
- Сеанс закрылся с ошибкой. Запишите текст ошибки и время.
- Новый вход по SSH. Попробуйте подключиться заново вручную: получилось ли сразу, и сколько прошло от отключения до первого успешного входа.
Здесь появляются две отдельные величины, и их стоит не смешивать. Первая — как долго вы не могли установить новое соединение. Вторая — как долго существующий сеанс выглядел живым, хотя уже не был таковым. Для пользователя вторая может оказаться неприятнее: он вводит команды в пустоту и не знает, что связи нет.
Чтобы вторая величина не растягивалась до неопределённости, её можно ограничить настройками самого клиента. Например, у SSH есть параметры, с помощью которых клиент сам проверяет живость канала и закрывает сеанс при отсутствии ответа. Если в вашем опыте сеанс висел долго, повторите его с включённой проверкой живости и сравните: это покажет, какую часть перерыва создаёт сеть, а какую добавляет клиент, который не торопится признать соединение мёртвым. Конкретные значения подбирайте сами и записывайте вместе с результатом, иначе числа из двух прогонов не получится сравнивать.
Эта же логика применима к приложениям с пулом соединений. Пул может держать соединения, которые на самом деле уже сброшены при смене routing peer, и отдавать их запросам по очереди. Тогда первые обращения после отказа получают ошибки, даже если новый путь уже работает, пока библиотека не выбросит битые соединения. Поэтому в журнале такого приложения смотрите не только на момент первого успеха, но и на то, сколько запросов подряд закончились ошибкой и прекратились ли они сами.
Наконец, сравните две строки наблюдений прямо рядом: длину серии ошибок в коротких запросах и время, через которое вы смогли войти в SSH заново. Если они близки, значит, клиент перестроился один раз, а остальное зависит от приложения. Если вход заново занял заметно больше, ищите причину в самом клиенте или в способе отключения, а не делайте вывод о сети в целом.
С передачей файла картина ещё нагляднее. Если инструмент умеет докачивать, перезапуск продолжит с места обрыва. Если нет, придётся начинать с начала. Для большого файла разница между этими вариантами и есть настоящая цена переключения.
Что это значит для ваших приложений
Из наблюдений складывается практическая таблица. Она заполняется вашими результатами, а не чужими.
| Что наблюдали | Что записать | Что это говорит |
|---|---|---|
| Короткие запросы | Число ошибок и время первого успеха после отключения | Как быстро новые подключения находят второй узел |
| SSH-сеанс | Оборвался или завис; сколько до обнаружения; повторный вход | Нужно ли пользователю переподключаться |
| Передача файла | Докачка или повтор с нуля | Цена обрыва для крупных операций |
| Приложение с пулом соединений | Поведение клиентской библиотеки | Восстанавливается ли оно само |
Если приложение умеет само переподключаться (автоматический реконнект, повтор запроса, докачка), отказ превращается в короткую заминку. Если не умеет, то второй routing peer даёт лишь одно: после ручного перезапуска всё работает. Это тоже ценно, но это не «бесшовность», и честнее так её и называть.
Возврат узла: переключаться ли обратно
Когда узел вернулся, сеть снова оказывается с двумя доступными путями. Вопрос в том, что произойдёт с трафиком. Поскольку выбор делает клиент и меньшая metric предпочтительнее, у вас есть основание ожидать возврата на основной узел. Но «ожидать» — не значит «знать», так что смотрите.
- Запустите отключённый узел и дождитесь, пока он станет доступным в панели.
- Не трогая цикл запросов, посмотрите, через какой узел идёт трафик теперь. Тем же способом, которым определяли исходный маршрут.
- Запишите, оставался ли трафик на запасном узле или вернулся на основной, и когда это произошло.
Если возврат на основной узел происходит, помните: по документации переключение routing peer при masquerade сбрасывает установленные TCP-соединения. Значит, обратное переключение может оборвать сеансы так же, как и прямое. То есть возвращённый узел — это не только завершение отказа, но и второе событие, способное задеть пользователей. Проверьте на длительном сеансе, заметили ли вы разрыв при возврате, и решите, когда в рабочей среде допустимо возвращать узел: ночью, в окно обслуживания или в любой момент.
Если же трафик остаётся на запасном узле, то неожиданная асимметрия тоже полезное открытие: основной узел стоит без дела, а вся нагрузка лежит на втором. Для планирования ресурсов это важно, ведь запасной узел должен быть способен нести всю работу один.
Отдельно проверьте, как обратное переключение выглядит для короткого запроса и для длительного сеанса. Для цикла запросов оно может пройти незаметно или дать одну-две ошибки, а для SSH стать вторым обрывом за один тест. Поэтому на этапе возврата держите оба наблюдаемых объекта запущенными заново, а не продолжайте с оборванными: иначе вы не узнаете, затрагивает ли возврат сеансы, открытые уже на запасном узле.
Если вы выяснили, что возврат рвёт соединения, это не повод отказываться от второго узла. Это повод заранее решить регламент: возвращать основной узел в тихое время либо оставлять трафик на запасном до окна обслуживания. Выбор зависит от того, какой тип сеансов у ваших пользователей: тем, у кого только короткие запросы, возврат почти не мешает, а владельцу долгой выгрузки он может стоить повтора с начала.
Два узла — это два независимых узла?
Один вопрос остаётся вне теста отключения, но определяет цену результата. Документация рекомендует разные failure domains, то есть узлы, которые не выходят из строя по одной и той же причине. Два сервера на одной стойке, в одной сети, у одного провайдера, на одном гипервизоре при общей проблеме отключатся вместе, и ваш тест, где вы вручную гасили один, этого не покажет.
Покупка двух VPS сама по себе не гарантирует независимости их размещения. Не стоит считать, что два сервера оказались на разном оборудовании, пока вы не получили такого подтверждения. Если независимость важна, выясните у провайдера, в каких локациях и на каких условиях размещены ваши серверы. В публичном предложении VPS MAATRIX перечислены локации UK, US, RU и FR, а сами серверы работают на NVMe и процессорах AMD EPYC с root-доступом. Размещение двух узлов в разных локациях — один из вариантов развести их по разным местам, но какие именно риски это закрывает, решайте сами и проверяйте.
Ресурсы под routing peer
Routing peer — это узел, через который проходит трафик ваших пользователей, поэтому ему нужны ресурсы, но их объём определяется нагрузкой, а не названием тарифа. Для тестового стенда из двух узлов хватит скромного плана: у MAATRIX это, например, Ba (1 vCPU, 2 ГБ RAM, 40 ГБ NVMe) или Uab (2 vCPU, 4 ГБ, 80 ГБ). Это лишь отправная точка для эксперимента, а не обещание ёмкости. Реальную пропускную способность и число одновременных пользователей покажет замер на вашем трафике, с нагрузкой на оба узла по очереди, в том числе на запасной, который однажды останется один.
Если в вашей схеме есть доступ к узлам для администрирования и вы используете двухфакторную защиту входа, полезно посмотреть соседний материал: двухфакторная аутентификация в Tailscale и NetBird. Он про другую задачу, но защита учётной записи, которая управляет сетью, тоже влияет на то, насколько спокойно вы переключаете узлы.
Что вы получаете в итоге
После теста у вас должна лежать не фраза «отказоустойчивость настроена», а короткая запись. Новые подключения после отключения основного узла возобновились спустя такое-то время при таком-то способе отключения. Открытый SSH-сеанс оборвался или завис, и пользователю нужно подключаться заново. Передача файла продолжается с места обрыва либо начинается сначала. Возврат узла вызвал или не вызвал второй разрыв.
Эти строки и есть характеристика отказа вашего приложения. Она может оказаться лучше, чем вы опасались, или хуже, чем обещала схема с двумя зелёными узлами. В любом случае вы знаете, что произойдёт у вас, а не у кого-то в документации, и можете решить, нужны ли вам автоматический реконнект, keepalive, докачка или просто предупреждение пользователям. Бесшовность никто не обещал, а измеренная картина отказа у вас теперь есть.