Кластеризация и доступность

Edit...
basics
Illustrated by Igan Pol

Привет, %username%! Часто можно слышать, что “приложение запущено в кластере” или не редко вопросом для новичков на собесе может быть такое: “Что такое кластеризация приложения?” или “Что такое HA?”

Терминология#

Пробежимся по основным терминам:

  • HA – или “High Availability” это высокая доступность предоставляемого сервиса;
  • Кластер – это группа компьютеров/серверов, предназначенных для выполнения одной задачи.
  • Кластеризация приложений – это объединение нескольких экземпляров приложений запущенных на разных серверах (или на одном, но зачем?) в группу, которая для внешнего потребителя (клиента) будет выглядет как один сервер, для чего перед кластером ставится балансировщик нагрузки.
  • Балансировщик нагрузки – это программа (но иногда и аппаратное решение), которая принимает пользовательские подключения и по определенному алгоритму раскидывает запросы от клиентов между “одинаковыми серверами приложения”, таким образом снижается нагрузка на единичный сервер/сервис.
  • Масштабируемость – это способность увеличивать или уменьшать ресурсы определенного типа, если система нуждается в сокращении или увеличении.

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

Давай на примере#

Мне кажется более наглядным использовать живые примеры для простоты понимания. Давай возьмем мой любимый интернет-магазин “У дяди Миши”. Посмотрим на группы серверов, из которых состоит “весь интернет-магазин”:

  • Группа “Frontend” – Пусть будет Nginx (принимает пользовательские подключения, раскидывает запросы между серверами “Backend” и отдает статику), тут же может стоять какой-нибудь Node/Nuxt для SSR;
  • Группа “Backend” – Пусть будет PHP-FPM (типичный бэкенд на типичном Bitrix), тут же могут стоять обработчики каких-то очередей;
  • Группа “Database” – Пусть будет MySQL (обычная БД для Bitrix, потому что с PostgreSQL это добро не умеет работать);

Сюда смело можно накидать еще сервисов, но я пока не буду усложнять – попробую как есть объяснить “на пальцах”.

Где мой микроскоп?#

С терминами и вводными для примера мы определились, а теперь давай каждую группу рассмотрим ближе и посмотрим на нее в формате “от простого к сложному”. Пойдем по порядку со стороны “клиента” и начнем группы “Frontend”.

Frontend#

В самом простом примере у нас в качестве фронта может быть один сервер. Ставишь на него Nginx, настраиваешь Nginx чтобы он слушал 80/443 порты и отдавал статику из нужной папочки. Готово!

Магазин растет и один сервер не справляется. Что делать? Ну можно этот сервер проапгрейдить и накинуть ему мощностей. А можно пойти другим путем – поставить рядом еще один такой же и сделать из них кластер. Например настроить на них KeepAlived , а можно выдать им разные “белые” IP-адреса и записать их в DNS. В простейшем случае Round-Robin DNS отвечает на запросы не одним IP-адресом, а списком из нескольких адресов серверов. Благодаря алгоритму round-robin, с каждым ответом последовательность IP-адресов в отдаваемом списке меняется. Обычно простые клиенты пытаются установить коннект с первым IP-адресом из списка и таким образом разным клиентам будут выданы адреса разных серверов, что распределяет общую нагрузку между серверами.

В обоих вариантах получившуюся группу Frontend-серверов можно считать кластером, только “кластеризация” сервиса Nginx выполняется разными способами.

Балансировщиком нагрузки для кластера Frontend может быть KeepAlived, RR DNS, Anti-DDoS от провайдера, baremetal LB – вариантов как видишь много.

Backend#

С фронтом мы разобрались, а теперь на очереди Backend. Тут в типичном интернет-магазине можно сделать максимально просто. Сделаем несколько серверов в этой группе, настроим их идентично, добавим их IP-адреса в настройки upstream’ов в каждом из Nginx группы Frontend.

Если ты забыл, то настройка апстримов выглядит в примитиве вот так:

upstream bitrix_backend {
    server 192.168.232.31:8080 fail_timeout=3s max_fails=3 weight=2;
    server 192.168.232.32:8080 fail_timeout=3s max_fails=3 weight=2;
    server 192.168.232.33:8080 fail_timeout=3s max_fails=3 weight=2;
    server 192.168.232.34:8080 fail_timeout=3s max_fails=3 weight=2;
    server 192.168.232.35:8080 fail_timeout=3s max_fails=3 weight=2;
    server 192.168.232.39:8080 backup;
}

Если тебе не особо понятно, что написано в этом конфиге, то срочно иди в документацию Модуль ngx_http_upstream_module .

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

Балансировщиком нагрузки для кластера Backend будет может выступать как отдельно стоящий балансировщик, так и сам кластер Frontend.

Database#

Кластеризация БД это один или несколько хостов базы данных, между которыми можно настроить репликацию. Я уже писал отдельно в статье [MySQL] Репликация Master-Slave про репликацию в режиме “master-slave”. Поясню “а нахрена оно тебе надо?” Не смотря на очевидность некоторых моментов, не указать их будет глупо.

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

Дополнительно, кластеризация позволяет сильно отсрочить появление ошибки [MySQL] Максимальное количество коннектов и увеличить количество обработанных запросов на чтение (и в некоторых случаях на запись при другом типе репликации).

Балансировщиком нагрузки для кластера Database, в нашем случае кластер MySQL, может выступать например MaxScale, HAProxy, ProxySQL и в этот балансировщик будут ходить сервера кластера Backend.

Итоги#

Кластеризация приложений делает серверную систему масштабируемой, поскольку позволяет легко добавлять или удалять серверы из кластера. Возможность масштабирования позволяет динамически менять “размер инфраструктуры” в зависимости от нагрузки. Перед глобальной распродажей мы довольно легко увеличиваем количество серверов, а после так же легко уменьшаем их количество. А при использовании облачных облачных решений вроде AWS, GCP, DO или банального Kubernetes, можно масштабироваться под нужную нагрузку в автоматическом режиме.

Использование кластеризации значительно снижает вероятность простоя, поскольку обычно для отказа кластера серверов требуется отказ нескольких серверов.

Реальная архитектура спроектированная мною, способная выдержать до 230-250rps (и более при должном масштабировании) доступна в картинке у меня на Patreon .

На этом всё!


Если у тебя есть вопросы, комментарии и/или замечания – заходи в чат , а так же подписывайся на канал .

О способах отблагодарить автора можно почитать на странице “Донаты ”.