DNS Fail


В сети любого Интернет-провайдера можно встретить такой обязательный элемент, как кэширующий DNS сервис. А поскольку работа сети Интернет без службы DNS невозможно, серверов таких будет минимум два, с обязательным резервированием и балансировкой. В заметке я постараюсь описать один из вариантов балансировки нагрузки между несколькими кэширующими серверами на основе Cisco IP SLA.


Возможные решения


Балансировка на клиентской стороне


Самым простым способом резервирования кэширующего DNS является настройка на клиентской стороне нескольких записей с адресами DNS-серверов. Адреса DNS-серверов можно сообщить клиенту различными способами:


  • через соответствующие атрибуты DHCP (для тех абонентов кто использует технологию IPoE и автоматическую настройку);


  • по протоколу LCP для абонентов PPPoE (или любой другой PPP-технологии);


  • указав в приложении к договору или инструкции для абонентов, чье подключение по IP настраивается вручную.

Клиент, в случае недоступности первого сервера, автоматически переключиться на второй и т.д. Но этот способ имеет два очевидных недостатка.


Первый — отсутствует полноценная балансировка нагрузки. Пока первый сервер доступен и работает (а мы исходим из того, что отказ сервера вещь хоть и неприятная, но крайне редкая), у абонентов нет никакого резона переключаться на второй, и тот простаивает.


Второй недостаток полностью проистекает из первого, но имеет куда большее значение. Критерии переключения на резервный сервер полностью определяются настройками на клиентской стороне. Вот, например, описание стандартных таймингов DNS клиента Windows XP. Из статьи следует, что Windows XP переключиться на использование резервного сервера только в том случае, если основной не ответит в течении одной секунды. Т.е. можно представить ситуацию, когда, в результате перегрузки, ошибки конфигурирования или сбоя, основной сервер работает неудовлетворительно, но отвечает в течении 0,95 сек. Очевидно, что при такой задержке ни о какой нормальной работе Интернет у абонента речи быть не может. Но, поскольку время ответа менее одной секунды, абоненты "будут плакаться, колоться, но продолжать есть кактус", точнее будут испытывать деградацию сервиса, но не переключатся на простаивающий резервный DNS-сервер.


Конечно, подобное поведение службу DNS является аварийным и должно быть обнаружено системой мониторинга с последующей эскалацией проблемы. Но вопрос мониторинга находится в стороне от темы заметки.


Destination NAT


Другой способ балансировки — destination NAT. Это решение, которое активно применяется для распределения нагрузки на кластерах web-серверов. В этом случае абоненты используют единственный адрес DNS-сервера, который является адресом интерфейса NAT, а реальные DNS-сервера имеют приватную адресацию. При обращении абонентов к DNS-серверу происходит трансляция в запросе Destination IP-address в адрес одного из серверов. При таком подходе нагрузку можно распределить равномерно. Но подобный метод является несколько избыточным, так как полноценный NAT, в случае с web-серверами, оправдан в силу того, что транспорт там обеспечивает протокол TCP, который является stateful, в отличии от stateless транспорт UDP, обычно применяемого для запросов DNS. В отличии от обмена трафика с web-сервером, диалог клиента с DNS-сервером очень лаконичен и предполагает только пару запрос-ответ.


Статическая маршрутизация


Более простой способ — статические маршруты. Представим, что у нас есть три DNS-сервера с IP-адресами:


  • 10.0.0.1,
  • 10.0.0.2,
  • 10.0.0.3.

На каждом из которых сконфигурирован Loopback-интерфейс 10.10.10.10. Служба DNS настроена на получение запросов на данный адрес, а в firewall есть правила для TCP/UDP-портов 53.


В таком случае любой из этих серверов готово обслуживать DNS-запросы с destination-адресом 10.10.10.10. Это и будет IP-адрес DNS-сервера, которым пользуются все наши абоненты. Осталось распределить их запросы между реальными серверами. Тут ничего особенного делать не требуется. Сконфигурируем на маршрутизаторе, куда подключены наши сервера три статических маршрута:


ip route 10.10.10.10 255.255.255.255 10.0.0.1
ip route 10.10.10.10 255.255.255.255 10.0.0.2
ip route 10.10.10.10 255.255.255.255 10.0.0.3

В результате мы получим такую картину:


Router#show ip route 10.10.10.10
Routing entry for 10.10.10.10/32
  Known via "static", distance 1, metric 0
  Routing Descriptor Blocks:
  * 10.0.0.1
      Route metric is 0, traffic share count is 1
    10.0.0.2
      Route metric is 0, traffic share count is 1
    10.0.0.3
      Route metric is 0, traffic share count is 1

Теперь стандартный механизм балансировки per-flow будет последовательно раскладывать запросы от разных абонентов по трем имеющимся маршрутам:


Схема балансировки


Применение IP SLAs DNS для Failover


Теперь, когда мы позаботились о балансировке, осталось решить вопрос с переключением трафика в случае отказа одного из серверов. В этом нам поможет механизм Cisco IP SLA, а точнее функция IP SLAs DNS Operation.


Описание работы


Кратко работу данной функции можно описать следующим образом:


  1. В конфигурации маршрутизатора создается три записи IP SLA, которые периодически выполняют запрос к каждому из трех DNS-серверов (например, стандартный запрос A-RR www.google.com). Результат запроса определяет состояние записи.


  2. С записями IP SLA связаны три объекта Track, которые переходят в статус DOWN, если состояние соответствующего IP SLA отлично от ОК.


  3. Три статических маршрута из раздела выше связываются со своим объектом Track

Теперь, если в определенный момент один из серверов не ответит или ответит некорректно на DNS-запрос, соответствующий объект Track перейдет в состояние DOWN, а связанный с ним статический маршрут исчезнет из таблицы маршрутизации. В результате проблемный сервер будет исключен из механизма балансировки.


Пример конфигурации


Конфигурация IP SLA:


ip sla 1
 dns www.google.com name-server 10.0.0.1
 timeout 5000
 frequency 9
 threshold 10

ip sla 2
 dns www.google.com name-server 10.0.0.2
 timeout 5000
 frequency 9
 threshold 10

ip sla 3
 dns www.google.com name-server 10.0.0.3
 timeout 5000
 frequency 9
 threshold 10

Активация и настройка трэкинга:


ip sla schedule 1 life forever start-time now
ip sla schedule 2 life forever start-time now
ip sla schedule 3 life forever start-time now

track 1 ip sla 1
track 2 ip sla 2
track 3 ip sla 3

Настройка маршрутов с привязкой к трэкингу:


ip route 10.10.10.10 255.255.255.255 10.0.0.1 track 1
ip route 10.10.10.10 255.255.255.255 10.0.0.2 track 2
ip route 10.10.10.10 255.255.255.255 10.0.0.3 track 3

Тестирование


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


Router# show ip sla statistics

IPSLA operation id: 1
    Latest RTT: 1 milliseconds
Latest operation start time: 15:33:27 UTC+7 Wed Aug 17 2016
Latest operation return code: OK
Number of successes: 373
Number of failures: 0
Operation time to live: Forever

IPSLA operation id: 2
    Latest RTT: 1 milliseconds
Latest operation start time: 15:33:27 UTC+7 Wed Aug 17 2016
Latest operation return code: OK
Number of successes: 373
Number of failures: 0
Operation time to live: Forever

IPSLA operation id: 3
    Latest RTT: 1 milliseconds
Latest operation start time: 15:33:27 UTC+7 Wed Aug 17 2016
Latest operation return code: OK
Number of successes: 373
Number of failures: 0
Operation time to live: Forever

Попробуем отключить сервис DNS на сервере DNS-1. При следующей проверки (они у нас происходят раз в девять секунд) соответствующий IP SLA сообщит о проблеме:


Router# show ip sla statistics 1

IPSLA operation id: 1
    Latest RTT: NoConnection/Busy/Timeout
Latest operation start time: 15:37:48 UTC+7 Wed Aug 17 2016
Latest operation return code: Timeout
Number of successes: 1
Number of failures: 1
Operation time to live: Forever

А соответствующий маршрут с next-hop 10.0.0.1 исчезнет из таблицы маршрутизации:


Router#show ip route 10.10.10.10
Routing entry for 10.10.10.10/32
  Known via "static", distance 1, metric 0
  Routing Descriptor Blocks:
  * 10.0.0.2
      Route metric is 0, traffic share count is 1
    10.0.0.3
      Route metric is 0, traffic share count is 1

Теперь запросы клиентов распределяются между двумя оставшимися серверами. Если мы вновь запустим сервис, то при следующей проверке IP SLA вернет маршрут и сервер вновь начнет участвовать в балансировке.


Недостаток метода


Основной и самый существенный недостаток данного метода — минимально возможная периодичность опроса девять секунд. Очень часто подобная "оперативность" является критической. К сожалению — это ограничение функционала Cisco. Если кто-то подскажет, как его обойти — буду очень благодарен.


Заключение


Мы рассмотрели применение статической маршрутизации и Cisco IP SLA при балансировке и резервировании сервиса кэшируюего DNS. Очевидные преимущества метода:


  1. простота настройки;
  2. все работает на маршрутизаторе и не требует дополнительных средств;
  3. контролируется ответ сервиса, а не только, к примеру, доступность по ICMP echo request.

Недостаток:


  1. минимальный период опроса 9 секунд, что означает время реакции до 9 * 2 = 18 секунд.
Поделиться с друзьями
-->

Комментарии (21)


  1. pfactum
    17.08.2016 13:01

    Есть ещё софтовый метод: https://github.com/LanetNetwork/dnsbalancer
    Или вот: http://dnsdist.org/


    1. Prototik
      17.08.2016 13:54
      +1

      Ну, это не исключает возможность отказа сервера с софтовым балансировщиком, так что мы опять упираемся в невозможность лёгкого горизонтального масштабирования.


      1. pfactum
        17.08.2016 14:04
        +1

        Да, поэтому нужно обязательно резервировать и балансировщики. Например, держать несколько балансировщиков + keepalived.


    1. kvinogradov
      17.08.2016 16:45

      Спасибо. Надо посмотреть решения. Ничего пока не могу сказать.


  1. ildarz
    17.08.2016 14:45
    +1

    Вы беспокоитесь, что DNS-клиент в XP переключается только при таймауте выше секунды, а в примере в SLA у вас 5 секунд прописаны — как-то нелогично. ;)

    > Теперь стандартный механизм балансировки per-flow будет последовательно раскладывать запросы от разных абонентов

    Имеется в виду per port? А трафик от одного и того же клиента куда пойдет? На один и тот же сервер? А если он отказал, вы предлагаете клиенту подождать «до 9 * 2 = 18 секунд» (и накинем еще 5 сверху на прописанный таймаут) вместо стандартной секунды, когда у клиента несколько DNS прописаны?

    По-моему, этот подход не стоит применять сам по себе — надо комбинировать со стандартной практикой выдачи нескольких DNS (каждый из которых уже может на самом деле являться балансировщиком).

    > если в определенный момент один из серверов не ответит или ответит некорректно на DNS-запрос

    А «ответит некорректно» — это как? Каковы критерии «корректности» ответа и вообще настраиваются ли они?

    А что будет, если «некорректный ответ» выдадут все включенные в настройку DNS (ну, например, домен гугла разделегируется :D)? Есть ли возможность сделать дополнительные критерии для проверки?


    1. kvinogradov
      17.08.2016 16:41

      а в примере в SLA у вас 5 секунд прописаны


      Скажу больше. Это timeout. Более критичен threshold (который тоже неявно 5000мс). Так что все еще жестче! ))) Конечно это ошибка. Спасибо! Исправил и добавил в конфиг threshold 10

      Имеется в виду per port? А трафик от одного и того же клиента куда пойдет?


      Если мне не изменяет память, Cisco по умолчанию раскладывает per flow. Критерии отдельного flow: src ip + dst ip + src port + dst port. Так что, по идее, трафик нового запроса должен уйти на другой сервер (в пределах вероятности), так как flow другой. Но есть мнение, что Cisco не учитывает src port, так как в production замечены случаи, что запросы одного абонента стабильно попадали на один резолвер.

      вы предлагаете клиенту подождать


      По сути — да. Только threshold можно поправить, так что просто <=9 секунд. И тут, в комментариях ниже, что нужно присмотреться к версии IOS. Вроде бы можно и меньше, но ничего не могу сказать — у меня 9.

      А «ответит некорректно» — это как?… домен гугла разделегируется


      Например NXDOMAIN:

      IPSLA operation id: 200
      	Latest RTT: 0 milliseconds
      Latest operation start time: 20:20:02 UTC+7 Wed Aug 17 2016
      Latest operation return code: DNS query error
      Number of successes: 0
      Number of failures: 11
      Operation time to live: Forever


      Конечно, тут основная идея, что мы выбираем неких «контрольный» домен и допускаем, что вероятность его сбоя или сбоя корневых серверов существенно ниже сбоя вашей инфраструктуры или ошибки конфигурации ваших инженеров. Например, DNS-ом у вас внезапно начал заниматься студен-практикант. )))) Тогда, если однажды Вы получите nxdomain вместо www.google.com, логично в первую очередь проверить, как там дела у студента и что он делает с кэшом, а потом звонить в гугол ))))


      1. Loiqig
        17.08.2016 18:03
        +1

        Но есть мнение, что Cisco не учитывает src port, так как в production замечены случаи, что запросы одного абонента стабильно попадали на один резолвер.

        Конечно это всё от Cisco зависит, но если есть возможность то решается вот этой командой: ip cef load-sharing algorithm include-ports source destination. По умолчанию не так.

        Собственно абонент может и запросы постоянно с одного порта посылать. Особенно если это активный DNS.


        1. kvinogradov
          17.08.2016 18:10

          А вот за это спасибо!


  1. drumken
    17.08.2016 15:18
    +1

    Добрый день.
    Разве
    track 1 ip sla 1
    track 2 ip sla 1
    track 3 ip sla 1
    не значит что все три трека опираются на 1й sla?

    И может это ограшничения именного вашей версии IOS, но я использовал меньшие значения frequency


    1. kvinogradov
      17.08.2016 16:24

      Конечно это опечатка. Спасибо, что заметили! Исправил


  1. Ant0ni0n
    17.08.2016 15:18
    +1

    «Активация и настройка трэкинга:»
    Предполагаю, что настройка привязки трэкинга не совсем правильно написана:
    track 1 ip sla 1
    track 2 ip sla 1
    track 3 ip sla 1
    может надо так:
    track 1 ip sla 1
    track 2 ip sla 2
    track 3 ip sla 3


    1. kvinogradov
      17.08.2016 16:24

      Конечно это опечатка. Спасибо, что заметили! Исправил


  1. blind_oracle
    17.08.2016 17:22

    А мы просто выдаём на каждый DHCP-запрос DNS-сервера в случайном порядке, а сами IP серверов — виртуальные через VRRPv3, которые распределены по реальным серверам.

    В итоге имеем практически идеальную балансировку нагрузки и время реакции при отказе сервера в 0.1 секунды.


    1. kvinogradov
      17.08.2016 18:14

      Это с DHCP. А если DNS прописан в настройка Virtual-Template для PPPoE и настраивается по LCP? Либо два Vt и думать как их распределить равномерно. Либо менять конфиг Vt через равные интервалы времени. Либо опять же — уходить на DHCP.


      1. blind_oracle
        17.08.2016 21:37

        Да, тут всё зависит от архитектуры, но сейчас всё больше популярен т.н. IPoE где эта схема вполне применима.
        Она, как минимум, проще в настройке, не имеет SPOF в виде роутера (который тоже тогда придётся резервировать, городить динамику и т.п.).

        Ну, и как сказали ниже, анонсы IP со стороны сервера выглядят красивее. На том же OSPF можно настроить суб-секундные таймауты и время реакции будет почти мгновенным.


        1. kvinogradov
          18.08.2016 07:25

          Это правильно. Так и делаем. Единственное, что маршрутизация, в отличии от IP SLA, сама по себе, не контролирует работу сервиса, а только достижимость хоста.


          1. blind_oracle
            18.08.2016 11:39

            Ну, никто не мешает Healthcheck любой на серверах поставить и тушить анонс как только обнаружены проблемы. У нас, в принципе, так в VRRP сделано — как только DNS служба наворачивается, VRRP-демон уходит в BACKUP-state.


  1. Loiqig
    17.08.2016 17:54
    +1

    А мне нравится когда подобные задачи решены чистой маршрутизацией — anycast адресацией. Конечно это не самый простой способ и для этого нужно активное взаимодействие с таблицей маршрутизации со стороны устройств в сети назначения. Но, IMHO, в целом получается красивее. Нету NAT, нету внешнего по отношению к сети сервиса такого как IP SLA.


    1. kvinogradov
      17.08.2016 18:11

      Интересно. А чуть подробней?


      1. Loiqig
        17.08.2016 18:49

        Собственно это просто продолжение вашего примера. Вместо статик маршрутов поднимаем динамические в каком-либо из протоколов маршрутизации. Если серверы в разных устройствах то просто делаем redistribute, но тут опять имеем проблему что линк может быть, а сервер не отвечать.

        Поэтому поднимаем маршрутизацию на самом сервере, фильтруем максимально анонсы чтобы обрабатывалось по минимуму и не сильно ресурсов отбирало. Если ломается что-то на сервере с маршрутизацией или сетью то соответственно маршрут исчезает. Время реакции накручивается таймерами. Т.е. делаем сервер активным непосредственным участником, а не просто чтобы он отпинывался на IP SLA.

        Для link-state протоколов удобно иметь данные маршруты как external, чтобы проще метрикой управлять было.

        Так же можно полностью резервный сервер поднимать, сервера распределённые по территориям — трафик пойдёт по таблице маршрутизации: как ближе, как настроил администратор. Для DNS, DHCP, NTP вообще никаких проблем не будет.


        1. kvinogradov
          17.08.2016 20:41

          Ясно. Такое делаем. Я просто как-то не сразу понял, что под anycast имеется ввиду. Тут только один аспект в пользу IP SLA: сам маршрутизатор, по сути, живость сервиса контролирует, а не только достижимость хоста. Т.е. ловим падение демона, к примеру, или ошибку конфигурации без внешнего мониторинга.

          А в остальном — согласен. Quagga на самом DNS и полный вперед.