Горизонтальное масштабирование - техника, которая позволяет решить две задачи: выдержать большую нагрузку и повысить отказоустойчивость системы. Она используется как для нагруженных так и не нагруженных сайтов, которым важно оставаться работоспособными в случае отказа сервера. А сервера имеют свойство ломаться.
Для горизонтального масштабирования нужно как минимум два одинаковых сервера, на которые выполняется деплой приложения. Серверов может быть и три и больше. Главное в этой схеме то, что эти сервера равноправны и взаимозаменяемы. Кстати, поэтому масштабирование называется горизонтальным.
В самых продвинутых системах, сервера добавляются и удаляются автоматически при росте или уменьшении нагрузки. В любом случае, в такой схеме, смерть одного из серверов не приводит к остановке проекта. Даже если это случилось ночью, можно спокойно досмотреть сны, проснуться и включить новый сервер в работу.
А что насчет распределения запросов между серверами? С одним сервером все понятно, домен связывается с ip-адресом сервера куда отправляются все пользователи. Когда серверов два, то нужен механизм распределения, который будет решать какой запрос куда отправить. Такой процесс называют балансировкой нагрузки. Балансировать нагрузку можно разными способами.
DNS Балансировка
DNS позволяет добавить любое количество ip-адресов, по которым доступен домен. Когда клиент, например, браузер, запрашивает ip-адрес домена, то DNS возвращает список этих ip-адресов. Как правило клиенты используют только первый из них. На этом факте основана балансировка, DNS сконфигурирован так, что список ip-адресов всегда возвращается в случайном порядке.
# Яндекс использует dns балансировку
host yandex.ru # возвращает список ip-адресов
YANDEX.ru has address 77.88.55.50
YANDEX.ru has address 5.255.255.80
host yandex.ru # порядок уже другой
YANDEX.ru has address 5.255.255.80
YANDEX.ru has address 77.88.55.50
DNS балансировка имеет недостатки, которые существенно ограничивают надежность и эффективность этого решения. Важнее всего то, что DNS не проверяет сервера на доступность, а приложение на работоспособность. Из-за этого, DNS всегда возвращает один и тот же список ip-адресов даже если сервер выключен или недоступен. Некоторые, продвинутые DNS умеют анализировать доступность, но даже в этом случае, реакция не будет мгновенной из-за промежуточного кеширования DNS запросов. Механизм, который помогает DNS быть эффективным в одном случае, мешает в другом.
Балансировщик нагрузки
Более надежное и чаще используемое решение это балансировщик нагрузки. Механизм, который принимает все входящие запросы и распределяет их между всеми доступными серверами. Балансировщиком нагрузки обычно выступает либо отдельный сервер с установленным на нем Nginx или Caddy, либо облачный сервис, такой как AWS, GCP, DO и т.д.
Балансировщики нагрузки умеют не только отслеживать доступность серверов и наличие ошибок, они умеют балансировать по нагрузке и даже географическому расположению. Выбор сервера, который физически ближе к клиенту, позволяет сократить задержку сети.
У балансировщиков нагрузки есть и недостатки. Основной - мы снова вернулись к схеме, когда есть одна точка отказа. Поломка балансировщика выводит из строя весь проект. Поэтому, там где возможно, стараются использовать балансировщик как сервис, доступный в любых облаках. Если это невозможно, то для балансировщика выбирают более надежные машины и даже аппаратный балансировщик.
Ниже пример того, как делается балансировка нагрузки в Caddy и Nginx:
# Caddy
handle {
# Добавляем столько серверов, сколько нужно
reverse_proxy app1:3000 app2:3000 app3:3000
}
# Nginx
http {
server {
location / {
# Запрос перенаправляется на upstream backend
proxy_pass http://backend;
}
}
upstream backend {
# Добавляем столько серверов, сколько нужно
server app1;
server app2;
server app3;
}
}
Реализация
Начнем с деплоя. Текущая схема с Ansible легко масштабируется с одного сервера на несколько. Для этого нужно создать новый сервер и добавить его ip-адрес в inventory-файл:
all:
children:
webservers:
hosts:
# В вашем случае будут другие адреса
web1:
ansible_host: 65.108.149.193
web2:
ansible_host: 55.234.111.100
Затем выполните деплой:
ansible-playbook ansible/release.yml -i inventory.yml -vv --extra-vars "version=v5"
Теперь зайдите в интерфейс создания балансировщика нагрузки на сайте DO:
- Выберите датацентр, в котором находятся ваши сервера
- Оставьте сеть по умолчанию, она будет такой же, в которой создавались наши сервера
- Балансировщик сам может состоять из нескольких машин для надежности. Нам достаточно одной
- Найдите через поиск созданные дроплеты и подключите их к балансировщику. Это можно сделать и после создания
- Опишите правила, по которым, происходит проброс портов. В нашем случае снаружи и внутри будет https. Когда вы выберите эту опцию, вам предложат выбрать новый сертификат. Выберите Passthrough.
- Затем вам предложат выбрать дополнительные опции, например, Health checks. Это проверки, которые будет выполнять DO, для проверки того, жив ли проект. Поправьте порт с 80 на 443. Добавьте автоматический редирект http на https.
Когда все настройки поправлены, нажмите "создать балансировщик". Возьмите его ip-адрес и замените им ip-адрес сервера в файле /etc/hosts. Откройте сайт и убедитесь что он работает devops-example.test.
Как проверить что балансировка нагрузки работает? Попробуйте отключить один из серверов прямо из панели DO ;)
Состояние на сервере
Горизонтальное масштабирование не дается бесплатно. Ключевое ограничение горизонтального масштабирования - отсутствие состояния на сервере. Под состоянием понимаются любые данные: база данных, файлы, сессии и тому подобное. Если хотя бы что-то из этого хранится на одном из серверов приложений, то значит этого нет на других серверах, а значит пользователь то будет видеть эти данные, то нет, в зависимости от того, куда направил его балансировщик.
- База данных должна находиться на своем выделенном сервере
- Сессии желательно хранить в куках
- Файлы грузить на сервисы типа Amazon S3
Логирование
Другая сложность - логирование. Когда сервер один, то всегда можно зайти на него и посмотреть логи приложения или системы. Когда их несколько, непонятно куда заходить. А если серверов 10? Для анализа логов в такой схеме нужен механизм их сбора где-то в централизованном хранилище. Существует два типа решений:
- Облачное. Легко подключается, настраивается и просто работает. Само решение может быть частью серверной инфраструктуры как в Amazon. Там за сбор логов отвечает Amazon CloudWatch. В других облаках такого решения может и не быть. В таких случаях используют внешние сервисы, например DataDog
- Самостоятельное. Для этого обычно используют связку ElasticSearch (хранилище и поиск), Logstash (сборщик логов) и Kibana (инструмент визуализации). Иногда ее называют ELK стек.
Какое бы решение не использовалось, на выходе получается единая панель управления, через которую можно найти всю необходимую информацию, которая когда-либо была в логах.
Самостоятельная работа
-
Выполните все шаги из урока.
-
Настройте приложения на разных серверах таким образом, чтобы каждое из них показывало разное сообщение (переменная окружения
SERVER MESSAGE
), например web1 и web2 -
Проверьте, что по адресу devops-example.test открывается приложение и выводит разные сообщения
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.