9  /  97

Как представить своё приложение в виде кластера

Просмотров: 18344
Дата последнего изменения: 23.09.2021
Сложность урока:
3 уровень - средняя сложность. Необходимо внимание и немного подумать.
1
2
3
4
5

Введение

Когда переходы на новый тарифный план или апгрейд "железа" сервера перестают решать проблемы производительности (либо становятся чрезмерно дорогими), то направление развития приложения одно: переход на кластерные технологии.

Решать задачу представления приложения в виде кластера можно с помощью следующих технологий, которые позволяют масштабировать базу данных, кеш, web и представить каждую из составляющих в виде группы взаимозаменяемых серверов:

  • Вертикальный шардинг (вынесение модулей на отдельные серверы MySQL).
  • Репликация MySQL и балансирование нагрузки между серверами.
  • Распределенный кеш данных (memcached).
  • Непрерывность сессий между веб-серверами (хранение сессий в базе данных).
  • Кластеризация веб-сервера:
    • Синхронизация файлов.
    • Балансирование нагрузки между серверами.

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

  1. разделение веб-сервера и базы на два разных сервера (это не кластер как таковой),
  2. построение собственно кластера.

  Разделение веб-сервера и базы на два разных сервера

На этом этапе приложение делится на составные части (web, БД, кеш), и эти части работают на разных серверах.

Этот этап не сложен в проектировании, и его выполнения с точки зрения производительности большинству проектов бывает вполне достаточно. Однако такое деление не решает задачу надёжности и отказоустойчивости. Каждый узел не зарезервирован, и в случае выхода из строя любого из них перестаёт работать весь проект в целом.

  Построение кластера

Для реализации этого этапа необходимо решить следующие задачи:

  1. Репликация и балансировка нагрузки MySQL.
  2. Масштабирование веб-сервера.
  3. Задачи синхронизации файлов и авторизации пользователей.
  4. Масштабирование кэша.

Репликация и балансировка нагрузки MySQL

Самое простое решение - репликация, возможность которой предоставляет любая современная база данных. Чаще всего используется MySQL, так как она достаточно проста, понятна, хорошо документирована. Средствами самой базы можно организовать репликацию, добавить некоторое количество slave-серверов, которые будут получать данные с master'а, и логично вынести select и запросы на чтение на эти slave.

Схема типового веб-приложения с реплицированной базой:

Все запросы на запись отправляются на master, все запросы на чтение отправляются на slave. Это самый простой способ масштабирования.

Если этот механизм будет реализован средствами Базы данных, то на долю самого приложения остаётся диспетчеризация всех этих запросов и распределение их между серверами. Делать это лучше именно на уровне ядра приложения, потому что:

  • Обеспечивается гибкая балансировка нагрузки SQL.

    Очень часто необходимо произвести чтение с данных, которые были только что изменены. Например, первым запросом добавили пользователя, а вторым - запросили список пользователей. Если запрос на запись отправляется на мастер, а запрос на чтение списка пользователей отправляется на slave, то возможна ситуация, когда slave отстают от master'а (типовая ситуация) и в ответ приходят устаревшие данные. Для списка пользователей такое положение, возможно, терпимо, но если речь идёт о заказах интернет-магазина или банковских транзакциях, то неправильные данные - это критично. Именно приложение должно определять, какие select'ы нужно отправлять тоже на master для получения актуальных данных. Это означает чуть большую нагрузку на master, но зато это гарантирует получение корректных данных.

  • Приложение проще администрировать.
  • Обеспечивается дешевое и быстрое неограниченное масштабирование.

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

  • Облегчается работа приложения во время выполнения бэкапа, что особо актуально для больших объёмов данных. Если на один из серверов задать вес, равный 0 (то есть не отправлять на него запросы вообще), то его можно использовать для снятия резервных копий. Это удобно в том плане, что не создаётся дополнительная нагрузка на "боевые" сервера, что в любом случае будет замедлять работу проекта.
  • Не требуется доработка логики веб-приложения.

Задачи синхронизации файлов и авторизации пользователей

Не внося больших изменений в логику веб-приложения, можно добавить несколько веб-серверов, над ними поставить любой из доступных балансировщиков: от распределения по DNS и заканчивая специализированными решениями типа балансировщика Amazon'а, либо "железные" решения типа Cisco, или простейший отдельный сервер NGNIX, который распределит запросы по нескольким серверам.

Этими инструментами можно решить задачу балансировки, но нельзя решить задачи:

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

Вопрос с сессиями решается достаточно просто. Они выносятся в отдельное централизованное хранилище. Либо в Базе данных, либо в мемкеше.

Вопрос с синхронизацией файлов в случае небольшого проекта достаточно прост. Можно подключить единое хранилище, например, через Network File System и работать с файловой системой со всех серверов. Удобно, но не быстро.

Другой вариант: хранить файлы на каждом сервере и использовать для синхронизации сторонние утилиты. Просто, но нет возможности синхронизировать данные моментально, всё равно будет временной промежуток недоступности файлов на каких-то серверах. С ростом объёма данных этот механизм будет работать всё менее надёжно и с замедлением.

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

Для реализации такого хранилища можно сформулировать несколько правил:

  • Должно существовать API хранилища для прозрачной работы с файлами.
  • Нужно разработать API в создаваемом приложении для разработчиков. Файл не хранится локально, значит, не подойдут стандартные функции для работы с ними, нельзя оперировать какими-то свойствами файлов (размер, изображение). Эти данные должны получаться при загрузке файла через какой-то (административный или пользовательский) интерфейс системы и сохраниться в служебной таблице.
  • Необходимо избегать "диких", то есть загруженных в обход системы файлов (например, FTP). Такие файлы можно отлавливать через обработку 404-ой ошибки.
  • Необходимо простое подключение хранилищ, желательно одной кнопкой в приложении.
  • Нужно создать правила при работе с несколькими хранилищами.
  • Нужно обеспечить прозрачность работы для всех модулей системы.

Для реализации можно использовать какой-то отдельный FTP сервер и выносить файлы туда. Но при этом не решается задача резервирования и надёжности. Для решения этих задач придётся применять другие методы, скажем, средства операционной системы, систем резервного копирования и других инструментов.

Заведомо надёжное хранилище - это облачное хранилище, которое в последнее время предоставляет всё большее число провайдеров. При этом оптимальным будет решение, когда на одном проекте одновременно можно хранить разные файлы в разных облачных хранилищах. Например, все файлы "весом" больше 100 Мб перемещать в Google Storage, а все видео - в Amazon S3.

Такое деление позволяет:

  • прямо в ходе работы оценить удобство, скорость и стоимость работы каждого хранилища и подобрать оптимальные варианты размещения контента.
  • избежать не очень комфортной ситуации vendor lock-in.
  • прямо в ходе работы переезжать с одного хранилища на другое, не прерывая работу проекта.

Rest API для всех популярных языков есть у всех хранилищ, проектирование системы на облаках не вызывает затруднений у квалифицированного разработчика.

Распределенный кеш данных

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

Основная задача, которая решается распределением кеша по группе серверов - это отказоустойчивость. Кеш можно распределять, как и в случае с БД, по весам, которые задаются в административной части приложения.

  • Высокая эффективность - за счет централизованного использования кеша веб-приложением.
  • Надежность - за счет устойчивости подсистемы кеширования к выходу из строя отдельных компонентов.
  • Неограниченная масштабируемость - за счет добавления новых memcached-серверов.

6
Курсы разработаны в компании «1С-Битрикс»

Если вы нашли неточность в тексте, непонятное объяснение, пожалуйста, сообщите нам об этом в комментариях.
Развернуть комментарии