Pull to refresh

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

Reading time 3 min
Views 13K
Наткнулся на неприятный подводный камень. Имеем систему с несколькими аплинками, и 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


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

Отключать этот сброс вполне безопасно, поскольку в более поздних ядрах никакого дополнительного механизма защиты от переполнения кеша маршрутов введено не было, имеющиеся были сочтены достаточно надёжными.
Tags:
Hubs:
+21
Comments 21
Comments Comments 21

Articles