Иногда, а скорее всего довольно часто, возникает необходимость обеспечения отказоустойчивости серверов или ещё лучше приложений, запущеных на этих самых серверах.
Способов это сделать довольно много:
— может сам сервис изачально придуман с возможностью отказоустойчивости — его можно запустить на нескольких серверах и клиент сам найдет рабочий из списка;
— можно наворотить кластер средствами операционной системы;
— можно придумать что-то с виртуализацей (тот же кластер, только вид сбоку);
Но к сожалению иногда, и таки довольно часто в моей личной практике, возникает ситуация выходящая за рамки этих возможностей: денег нет, сеть есть, приложение самописное на коленке — кластер не соберешь, клиентская часть умеет ходить только на один сервер. И вдруг это приложение стало критичным, надо сделать 25x8x366. Под катом один из довольно безобидных способов.
Предположим, что у нас уже есть какая-то сеть с серверными свитчами, пользователями и всякими прочими прелестями. Было бы неплохо чтоб серверных свитчей было два и в разных зданиях, а то мало-ли свет потухнет? Но данный способ можно свести и к одному свитчу без особых усилий. Итак, см. картинку сверху — два серверных свитча-L3, какая-то ip-сеть между ними, в сети динамическая маршрутизация(у меня будет eigrp, но это не сильно важно), где-то в этой сети живут пользователи — почти всеохватывающий случай. Критичный сервис (пусть это будет веб-приложение доступное на 80м порту) работает на сервере Server1 включенном в свитч swc01 (допустим, Cisco 3750G).
Первым делом добываем второй сервер Server2 и включаем его во второй свитч swc02 (пусть это Cisco6504. свитчи разные для того чтоб показать небольшое различие в синтаксисе конфига, см. далее). Потом применяем силу к разработчикам, чтоб они установили приложение на второй сервер и подумали о синхронизации, репликации и прочей тирьям-пам-пации. Вот, в принципе и всё :) Так пользователям и скажем — если лезешь на 192.68.1.2 (server1) и не работает, то попробуй лезть на 192.168.2.2 (server2), а после пишем заявление об увольнении ПСЖ. Чтоб не страдать поиском новой работы попробуем сделать всё незаметно для пользователей.
Для начала повесим на сервера по дополнительному интерфейсу loopback. И навесим на оба этих интерфейса одинаковый адрес 172.16.1.1/32, который и будет отныне единым адресом доступа к сервису. Далее можно было бы той же динамической маршрутизацией заставить сервера сообщать в сеть о том что они живы и есть, но лично я не люблю динамики на серверах. Да и пусть сетевыми вопросами сеть занимается, а то так и программисты будут маршрутизацию настраивать — непорядок!
Далее, swc01 пытается установить tcp-сессию на порт 80 на адрес eth-интерфейса сервера server1 и в случае успеха устанавливает у себя статичный маршрут до 172.16.1.1 через next-hop 192.168.1.2 (eth от сервера server1) и сообщает об этом маршруте в сесть протоколом динмической маршрутизации (eigrp).
А swc02 следит за доступностью (пытается установить tcp-сессию) и server1 и server2 и если 1 упал, а 2 работает, то устанавливает свой статичный маршрут до 172.16.1.1 через 192.168.2.2 (eth от server2) и тоже сообщает об этом в сеть через динамику.
Примерно так. Теперь к деталям:
swc01 config:
router eigrp 1 redisribute static ! rtr 1 type tcpConnect dest-ipaddr 192.168.1.2 dest-port 443 control disable timeout 500 ! rtr schedule 1 life forever start-time now ! track 1 rtr 1 ! ip route 172.16.1.1 255.255.255.255 192.168.1.2 track 1 !
swc02 config:
router eigrp 1 redisribute static ! ip sla monitor 1 type tcpConnect dest-ipaddr 192.168.1.2 dest-port 80 control disable timeout 500 ! ip sla monitor schedule 1 life forever start-time now ! ip sla monitor 1 type tcpConnect dest-ipaddr 192.168.2.2 dest-port 80 control disable timeout 500 ! ip sla monitor schedule 2 life forever start-time now ! track 1 boolean list and object 1 not object 2 ! ip route 172.16.1.1 255.255.255.255 192.168.2.2 track 1 !
// обратите внимание на разницу синтаксиса ip-проб. в старых ios-ах (вроде до 12.2.20) надо было писать rtr, а в новых ip sla
Единственная хитрость заключена в track-е на втором свитче, который (!obj1 && obj2).
Зачем именно так? Потому что по-другому не получится.
Можно пойти в лоб и просто навесить два статичных маршрута на обоих свитчах. Тогда часть сети будет ходить на один сервер, а часть на другой — иногда это хорошо, так как появляется некоторая балансировка, но в большинстве случаев разработчики хотят точно и детерминировано знать какой сервер рабочий в текущий момент.
Можно сделать просто по одному ip-sla до ближайшего сервера и статику с трекингом этого ip-sla-я, просто на одном из свитчей статика будет с большей дистанцией:
ip route 172.16.1.1 255.255.255.255 192.168.2.2 200 track 1
Тогда в момент выключения и включения основного сервера в сети появятся два маршрута и мы придем к недетерминированному состоянию.
Можно попробовать на втором свитче тречить не доступность сервера, а наличие в таблице маршрутизации маршрута до loopback-а и если он есть, то не устанавливать свой маршрут, а если нету — то установить:
track 1 ip route 172.16.1.1/32 reachability ip route 172.16.1.1 255.255.255.255 192.168.2.2 track 1
Проблема ровно такая же. Когда упадет основной сервер — маршрут сперва пропадет из таблицы, потом установится свой статичный и всё, больше никогда оттуда не пропадет, даже если основной сервер появится. И опять будет недетерминированное состояние.
Автор: Karroplan