Обложка: Топ-5 архитектурных паттернов для распределённых систем

Топ-5 архитектурных паттернов для распределённых систем

Распределённые приложения — главный элемент современной индустрии разработки ПО. Они имеют решающее значение для облачных сервисов хранения данных и позволяют веб-приложениям с огромной аудиторией оставаться реактивными. Для того чтобы эффективно проектировать эти системы, программисты используют фундаментальные блоки — паттерны распределённых систем.

Мы рассмотрим пять архитектур распределённых систем, их плюсы, минусы и области применения.

Что такое паттерн распределённой системы?

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

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

Паттерны распределённых систем описывают взаимодействие различных узлов системы и то, как они обрабатывают задачи и виды процессов для различных задач.

Эти паттерны широко используются в архитектуре крупномасштабных облачных вычислений и систем масштабируемых микросервисов.

Типы паттернов распределённых систем

Большинство паттернов распределённых систем попадает в одну из трёх категорий, в зависимости от функциональности с которой они работают:

  • Взаимодействие объектов: описывают протоколы отправки сообщений и разрешения для общения между компонентами системы.
  • Безопасность: обеспечивают конфиденциальность, целостность и доступность для защиты системы от несанкционированного доступа.
  • Событийные: описывают создание, определение, использование и реакцию на события системы.

1. Разделение ответственности на команды и запросы (CQRS)

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

Команды и запросы обрабатываются центром управления, который получает запросы от пользователей. Затем центр получает данные и выполняет необходимые изменения, сохраняет их и уведомляет сервис выполняющий чтение. Этот сервис обновляет модель чтения и показывает изменения пользователю.

Плюсы:

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

Минусы:

  • Требует постоянного взаимодействия между командами и запросами.
  • Может увеличить задержку при отправке большого количества запросов.
  • Нет средств связи между сервисными процессами.

Область применения

CQRS отлично подходит для приложений, интенсивно использующих данные, например систем управления базами данных SQL или NoSQL. Также паттерн используется для архитектур микросервисов с большим объемом данных. Он прекрасно подходит для приложений, сохраняющих состояние благодаря разделению на писателя и читателя.

2. Двухфазная фиксация (2PC)

2PC похож на CQRS использованием транзакций и центра управления, но здесь разделение производится на основании того, на какой стадии находится транзакция. Есть две фазы: фаза подготовки (в которой центр управления сообщает службам подготовить данные) и фаза фиксации (которая сигнализирует службе отправить подготовленные данные).

Все сервисы в 2PC по умолчанию заблокированы и не могут отправлять данные. После завершения подготовки координатор по одному разблокирует сервисы и запрашивает их данные. Если сервис не готов подтвердить данные, координатор переходит к другому сервису. Когда все подготовленные данные отправлены сервисы остаются разблокированными и ожидают задачи от координатора.

2PC гарантирует, что одновременно может работать только одна служба, что делает процесс более устойчивым и последовательным, чем CQRS.

Плюсы:

  • Консистентность и устойчивость к ошибкам из-за отсутствия параллельных запросов.
  • Масштабируемость — может обрабатывать большие пулы данных так же эффективно, как и данные с одного компьютера.
  • Поддерживает одновременную изоляцию и разделение данных.

Минусы:

  • Не отказоустойчив, подвержен возникновению узких мест и блокировок из-за своей синхронной природы.
  • Требует больше ресурсов, чем другие паттерны.

Область применения

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

3. Saga

Saga — это асинхронный паттерн не использующий центр управления. Сервисы здесь сами взаимодействуют между собой. Эта особенность позволяет избавиться от недостатков упомянутых выше паттернов.

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

Эта структура похожа на 2PC тем, что службы циклически запускаются, если кто-то не может выполнить задачу. Тем не менее, Saga не использует центр управления, чтобы лучше управлять потоком и уменьшить количество требуемой обратной связи.

Плюсы:

  • Отдельные сервисы могут обрабатывать более долгие транзакции.
  • Децентрализация отлично подходит для распределённых систем.
  • Меньше узких мест благодаря одноранговой связи между службами.

Минусы:

  • Асинхронная независимость делает трудным отслеживание сервисов выполняющих индивидуальные задачи.
  • Сложный механизм управления затрудняет отладку.
  • Меньшая изоляция сервисов, чем в предыдущих паттернах.

Область применения

Этот паттерн распределённой системы хорошо подходит для задач, которым требуется масштабируемая беcсерверная архитектура, способная обрабатывать много запросов одновременно. AWS использует подобные решения в AWS Step Functions и AWS Lambda, и других продуктах.

4. Реплицированные сервисы с распределением нагрузки (RLBS)

RLBS — это самый простой и часто используемый шаблон проектирования. На базовом уровне он состоит из нескольких идентичных сервисов, которые общаются с центральным распределителем. Каждый сервис способен выполнять задачи и перезапускать их в случае неудачи. Распределитель получает запросы от конечного пользователя и разделяет их между сервисами, используя round-robin или более сложный алгоритм.

Дублирующие службы обеспечивают высокую доступность приложения для запросов пользователей и могут перераспределять работу в случае сбоя одного экземпляра службы.

RLBS часто используется с Azure Kubernetes, которая представляет собой технологию оркестровки контейнеров с открытым исходным кодом, разработанную Microsoft, которая предлагает автоматическое масштабирование служб в зависимости от воркфлоу.

Плюсы:

  • Стабильная производительность с точки зрения конечного пользователя.
  • Быстрое восстановление после сбоев.
  • Высокая масштабируемость через увеличение числа сервисов.
  • Отличная многопоточность.

Минусы:

  • Нестабильная производительность, зависящая от алгоритма балансировки.
  • Управление сервисами требует много ресурсов.

Область применения

RLBS отлично подходит для систем, с которыми пользователи взаимодействуют напрямую. Нагрузка на эти системы в течение дня изменяется, поэтому требуется низкая задержка, например Netflix или Amazon Prime.

5. Шардинг

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

Шардинг сервисов обычно используется для создания сервисов с поддержкой состояния, потому что объём состояния часто слишком большой для одного stateless контейнера. Шардинг позволяет масштабировать отдельные элементы под размер состояния.

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

Плюсы:

  • Возможность масштабировать сегменты для общих запросов.
  • Легкая приоритизация запросов.
  • Простая отладка, благодаря естественной сортировке.

Минусы:

 

  • Поддержка большого числа сегментов может потребовать много ресурсов.
  • Непропорциональное использование сегментов может привести к потерям производительности.

Область применения

Шардинг сервисов хорош в тех случаях, когда ваша система работает с предсказуемой несбалансированной нагрузкой для разных запросов, а некоторые запросы имеют приоритет.

Что дальше?

В статье были рассмотрены лишь несколько паттернов распределённых систем. Вот ещё несколько шаблонов проектирования для изучения:

  • Sidecar паттерн;
  • Упреждающая журнализация (Write-Ahead Log);
  • Split-Brain паттерн;
  • Направленная отправка (Hinted Handoff);
  • Чтение с восстановлением (Read Repair).

Мы спросили экспертов о том, какие шаблоны проектирования стоит знать каждому.

 

Источник Top 5 Distributed System Design Patterns