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

Привет, %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 .
На этом всё!
Если у тебя есть вопросы, комментарии и/или замечания – заходи в чат , а так же подписывайся на канал .
О способах отблагодарить автора можно почитать на странице “Донаты ”.