Iproute2 policy-routing и балансировка трафика между аплинками — проблема сброса соединений

Наткнулся на неприятный подводный камень. Имеем систему с несколькими аплинками, и policy-routing, реализующий балансировку соединений между аплинками с помощью:

ip route replace default scope global
nexthop via 11.22.33.1 dev eth0 weight 1
nexthop via 55.66.77.1 dev eth1 weight 1


(Примерная инструкция здесь)

Проблема заключается в следующем — соединения периодически падают, причём никакой системы нет. Может простоять несколько часов, может упасть через 5-10 минут. Всяким http и torrent'ам это не мешает. В первом случае сессии обычно достаточно короткие, во втором реконнект проходит незаметно и без последствий. Но если мы работаем с ssh?

Разъяснение для тех, кто не знает, как работает такая схема маршрутизации.

Для каждого соединения, идущего через шлюз по умолчанию, выбирается один из имеющихся в наличии каналов, с вероятностью, соответствующей параметру weight.

Затем запись о маршруте для этого соединения заносится в кеш, и все пакеты между этими ip-адресами далее ходят по этому маршруту. Если какое-то время пакетов по этому маршруту нет — запись из кеша удаляется. По умолчанию на это требуется около пяти минут. В этом есть уже как минимум одна проблема — если ваше соединение долго не передаёт никаких данных, запись из кеша маршрутов будет вытерта, хотя из кеша соединений, возможно, ещё и не будет. По умолчанию в модуле nf_conntrack выставлено какое-то очень большое время жизни для tcp-соединений. Что случится? При следующем прохождении пакета в этом соединении, которое ещё считается несброшенным, будет выбран новый маршрут, как если бы оно было вновь установлено. Если повезет — тот же, что и был. Тогда всё продолжит работать. А вот если другой — ничего никуда не пойдёт.

Но на практике это проблема невеликая, довольно мало ситуаций, в которых соединение стоит без дела столько времени, а даже если это, скажем, ssh-сессия, то в ней можно включить keep-alive пакеты. Как и в большинстве других практических случаев. По идее такая ситуация возможна ещё с ftp, но я им давно не пользуюсь, и вам не советую. Да и большинство ftp-клиентов тоже умеют keep-alive.

Хуже другое — в такой схеме падали даже сессии с непрерывным потоком данных. И вот это оказалось непонятно.
Простой обход проблемы, слепленный на скорую руку, оказался в прописывании статических маршрутов для наиболее нужных удалённых хостов, так чтобы маршрут к ним лежал строго через один интерфейс. Но некрасиво же. Неуниверсально и ломает идею connection-failover.

То, что это помогло, и навело меня на мысль, что проблема где-то именно в роутинге. Трёхчасовые раскопки выявили следующее: в ядрах до 2.6.35 (а систем на них очень и очень немало) в настройках роутинга есть параметр net.ipv4.route.secret_interval, в секундах, по умолчанию 600. Отвечает за принудительный сброс кеша маршрутов во избежание его переполнения. В дальнейшем от него было решено отказаться — https://github.com/torvalds/linux/commit/3ee943728fff536edaf8f59faa58aaa1aa7366e3

Таким образом, раз в 10 минут ваш кеш сбрасывается, и маршруты выбираются заново. И не всегда так, как хотелось бы.
Поэтому для стабильной работы policy-routing на системах с несколькими аплинками я рекомендую выставлять этот параметр в 0.

sysctl -w net.ipv4.route.secret_interval=0


Можно конечно поставить патч ядра, устраняющий это поведение целиком, но это уже решение не для всех.

Отключать этот сброс вполне безопасно, поскольку в более поздних ядрах никакого дополнительного механизма защиты от переполнения кеша маршрутов введено не было, имеющиеся были сочтены достаточно надёжными.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 21

    0
    Хм, а почему изменение роутинга должно приводить к разрыву соединения? Разве хосту не пофиг, каким маршрутом пришел пакет? Главное, что бы исходящий адрес не менялся.
      0
      Так он изменится — у другого аплинка внешний ip другой.
        –2
        Это же только для новых соединений и после сброса кеша. Если соединение активно маршрут не изменится. Тут нет вариантов.
          0
          Пост не читали? Речь и идёт о проблемах с самопроизвольным сбросом кеша
            0
            Конечно читал. Не припомню, чтобы на Debian была подобная ситуация. Возможно это дистрибутивозависимо.
              0
              Это ядрозависимо. ЕМНИП, у дебиана ядра новее
        +1
        Да, это вам, батенька, не BGP…
          0
          Ну да, действительно, если во владении нету своей сетки, то по другому и не выкрутишься.
            0
            Ну решение-то в общем изначально наколеночное, для домашнего сервера разве что.
              0
              Угу.

              Я ещё наблюдал странное поведение, даже на более или менее современных ядрах — когда кеш не соответствует таблице маршрутов.

              То есть, всё, вроде бы красиво — дефолтный маршрут на хосте указывает на роутер, который всех в инет выпускает, но произвольные адреса в интернете не пингуются, либо весь интернет недоступен.

              Делаем ip route flush cache — и всё поехало. Проблема вылезала на 3.14, кажется, где-то раз в месяц. Сейчас, на 3.18, не видел пока, может пофиксили.
                0
                С таким не сталкивался. На 2.6.32 предложенный способ отлично работает. Принудительно сбрасывать не приходилось никогда. Насколько велик у вас кеш?
                  0
                  Начиная с ядер 3.6 ipv4 кеш вообще выпилен, т.е. вывод команды ip route cache пустой и flush cache ничего не делает. Тут pdf-презентация с оправданиями, почему так сделали.

                  Multipath на таких ядрах совместно с nat уже мало пригоден для практического применения, что особенно заметно на https-сессиях.
                    0
                    А не подскажите, чем тогда реализовать multipath, например в Centos 7, с ядром 3.10?
                      0
                      Есть пример решения, где помимо правил маршрутизации используется ещё ipset и iptables. Выглядит устрашающе, не знаю, возможно есть другие решения.
                      0
                      Угу, я про это тоже читал в процессе решения проблемы. Но факт остаётся фактом — только ip route flush cache помогал восстановить связь. Ядро было точно не старее 3.14
              0
              А можно я задам простой вопрос: а почему надо использовать недетерминистический алгоритм выбора аплинка? Используйте либо хэш от пары ip-адрес порт («последний бит хеша 0 — налево, 1 — направо»), либо, вообще, последний бит IP-адреса. То есть маршрутизировать исходя из маски 0.0.0.1.

              Автоматически снимает все вопросы со «странными contracker'ами», которые вообще можно отключить. Пакет с чётным dst в IP? Аплинк 1. С нечётным? Аплинк 2.
                +1
                Идея мне нравится. Не подскажете, как реализовать +- штатными средствами, скажем в CentOS?

                А хотя есть тут один подводный камень. Но надо померять предварительно. А чтоб померять — реализовать.
                  0
                  iptables -t mangle -A PREROUTING -i $dev_in -d 0.0.0.0/0.0.0.1 -j MARK --set-mark 0x1
                  iptables -t mangle -A PREROUTING -i $dev_in ! -d 0.0.0.0/0.0.0.1 -j MARK --set-mark 0x2
                  0
                  А собственно, отвечая на ваш вопрос: использовать не надо. Использовать можно. Более менее популярное и документированное решение, без изобретения велосипедов. Как часто случается — не без граблей. Ваш вариант, если он так же решается штатными средствами, наверно просто менее популярен и документирован.
                    0
                    Забыл уточнить — в моём практическом случае полосы пропускания аплинков соотносятся 1:2. Соот-но, и weight у меня стоит 1 и 2. То есть вариант чёт/нечет уже не очень хорош.
                      +1
                      1) Матчим в iptables любые биты как хотим, например как тут www.stearns.org/doc/iptables-u32.current.html
                      2) Создаем IP рулы: ip rule add fwmark
                      3) Указываем соответвущие gw для созданных рулов

                  Only users with full accounts can post comments. Log in, please.