Короткий ответ

Два маршрута 0.0.0.0/0 с одинаковым distance — ECMP. RouterOS при включённом connection tracking балансирует по соединениям, не по пакетам внутри TCP. Пер-пакетный баланс на NAT-файрволе даёт асимметрию и «сайты через раз». Неравномерные каналы (100 Мбит + 20 Мбит) ECMP не взвесит справедливо — тяжёлые потоки случайно сядут на тонкий WAN.

Если нужен резерв, а не баланс — разный distance (failover). Если нужен «этот VLAN на ISP2» — policy routing, не второй default.

Симптомы и как отличить

Оба WAN в /ip route print с A и одним distance. Канал1 90%, канал2 5%. Или HTTPS зависает, ping стабилен.

ЦельИнструмент
Резервdistance 1/2
Баланс исходящих сессийECMP или PCC
Жёсткая привязкаmangle + table
Симметричный ответ на входящиеmark по in-interface

Возможные причины

  1. Путают failover и ECMP.
  2. NAT только на одном интерфейсе: половина сессий без srcnat.
  3. FastTrack + ECMP: редкие сюрпризы с marks.
  4. PCC настроен, ECMP default всё ещё есть — двойной баланс.
  5. Входящий dstnat на WAN1, ответ ушёл в WAN2.
  6. Бандлы разной стоимости без весов (в ROS простые равные ECMP).

Диагностика

/ip route print detail
/ip firewall nat print
/ip firewall connection print count-only
/interface print stats

Два dst-address=0.0.0.0/0 с distance=1 gateway разные — ECMP. Снимите stats RX/TX за интервал теста.

Проверка асимметрии: с ПК HTTPS, в connections смотрите reply-dst-address / интерфейсы. Ответ не тем WAN — вот почему «ломается».

PCC:

/ip firewall mangle print where per-connection-classifier

Если PCC есть и ECMP есть — решите, кто главный.

Решение

Сценарий A. Хотели failover, получили ECMP

Поставьте distance=2 на backup. Второй перестанет быть active, пока жив primary.

Сценарий B. Хотели баланс, HTTPS сыпется

  1. Masquerade на оба WAN (out-interface-list=WAN).
  2. Оставьте tracking включённым (не per-packet).
  3. Не балансируйте в ECMP линки с разным NAT-поведением (один публичный, второй CGNAT) без понимания входящих.

Сценарий C. PCC вместо голого ECMP

PCC в mangle (оба адреса и порты) + mark-routing в две таблицы с default. Это контролируемее ECMP equal-cost: можно исключить сети, не класть UDP DNS в баланс и т.д. Не копируйте «PCC 2 линии» скрипты целиком: вычищайте FastTrack-исключения и LAN-to-LAN (dst-address=192.168.88.0/24 не маркировать).

Типичный classifier:

/ip firewall mangle
add chain=prerouting dst-address-type=!local in-interface-list=LAN per-connection-classifier=both-addresses-and-ports:2/0 action=mark-connection new-connection-mark=wan1
add chain=prerouting dst-address-type=!local in-interface-list=LAN per-connection-classifier=both-addresses-and-ports:2/1 action=mark-connection new-connection-mark=wan2

Дальше mark-routing и две FIB-таблицы, как в policy routing.

Сценарий D. Входящие на оба белых IP

connection-mark на prerouting in-interface=ether1 / ether2, ответные mark-routing в ту же сторону. Иначе ECMP outgoing сломает dstnat.

Как проверить, что проблема устранена

Длительные загрузки идут целиком одним WAN (ожидаемо). Много мелких сессий распределяются. Сайты стабильны. Для failover-сценария второй default не active одновременно. VoIP двусторонний.

Сравните 203.0.113.10 vs второй публичный на what-is-my-ip с двух ПК — могут отличаться при балансе; это норма, если оба NAT верны.

Если не помогло

  • Один провайдер режет TTL/P2P — «неравномерно» не лечится ECMP.
  • Нужна агрегация 2×канал как один IP — это не ECMP, а bonding/провайдерский MLPPP, на независимых ISP невозможно.
  • VPN хаб видит смену IP сессии — исключите VPN из баланса (FastTrack/VPN + policy).

Профилактика

  • Явная цель: failover XOR balance XOR policy.
  • Оба WAN в NAT list.
  • Мониторинг по интерфейсам и по качеству, не только сумме.
  • Не держать detect-internet вместе с ручным ECMP без понимания.

Неравные каналы, sticky IP и что не умеет простой ECMP

Два default с distance=1 делят новые соединения, не байты внутри слона. Поток на 400 Мбит сядет на один WAN целиком — график «неравный» при 500+100 Мбит каналах неизбежен. Weighted ECMP как у крупных маршрутизаторов на SOHO не ждите; для 70/30 берите PCC с неравным числом корзин и две таблицы, затем измерьте, а не верьте формуле.

Банки и личные кабинеты с привязкой к IP страдают от смены 203.0.113.10 на второй адрес. Такие хосты вынесите в address-list и policy routing на один ISP, остальное пусть балансируется.

UDP 500/4500 и WG listen-port исключите из PCC: иначе IKE/handshake прыгает между WAN и туннель «моргает». DNS UDP тоже лучше sticky или вообще через кэш роутера, чтобы не ловить странные SERVFAIL.

Входящий dstnat на WAN1 при ECMP исходящих без connection-mark по in-interface даёт односторонний TCP. Сначала нарисуйте, нужны ли входящие на оба белых IP. Если нет — не балансируйте, сделайте failover с разным distance.

FAQ

ROS 7 умеет weighted ECMP?

Не рассчитывайте на полноценные веса как у Cisco на SOHO. Для неравных каналов лучше policy/PCC с долей classifier (2/0, 2/1 неравномерно не сделать идеально; берут 3/0 3/1 3/2 и два mark на толстый). Проверяйте фактический match.

Per-packet load balancing включить где?

В классическом ROS для IP routing при tracking это не ваш друг за NAT. Не ищите «галочку per-packet» как решение HTTPS.

Почему ping 1.1.1.1 всегда ISP1?

Мало потоков. Один dst+src ICMP может липнуть. Смотрите много TCP.

Нужен ли same NAT IP?

Невозможен с двумя ISP. Баланс = два внешних адреса. Сессии к банкам с привязкой IP будут страдать — таких хостов выносите в policy на один WAN.

ECMP и WireGuard endpoint?

Endpoint должен быть стабилен. Не балансируйте пакеты IKE/WG по двум WAN без sticky. Исключайте UDP 13231/500/4500 из PCC.

Почему after failover с ECMP часть сессий «залипла» в мёртвый WAN?

Conntrack помнит выход. Пока соединение established, ECMP новое не перекладывает. После падения gateway нужен check-gateway, чтобы маршрут исчез, плюс разрыв старых connection или ожидание timeout. Чистый failover с distance 1/2 предсказуемее «ECMP + надежда». Не равняйте два default, если хотели резерв. После возврата primary старые сессии могут остаться на backup до естественного закрытия — для NAT это смена внешнего IP.