Dhaf — сделать свой веб-сервис отказоустойчивым доступно для каждого

image-loader.svg

I. Вступление

Здравствуйте, уважаемые читатели.

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

II. Немного о решаемой проблеме

*Прим. автора: для тех, кто хорошо понимает, о чем речь — можно пропустить данный раздел.

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

III.a. Изменение DNS записей веб-сервиса

Само по себе практически ничем не поможет в решении задачи обеспечения отказоустойчивости. В случае падения веб-сервиса, даже если вы оперативно поменяете IP адрес в A-записи на резервный сервер и понадеетесь что сейчас у всех всё заработает, а вы пока разберетесь с основном сервером, — это не сработает, и всякие надежды разобьются о рифы реальности.

DNS сервера, провайдеры, иные промежуточные звенья и просто конечные пользователи уже закэшировали прошлую A-запись из DNS записей вашего доменного имени. Когда они решат обновиться — крайне сложный для прогнозирования вопрос, но в худшем случае крайне не скоро (может пройти несколько суток и более). И низкий TTL кэша записей вам не поможет, ибо:

  • Далеко не все соблюдают TTL;

  • Устанавливать значение TTL близкое к нулю — лишить смысла механизм кэширования. Тем более, если он будет несколько минут, то это уже достаточно позорное время для простоя вашего сервиса.

Аналогично, в данной задаче вам не поможет и добавление нескольких A-записей. Так называемый Round-robin DNS работает совершенно непредсказуемо (как на уровне сети/операционной системы, так и на уровне браузеров).

III.b. Создание нескольких (под)доменов веб-сервиса

Практика и здравый смысл показывает, что это крайне плохое решение. Действительно, можно сделать несколько доменных адресов (или поддоменов) вашего веб-сервиса под разные сервера и раздать со словами: «при условии неработоспособности A, используйте B». Однако, пользователь не должен вручную выбирать адрес, ведь он наверняка будет постоянно ошибаться. Будет добавлять в закладки только резервный узел и не переходить обратно на основной (а что, если они разные по быстродействию/прочему приоритету?). Да и вообще, пользователь не должен знать о том, что что-то пошло не так, это не его проблемы.

III.c. Низкоуровневая работа в рамках «всемирной паутины»

Можно подумать о том, возможно ли основному и резервным серверам назначить один и тот же IP адрес. Или же оперативно на сетевом уровне переключать некий «плавающий» IP между серверами в зависимости от их доступности. Первое возможно, напр., через anycast. Второе возможно, напр., через VRRP с keepalived и имея свою подсеть IP адресов (фактически, для анонсирования минимальный размер /24 (IPv4) или /48 (IPv6) для подсети).

Но всё это, мягко говоря, дорого/сложно (особенно учитывая что IPv4 заканчиваются) хоть и при должном старании, крупных финансовых вливаниях вполне надежно. Тем не менее, такую схему многим реализовать практически нереально (малые и средние веб-проекты, например). Также можно заказать плавающий IP адрес у какого-то ДЦ-провайдера (на рынке бывают предложения даже среди нескольких ДЦ одного провайдера) — однако, зависеть от какого-то провайдера, в т.ч. от ценовой политики, географии, инфраструктуры его ДЦ, и уповать на его волю желание не велико.

III.d. Промежуточные выводы

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

III. Что же делать?

*Прим. автора: в данной главе идёт речь о Cloudflare, но это не является основным объектом статьи.

Небезызвестная компания Cloudflare (по некоторым оценкам, проксирует через свою инфраструктуру почти 20% всего интернета) предлагает мигрировать управление DNS к ним, вместе с тем гарантируя совершенно бесплатно следующее:

Our authoritative DNS is the fastest in the world, offering DNS lookup speed of 11ms on average and worldwide DNS propagation in less than 5 seconds.

Работает с точки зрения использования это дюже просто: у регистратора своего доменного имени вы прописываете NS-сервера Cloudflare, далее в панели управления последнего прописываете необходимые вам DNS-записи, не забывая поставить галочку «Proxied» напротив каждой записи (впрочем, это делается автоматически). И всё, оно уже работает.

Но что будет, если, например, теперь осуществить ping по вашему доменному имени? Вы не увидите там своего IP адреса, там будет IP адрес от Cloudflare. Ибо это работает примерно по следующей схеме:

  • Веб-браузер пользователя запрашивает ваш сайт по доменному имени;

  • Доменное имя через DNS разрешается в IP адрес Cloudflare;

  • Веб-браузер осуществляет HTTP запрос по разрешенному ранее IP адресу, заботливо прикладывая к оному Host header;

  • Cloudflare принимает запрос, связывает его с вашей зоной, анализирует DNS записи которые вы ранее там прописали, и далее работает в качестве обратного прокси-сервера между сервером из A-записи и конечным клиентом.

Благодаря этому и возможно «мгновенное» переключение DNS через Cloudflare. Потому что фактически реальные DNS записи вашего доменного имени не меняются, а меняются настройки реверсного прокси-сервера Cloudflare, которые оформлены в виде DNS записей. К слову, у данного подхода есть ещё ряд преимуществ, и они также бесплатны:

  • Ввиду того, что вы скрываете реальные IP адреса своих серверов за Cloudflare, это повышает их безопасность и приватность;

  • Global content delivery network (CDN)

  • Также вы получаете превосходную защиту от DDoS-атак «из коробки». Опять же, потому что злоумышленники не знают ваших реальных IP адресов.

«Разве Cloudflare не является единой точкой отказа?» — Спросите вы. Фактически, нет. Там уже позаботились о решении проблемы отказоустойчивости (причем сразу несколькими рабочими промышленными методами, включая anycast, round-robin и т.д.). Работоспособность этой инфраструктуры нарушается крайне редко. То есть, используя искомое, вы вполне сможете приблизиться по uptime своего веб-сервиса к таким гигантам как Google, Amazon и т.д.

Резюмируя, отметим: мы можем использовать это в качестве практически мгновенного переключения DNS записей. Однако, делать это вручную — не вариант, но это уже дело техники. Ведь главное, что мы получили инструмент для крайне быстрой смены своих серверов для доменного имени (A-запись в DNS Cloudflare). Об автоматизации этого процесса (и не только) в главе ниже.

IV. Как же быть?

Естественным образом я подвожу вас к моему проекту с открытым исходным кодом под названием Dhaf. Он представляет собой легковесный распределенный высоко-доступный failover (т.е. представляет собой кластер) для веб-сервисов, написанный на современном кросс-платформенном C# .NET (поддерживаются Linux, Windows и macOS).

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

Вкратце, в архитектуре dhaf заложены некие «переключатели» (switchers) — различные провайдеры для управления точками входа в веб-сервис, средства проверки работоспособности (health checkers) и провайдеры для уведомлений (notifiers). Он чрезвычайно гибкий, расширяемый и простой в использовании и настройке. У кластера существует т.н. лидер и ведомые узлы. Все из них занимаются мониторингом, но управляет состоянием и уведомлениями только лидер. Стоит отметить, что в качестве distributed configuration system (DCS) используется etcd. Какие основные возможности? А вот какие:

  • Failover (при необходимости dhaf автоматически и прозрачно переключит ваши серверы для конечных клиентов);

  • Switchover (ручное переключение ваших серверов) — полезно для отладки и выполнения обслуживания серверов незаметно для конечного клиента;

  • Поддержка нескольких различных сервисов в одном кластере dhaf (которые могут «располагаться», например, на поддоменах вашего доменного имени);

  • Поддержка использования нескольких провайдеров уведомлений в одном dhaf кластере;

  • Точки входа (entry points) для веб-сервиса располагаются по приоритету (т.е. если снова стал доступен некогда упавший сервер и он приоритетнее текущего — также произойдет автоматическое переключение, т.н. switching);

  • Провайдеры уведомлений об изменениях состояния ваших веб-сервисов и/или dhaf кластера. Из коробки уже доступны следующие:

  • Действительно гибкая настройка health checks для сервиса;

  • Вся пользовательская конфигурация в «дружелюбном» формате YAML;

  • Только вы решаете, откуда проверять доступность ваших веб-сервисов;

  • Удобный CLI для проверки и управления кластером dhaf;

  • REST API для проверки и управления кластером dhaf;

  • Возможность легко создавать собственные провайдеры для switchers, health checkers и notifiers на C#, подключая их динамически в качестве расширений;

  • Возможность подключения собственных исполняемых скриптов (напр., на языке Python) в качестве switchers и health checkers;

  • Является распределенным высоко-доступным кластером.

Какие преимущества от того, что dhaf — кластер? Возможно, это для кого-то не очевидно, так что я поясню:

  • Если какой-то из узлов dhaf кластера отвалится, то сам кластер по-прежнему продолжит свою работу (до тех пор, пока это возможно). Если вышел из строя лидер, то тотчас начнётся т.н. гонка за лидера, т.е. методом «кто первый того и тапки» будет определен новый лидер.

  • Health checks для веб-сервиса осуществляются всеми доступными узлами, и решение о (не)доступности оного является коллективным. И только если большинство считает, что сервис недоступен, то лидер кластера начинает процедуру по переключению точки входа в веб-сервис (в случае с switcher-провайдером Cloudflare он меняет A-запись в DNS Cloudflare на очередной сервер). Это элегантно решает проблему, когда один из узлов решил, что веб-сервис недоступен, хотя на самом деле это не так для реальных пользователей.

Теперь самое время рассказать о том как всё это добро запустить. Однако, это уже написано в `README.md` репозитория на Github (см. секцию «Quick Start»), и повторяться не очень хочется. Ниже показано, как может выглядит конфигурация кластера на одном из узлов (все credentials являются вымышленными):

config-n1.dhaf

dhaf:
  cluster-name: habr-cr
  node-name: node1

etcd:
  hosts: http://111.111.1.1:2379,http://111.122.2.2:2379,http://111.133.3.3:2379

services:
  - name: main
    domain: habr.com
    entry-points:
      - name: serv1
        ip: 111.101.1.1
      - name: serv2
        ip: 122.102.2.2
    switcher:
      type: cloudflare
      api-token: f-PFRRRqVVVtPaaa_Z000YN3Bb222bHHb111KKKb
      zone: habr.com
    health-checker:
      type: web
      schema: https

notifiers:
  - type: email
    name: habr-mail
    from: dhaf@habr.com
    to: admin@habr.com
    smtp:
      server: smtp.habr.com
      port: 465
      security: ssl
      username: dhaf@habr.com
      password: 5bjAQjFGKoCIVNAc

  - type: tg
    token: 4105703518:BtiWEX6mKwpW0ASS2BSSG6zSkh3M04CsmiX
    join-code: ox3a35kYloJrc9OY
    name: habr-tg

Консольный вывод одного из узлов dhaf:

Рис 1. Консольный вывод одного из узлов dhafРис 1. Консольный вывод одного из узлов dhaf

Работа с CLI может выглядеть так так:

Рис 2. Пример работы с dhaf.cliРис 2. Пример работы с dhaf.cli

V. Некоторые рекомендации по работе с dhaf

Ниже вы сможете обнаружить условия, при которых кластер dhaf будет работать максимально плодотворно:

  • Не размещайте узлы кластера dhaf на тех же серверах, где и ваш веб-сервис;

  • Можно (и это логично) размещать узлы etcd там же где dhaf;

  • Кол-во узлов etcd должно быть не менее трёх (тогда возможно пережить падение одного из узлов). Подробнее тут;

  • Кол-во узлов dhaf должно быть не менее двух, но, учитывая, что они обычно работают там же где и etcd, то логично их сделать также три. Тем не менее, даже при кластере из двух узлов dhaf способен пережить падение одного из узлов;

  • Для работы узла кластера dhaf (даже в связке с etcd) достаточно самого дешевого виртуального сервера (включая облачные), поскольку нагрузка на него минимальна в силу того что он не занимается обслуживанием кучи пользователей, — он занимается здоровьем вашего веб-сервиса;

  • Располагайте узлы dhaf кластера (и etcd) у разных провайдеров в разных дата-центрах. Это убережет вас от тех неприятных случаев, когда у одного из провайдеров накрылась вся его инфраструктура. Также узлы стоит географически располагать там, откуда предполагается использование вашего сервиса (т.е. с точки зрения сети «приближаем» узлы к реальным пользователям);

  • Точек входа для веб-сервиса в конфигурации dhaf должно быть указано не менее двух, однако, пожалуй, это очевидно;

  • Если у вас есть желание и/или потребность балансировать нагрузку, то dhaf не для этого. Его цель — обеспечивать рабочую точку входа в веб-сервис, и он ни в коем случае не является прокси-сервером. Таким образом, если есть необходимость вышеуказанного, то точками входа в конфигурации dhaf должны быть сервера с, напр., HAProxy (или его аналог), функционал коих, в частности, предназначен как раз для этого.

VI. Заключение

Описываемый в статье вариант для решения проблемы отказоустойчивости веб-сервисов не претендует на единственно возможный. Решение предложено, использовать его или нет — решать вам.

Учитывая, что dhaf — проект с полностью открытым исходным кодом, буду рад если вы присоединитесь к разработке. В случае обнаружения багов просьба создать bug report. Если же вам не хватает какого-то функционала, стоит создать feature request.

Вы можете присоединиться к Telegram-чату для обсуждения работы dhaf.

С уважением,
Петр Осетров.

© Habrahabr.ru