Привет, %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.

На этом всё!


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