Два провайдера: отказоустойчивость и распределение нагрузки (Продолжение)
Добавлено: 22 апр 2021, 01:50
Эта статья - прямое продолжение темы двух провайдеров, поднятой мною более восьми лет назад.
Тогда я подробно описал модель OSI и начальной настройки. Однако, полноценной отказоустойчивости и распределения нагрузки я тогда не достиг.
Задачка оказалась совсем не простой. Надо сказать, что спустя восемь лет я склоняюсь к мысли, что она не имеет полного и окончательного решения - чуть позже я объясню почему.
Но полагаю, что мне удалось приблизиться к заветной цели настолько, насколько это вообще возможно на сегодняшнем уровне развития RouterOS.
Важным граничным условием задачи было использование существующих механизмов - без скриптинга и множества правил маркировки.
Итак, приступим!
Вернее, продолжим.
Я рассмотрю три случая настроек подключения:
Укажем адреса на интерфейсах:
Пропишем DNS
Первая пара относится к TTK, вторая - к Ростелекому. Чуть позже нам предстоит разрулить обращения к ним по соответствующим каналам.
Прописываем маршруты:
Что здесь происходит?
Во первой строке я назначил шлюз провайдера ТТК как маршрут по умолчанию в основной таблице маршрутизации (main).
Доступность шлюза я проверяю используя протокол уровня Ethernet.
Во-второй строкой я прописал шлюз Ростелекома, указав, что он менее предпочтителен, в сравнении с TTK (distance=2).
Третьей строкой я прописал шлюз Ростелекома маршрутом по умолчанию в таблице RT_table. Доступность шлюза проверяю через ping. Оба способа (arp и ping) будут работать одновременно. Все маршруты Ростелекома лягут независимо от того, на каком правиле первей сработает проверка.
Напомню, что в таблице маршрутизации может быть лишь один действующий маршрут по умолчанию.
При данной настройке весь трафик будет идти через ТТК. Если ТТК отвалится - трафик тут же потечёт через Ростелеком.
Отказоустойчивость есть, балансировки - нет.
Но мы же не зря написали третью строчку.
Надо завернуть в неё часть трафика правилами:
Я завернул в канал Ростелекома все обращения к DNS-серверам Ростелекома и трафик торрент-качалки.
Для внешнего подключения к минорному интерфейсу (где distance=2) придётся использовать метку соединений:
Можно сделать чуть по другому:
Прописываем маршруты по умолчанию для таблиц TTK_table и RT_table.
В основной таблице пишем оба маршрута через запятую включая ECMP (равномерное распределение соединений).
Это не значит, что трафик будет распределён равномерно. Никто и никогда заранее не угадает через какое соединение вдруг пойдёт закачка большого файла или просмотр видео.
Равномерно распределятся именно соединения.
Разрулим обращения к DNS-серверам:
Понятно, что так же можно направить трафик произвольных хостов или подсетей.
Или исходящие подключения туннелей (VPN работает лучше внутри сети одного провайдера).
И ещё два слова про NAT.
Вы можете создать список WAN-интерфейсов и сказать:
Но лучше так не делать. Если у вас статика - используйте src-nat, а не masquerade.
Фигура вторая, двуточечная
При подключении PPPoE провайдер выдаёт адрес и все настройки (Gateway, DNS, NTP...). Хотелось бы использовать всё это богатство, а не прописывать руками.
К тому же все означенные настройки могут время от времени меняться.
Но как в таком случае задать routing-mark и check-gateway?
Есть два способа. Первый - виртуальная таблица маршрутизации:
Так мы сделали для интерфейса RT отдельную таблицу маршрутизации.
В /ip route наше PPPoE подключение к Ростелекому будет с меткой routing-mark=RT_table
Мы можем направить туда часть трафика с помощью правил /ip route rule, но если канал Ростелекома упадёт - то опаньки.
Переключения на ТТК не случится. Поэтому для целей отказоустойчивости используем второй способ:
Мы находим динамические подключения с distance=2 (в нашем примере это PPPoE Ростелекома) и назначаем ему метку маршрута (сиречь отдельную таблицу маршрутизации) и проверку шлюза.
В /ip route всё будет выглядеть и работать ровно так же, как при VRF. Но если маршрут помрёт - назначенный ему трафик пойдёт через таблицу main, где основным маршрутом будет ТТК.
В данном случае ECMP будет работать по имени интерфейса:
Так два из трёх соединений будет идти через ТТК.
Понятно, в основной таблице не должно быть других маршрутов с distance=1.
Значит ТТК надо убрать в отдельную таблицу маршрутизации
Либо сделать default-route-distance=3 в /interface pppoe-client
Фигура третья, динамическая
Мы получаем от провайдера произвольный адрес и прочие настройки по DHCP.
Не только выдаваемый вам адрес, но и gateway и DNS могут менять время от времени.
Да, мы умеем назначать разные таблицы маршрутизации при помощи /routing filter и направлять в них трафик при помощи правил /ip route rule.
Но как включить ECMP?
Имена интерфейсов в данном случае не работают. Только прямое указание ip шлюза (и желательно с указанием интерфейса, через который он достижим - будет работать быстрее):
Провайдер время от времени меняет адреса шлюзов. И тут нам, к сожалению, не обойтись без скриптов (это подтвердила техподдержка Микротика).
Создадим скрипт SetGW4ECMP следующего содержания:
Будем запускать скрипт при получении/обновлении адреса на обоих интерфейсах:
Не забываем разруливать обращения к DNS ну и всякое, о чём я писал выше.
Post scriptum
Так же не могу не упомянуть про новый механизм detect-internet.
Пока он просто показывает наличие интернета на интерфейсе, что можно использовать в скриптах
Но микротиковцы работают над этим и кто знает, может в ближайшее время нас ожидает check-gateway=detect-internet или что-то подобное.
За сим разрешите откланяться.
Удачи на маршрутах ;)
Тогда я подробно описал модель OSI и начальной настройки. Однако, полноценной отказоустойчивости и распределения нагрузки я тогда не достиг.
Задачка оказалась совсем не простой. Надо сказать, что спустя восемь лет я склоняюсь к мысли, что она не имеет полного и окончательного решения - чуть позже я объясню почему.
Но полагаю, что мне удалось приблизиться к заветной цели настолько, насколько это вообще возможно на сегодняшнем уровне развития RouterOS.
Важным граничным условием задачи было использование существующих механизмов - без скриптинга и множества правил маркировки.
Итак, приступим!
Вернее, продолжим.
Я рассмотрю три случая настроек подключения:
- Static IP - вбиваем адреса, шлюз и DNS руками;
- PPPoE - всё получаем от провайдера используя имя и пароль;
- DHCP - просто получаем все настройки втыкая кабель в порт роутера.
Укажем адреса на интерфейсах:
Код: Выделить всё
/ip address
add address=80.72.223.114/30 interface=ether1-TTK
add address=31.23.202.41/30 interface=ether2-Rostelecom
Код: Выделить всё
/ip dns
set allow-remote-requests=yes servers=80.72.225.2,80.72.230.2, 80.254.108.202,80.254.108.194
Прописываем маршруты:
Код: Выделить всё
/ip route
add check-gateway=arp distance=1 gateway=80.72.224.115
add check-gateway=arp distance=2 gateway=31.23.202.42
add check-gateway=ping distance=1 gateway=31.23.202.42 routing-mark=RT_table
Во первой строке я назначил шлюз провайдера ТТК как маршрут по умолчанию в основной таблице маршрутизации (main).
Доступность шлюза я проверяю используя протокол уровня Ethernet.
Во-второй строкой я прописал шлюз Ростелекома, указав, что он менее предпочтителен, в сравнении с TTK (distance=2).
Третьей строкой я прописал шлюз Ростелекома маршрутом по умолчанию в таблице RT_table. Доступность шлюза проверяю через ping. Оба способа (arp и ping) будут работать одновременно. Все маршруты Ростелекома лягут независимо от того, на каком правиле первей сработает проверка.
Напомню, что в таблице маршрутизации может быть лишь один действующий маршрут по умолчанию.
При данной настройке весь трафик будет идти через ТТК. Если ТТК отвалится - трафик тут же потечёт через Ростелеком.
Отказоустойчивость есть, балансировки - нет.
Но мы же не зря написали третью строчку.
Надо завернуть в неё часть трафика правилами:
Код: Выделить всё
/ip route rule
add comment="DNS RT" dst-address=80.254.0.0/16 table=RT_table
add comment="Torrent NAS" src-address=192.168.25.240/32 table=RT_table
Для внешнего подключения к минорному интерфейсу (где distance=2) придётся использовать метку соединений:
Код: Выделить всё
/ip firewall mangle
add action=mark-connection chain=input connection-state=new dst-address=31.23.202.41 new-connection-mark=RT_conn
add action=mark-routing chain=output connection-mark=RT_conn new-routing-mark=RT_table
Код: Выделить всё
/ip route
add check-gateway=arp distance=1 gateway=80.72.224.115 routing-mark=TTK_table
add check-gateway=ping distance=1 gateway=31.23.202.42 routing-mark=RT_table
add check-gateway=ping distance=1 gateway=80.72.224.115%ether1-TTK,31.23.202.42%ether2-Rostelecom
В основной таблице пишем оба маршрута через запятую включая ECMP (равномерное распределение соединений).
Это не значит, что трафик будет распределён равномерно. Никто и никогда заранее не угадает через какое соединение вдруг пойдёт закачка большого файла или просмотр видео.
Равномерно распределятся именно соединения.
Разрулим обращения к DNS-серверам:
Код: Выделить всё
/ip route rule
add comment="DNS RT" dst-address=80.254.0.0/16 table=RT_table
add comment="DNS TTK" dst-address=80.72.0.0/16 table=TTK_table
Или исходящие подключения туннелей (VPN работает лучше внутри сети одного провайдера).
И ещё два слова про NAT.
Вы можете создать список WAN-интерфейсов и сказать:
Код: Выделить всё
/ip firewall nat
add action=masquerade chain=srcnat out-interface-list=WAN src-address=192.168.25.0/24
Код: Выделить всё
/ip firewall nat
add action=src-nat chain=srcnat out-interface=ether1-TTK src-address=192.168.25.0/24 to-addresses=80.72.223.114
[... и таки да - отдельное правило для каждого интерфейса]
Код: Выделить всё
/interface pppoe-client
add name=TTK add-default-route=yes default-route-distance=1 interface=ether1-TTK use-peer-dns=yes user=yyyyyyyy password=xxxxxxx
add name=RT add-default-route=yes default-route-distance=2 interface=ether2-Rostelecom use-peer-dns=yes user=yyyyyyyy password=xxxxxxx
К тому же все означенные настройки могут время от времени меняться.
Но как в таком случае задать routing-mark и check-gateway?
Есть два способа. Первый - виртуальная таблица маршрутизации:
Код: Выделить всё
/ip route vrf
add interfaces=RT routing-mark=RT_table
В /ip route наше PPPoE подключение к Ростелекому будет с меткой routing-mark=RT_table
Мы можем направить туда часть трафика с помощью правил /ip route rule, но если канал Ростелекома упадёт - то опаньки.
Переключения на ТТК не случится. Поэтому для целей отказоустойчивости используем второй способ:
Код: Выделить всё
/routing filter
add chain=dynamic-in distance=2 set-check-gateway=ping set-routing-mark=RT_table
В /ip route всё будет выглядеть и работать ровно так же, как при VRF. Но если маршрут помрёт - назначенный ему трафик пойдёт через таблицу main, где основным маршрутом будет ТТК.
В данном случае ECMP будет работать по имени интерфейса:
Код: Выделить всё
/ip route
add check-gateway=ping distance=1 gateway=TTK,TTK,RT
Понятно, в основной таблице не должно быть других маршрутов с distance=1.
Значит ТТК надо убрать в отдельную таблицу маршрутизации
Код: Выделить всё
/routing filter
add chain=dynamic-in distance=1 set-check-gateway=ping set-routing-mark=TTK_table
Фигура третья, динамическая
Мы получаем от провайдера произвольный адрес и прочие настройки по DHCP.
Не только выдаваемый вам адрес, но и gateway и DNS могут менять время от времени.
Да, мы умеем назначать разные таблицы маршрутизации при помощи /routing filter и направлять в них трафик при помощи правил /ip route rule.
Но как включить ECMP?
Имена интерфейсов в данном случае не работают. Только прямое указание ip шлюза (и желательно с указанием интерфейса, через который он достижим - будет работать быстрее):
Код: Выделить всё
/ip route
add check-gateway=ping comment="Main Gateway" distance=1 gateway=80.72.224.115%ether1-TTK,31.23.202.42%ether2-Rostelecom
Создадим скрипт SetGW4ECMP следующего содержания:
Код: Выделить всё
:local TTK_GW [/ip dhcp-client get [find interface=ether1-TTK] gateway]
:local RT_GW [/ip dhcp-client get [find interface=ether2-Rostelecom] gateway]
/ip route set [find comment ="Main Gateway"] gateway="$TTK_GW%ether1-TTK,$RT_GW%ether2-Rostelecom"
Код: Выделить всё
/ip dhcp-client
set 0,1 script=SetGW4ECMP
Post scriptum
Так же не могу не упомянуть про новый механизм detect-internet.
Код: Выделить всё
/interface list
add name=WAN
add name=LAN
add name=Inet
/interface list member
add interface=ether1-TTK list=WAN
add interface=ether2-Rostelecom list=WAN
/interface detect-internet
set detect-interface-list=WAN internet-interface-list=Inet wan-interface-list=WAN
Код: Выделить всё
:put [/interface detect-internet state get [find name=ether1-TTK] state]
ineternet
За сим разрешите откланяться.
Удачи на маршрутах ;)