Туда через Амстердам, обратно через Нью-Йорк: что такое асимметричный маршрут и чем он опасен
Запускаете traceroute до сервера в США — путь идёт через Франкфурт и точку обмена трафиком в Нью-Йорке. Заходите на сам сервер и гоняете traceroute обратно к себе — путь совершенно другой, через Амстердам и Лондон. Первая реакция — «где-то маршрутизация сломана, надо чинить». На деле в девяти случаях из десяти ничего не сломано: это асимметричная маршрутизация, нормальное свойство интернета, с которым большинство сетевых инженеров вплотную знакомится только после первого инцидента, который она вызвала.
Содержание
- Как реально выбирается маршрут: у каждой сети своя политика, а не общая карта
- Как это увидеть на практике: traceroute в обе стороны
- Проблема №1: stateful-оборудование ждёт оба направления через себя
- Проблема №2: диагностика ломается, если предполагать симметрию по умолчанию
- Что можно сделать: где асимметрию нужно принять, а где — устранить у себя
Как реально выбирается маршрут: у каждой сети своя политика, а не общая карта
BGP не ищет «оптимальный» маршрут в смысле кратчайшего физического расстояния или наименьшей задержки. Каждая автономная система выбирает лучший путь до конкретной подсети по своим локальным правилам: приоритет прямому пирингу перед транзитом, приоритет более дешёвому каналу перед дорогим, local-preference, проставленный вручную инженерами конкретного провайдера, договорные ограничения («этот пир принимает от нас трафик только на определённых точках обмена») и так далее. Дальше сетей за границей своей собственной BGP-таблицы AS в общем случае не «видит» — она знает только AS-path, то есть через какие автономные системы объявлен префикс, но не то, какими были доступные ей варианты.
Отсюда классическая причина асимметрии — hot-potato routing («маршрутизация горячей картошки»): сеть старается передать транзитный трафик соседу как можно раньше, на ближайшей к себе точке обмена, а не тащить его через весь свой бэкбон до точки, ближайшей к получателю. Это снижает нагрузку и стоимость для сети, которая передаёт пакет дальше, но никак не связано с тем, как её сосед решит вернуть ответ.
Пример из заголовка — не абстракция. Пользователь в Европе идёт к серверу в США. Его провайдер видит два варианта отдать трафик дальше: через своего партнёра на AMS-IX в Амстердаме или через транзитного оператора с точкой присутствия в Лондоне. Он выбирает Амстердам — например, потому что пиринг там бесплатный, а транзит через Лондон платный. Дальше трафик идёт через сеть этого партнёра его собственным путём до дата-центра в США. А вот сервер в США, отправляя ответ, смотрит на свою собственную таблицу маршрутов до подсети пользователя — и у его провайдера может не быть пути через ту же европейскую сеть вообще, зато есть выгодный транзитный маршрут через Нью-Йорк. Итог: туда трафик идёт через Амстердам, обратно — через Нью-Йорк, и оба провайдера по-своему правы, потому что каждый оптимизировал свою половину пути независимо.
Как это увидеть на практике: traceroute в обе стороны
Проблема диагностики в том, что traceroute с вашей машины показывает только путь «туда». Путь «обратно» с вашей стороны не виден в принципе — вы видите лишь то, что ответные пакеты в итоге до вас дошли (или нет), но не какими сетями они шли. Единственный надёжный способ увидеть оба направления — иметь возможность запустить traceroute с обеих сторон диалога. Это ровно тот случай, когда наличие своего сервера, а не только клиентского доступа, превращает догадки в измерение:
# С клиента к серверу
mtr -rwzb -c 50 203.0.113.10
# С сервера обратно к клиенту (по SSH на сам сервер)
ssh user@203.0.113.10
mtr -rwzb -c 50 198.51.100.20
Флаги -r (report-режим, без интерактивного экрана), -w (полные имена/IP без обрезки), -z (показывать ASN хопа) и -b (показывать и имя, и IP) дают отчёт, который можно сравнить построчно для обоих направлений. Если списки ASN по пути в одну и другую сторону не пересекаются или пересекаются частично — это и есть асимметрия, зафиксированная фактически, а не предположительно.
Когда доступа ко второй стороне нет (например, диагностируете маршрут до чужого публичного сервиса), помогают looking glass серверы — веб-интерфейсы, которые крупные сети и точки обмена предоставляют для запуска traceroute/BGP-запросов из своей сети наружу. У большинства крупных провайдеров и IX есть публичный looking glass — стоит поискать по названию конкретной сети. Для быстрой проверки, через какую автономную систему проходит конкретный IP, подойдёт whois по BGP-данным:
whois -h whois.radb.net 203.0.113.10
# или через RIPE
whois -h whois.ripe.net -- '-B 203.0.113.10'
Это не покажет весь путь, но покажет, в чьей сети находится точка входа — уже достаточно, чтобы понять, что туда и обратно трафик обслуживают разные транзитные провайдеры.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПроблема №1: stateful-оборудование ждёт оба направления через себя
Файрвол с отслеживанием состояния (stateful inspection) не проверяет каждый пакет по отдельности — он строит таблицу соединений: увидел SYN, завёл запись, увидел SYN-ACK от того же диалога — обновил запись, пропустил пакет как ESTABLISHED. Правило вида -m state --state ESTABLISHED,RELATED -j ACCEPT в iptables/nftables работает именно по этому принципу и предполагает, что оба направления диалога пройдут через один и тот же файрвол — только тогда у него есть запись, с которой можно сверить ответный пакет.
Если исходящий и входящий трафик одного соединения физически идут через разные устройства — сервер с двумя аплинками и policy-based routing, кластер файрволов active-active без синхронизации состояний, upstream-маршрутизаторы с ECMP, раскладывающие пакеты одного потока по разным линкам, — файрвол, видящий только половину диалога, принимает ответный пакет за внезапный и молча его дропает. Симптом на стороне пользователя — рваные, не воспроизводимые стабильно обрывы: часть запросов проходит (повезло с симметричным путём), часть зависает и таймаутится. Ровно так это выглядело в разборе инцидента с двумя интерфейсами и одним шлюзом — асимметричный маршрут ронял там каждый третий пакет, и причину нашли только сопоставив маршруты в обе стороны.
Балансировщики с сохранением состояния подвержены той же логике: если узел ожидает, что ответ либо пройдёт через него же, либо что состояние синхронизировано между всеми узлами кластера, асимметричный путь (в том числе внутри своей сети, между зонами доступности) ломает эту логику так же, как файрвол. Таблица ниже — типичные категории оборудования и их чувствительность к асимметрии:
| Тип устройства | Ожидает оба направления через себя | Поведение при асимметрии |
|---|---|---|
| Stateless ACL / packet filter | Нет | Работает нормально, каждый пакет проверяется независимо |
| Stateful firewall (iptables conntrack, pfSense, большинство NGFW) | Да | Ответный пакет без state — дроп |
| NAT (source/destination) | Да | Трансляция не находится, соединение рвётся |
| Балансировщик с sticky-сессиями по conntrack | Да | Запрос уходит на другой узел, сессия теряется |
| Балансировщик без состояния (L4 ECMP hash по 5-tuple) | Нет, если хэш стабилен | Работает, если хэш не меняется при флаппинге маршрута |
| IDS/IPS в inline-режиме | Обычно да | Видит только половину сессии, часть сигнатур не срабатывает |
Проблема №2: диагностика ломается, если предполагать симметрию по умолчанию
Вторая практическая проблема тише первой, но обходится не дешевле: она не роняет трафик сразу, а сбивает с толку при расследовании. Если инженер меряет задержку и потери только ping или mtr с одной стороны и делает вывод «сеть в целом ок» или «сеть в целом плохая», он на самом деле измерил только половину картины. Затор на пиринговом линке в одном направлении может не иметь никакого отношения к обратному пути — и наоборот. Разбор чтения таких отчётов без предположения о симметрии — отдельная тема, подробнее в статье про чтение traceroute и ping через VPN: часть логики (рост числа хопов, скачок RTT на одном хопе) переносится и на обычные, не VPN-соединения.
Практическое следствие: если жалоба звучит как «до сервера долго» или «рвутся соединения», не спрашивайте «какой маршрут», спрашивайте «какой маршрут в каждую сторону» и снимайте оба сразу, с привязкой ко времени, чтобы можно было сопоставить с логами файрвола или графиками загрузки интерфейсов. На сервере полезно параллельно с mtr в обе стороны поднять захват трафика, чтобы увидеть, действительно ли ответные пакеты покидают систему:
tcpdump -i eth0 -w /tmp/asym-check.pcap host 198.51.100.20 and port 443
Если в дампе видно, что сервер честно отправляет SYN-ACK или ACK, а с клиентской стороны они не доходят — проблема снаружи, на асимметричном участке между сетями, и чинить там особо нечего, кроме как обходить последствия (см. следующий раздел). Если же исходящих пакетов нет вовсе — дело не во внешней асимметрии, а в локальном: файрвол дропнул пакет до отправки, или таблица маршрутизации сервера отправляет ответ не в тот интерфейс. Разница принципиальна, и без раздельного взгляда на оба направления её легко упустить.
Основы того, почему конкретные маршруты вообще выглядят так, как выглядят — через какие точки обмена, с каким числом хопов — разобраны в статье о том, как пакет добирается от домашнего роутера до сервера в США; а то, как BGP на каждом шаге принимает решения, которые в сумме и создают асимметрию, подробнее описано в статье про сам протокол BGP.
Что можно сделать: где асимметрию нужно принять, а где — устранить у себя
Асимметрию за пределами своей сети вы не контролируете и в общем случае не должны пытаться контролировать — это нормальная экономика пиринга и транзита у сотен независимых операторов между вами и точкой назначения. Пытаться заставить весь интернет ходить симметрично — не инженерная задача, а фантазия. Но у себя, внутри своей инфраструктуры, асимметрию, которую вы создали сами, устранить обычно можно и стоит.
Если сервер многоканальный (несколько аплинков, несколько интерфейсов в разные сети), убедитесь, что ответ уходит туда же, откуда пришёл запрос, через policy-based routing по source-адресу, а не просто по маршруту по умолчанию:
# отдельная таблица маршрутизации для трафика, пришедшего на второй интерфейс
ip rule add from 10.20.0.0/24 table 100
ip route add default via 10.20.0.1 table 100
# проверка, каким путём реально уйдёт ответ конкретному адресу
ip route get 198.51.100.20 from 10.20.0.5
Это не убирает асимметрию снаружи, но убирает ту её часть, которую вы добавили сами тем, что ответ по умолчанию уходит через основной шлюз, а не через тот интерфейс, на который пришёл запрос, — именно этот класс ошибок и разбирался в статье про инцидент с двумя интерфейсами, упомянутой выше.
Для stateful-оборудования — не размазывайте инспекцию по нескольким параллельным точкам, через которые трафик одного соединения может пойти по-разному в разные моменты. Если избыточность нужна, используйте кластеризацию с синхронизацией состояний (conntrackd для связки iptables-файрволов, штатный state sync у коммерческих NGFW), а не два независимых узла, между которыми ECMP переключает трафик без предупреждения. Там, где инспекция состояния не обязательна — простой pass-through фильтр по портам между внутренними сегментами — рассмотрите stateless ACL: он не боится асимметрии в принципе.
Для балансировщиков — выбирайте схему с консистентным хэшированием по 5-tuple, которая не зависит от того, через какой узел кластера физически прошёл первый пакет соединения, либо явно закрепляйте сессии (source IP affinity) и синхронизируйте таблицы состояний между узлами так же, как для файрволов.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Асимметричная маршрутизация — это всегда проблема, которую нужно чинить?
Нет. Для обычного трафика без stateful-оборудования на пути это нормальное, ожидаемое поведение интернета, и оно не мешает работе TCP/UDP как таковых. Проблемой она становится только там, где на пути стоит устройство, которому важно видеть оба направления одного соединения — файрвол с отслеживанием состояния, некоторые балансировщики, inline IDS/IPS.
Можно ли заставить трафик идти симметрично на всём пути от клиента до сервера?
В общем случае нет — вы не управляете маршрутизацией в чужих автономных системах между вами и получателем: решения там принимаются независимо, каждой сетью по своим договорённостям с соседями. Управлять можно только той частью пути, которая находится в вашей сети или сети провайдера (например, через BGP local-preference или community, если у вас своя AS).
Как быстро проверить, что причина проблемы именно в асимметрии?
Снимите mtr/traceroute одновременно с обеих сторон соединения (нужен доступ к серверу) и сравните списки хопов и ASN. Если списки для двух направлений не пересекаются или пересекаются частично — асимметрия подтверждена как факт. Дальше проверьте логи файрвола/conntrack на предмет дропов пакетов, похожих на продолжение существующего соединения, но не распознанных таковыми.
UDP-трафик страдает от асимметрии так же, как TCP?
Сам UDP как протокол без установления соединения к пути безразличен. Но если на пути стоит stateful-файрвол с conntrack для UDP или NAT с таблицей трансляций, эффект тот же, что и для TCP: ответ, не увидевший «своего» состояния, отбрасывается.
Если у меня простой VPS с одним интерфейсом и одним провайдером, мне вообще нужно об этом думать?
Как источник проблем на вашей стороне — почти нет: одна таблица маршрутизации, один путь наружу. Но как объяснение чужого поведения — да: если пользователи из разных регионов видят разное качество соединения к одному серверу, часть причины может быть в том, что путь до них и обратно у их провайдеров устроен асимметрично и с разным качеством в каждую сторону.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →