какие технологии применяются для построения распределенной архитектуры web сервиса
Архитектура распределенных информационных систем и Web-приложений
Распределенная система— это набор независимых вычислительных машин, представляющийся их пользователям единой объединенной системой. Не смотря на то, что все компьютеры автономны, для пользователей они представляются единой системой.
К основным характеристикам распределенных систем:
1. От пользователей скрыты различия между компьютерами и способы связи между ними. То же самое относится и к внешней организации распределенных систем.
2. Пользователи и приложения единообразно работают в распределенных системах, независимо от того, где и когда происходит их взаимодействие.
Распределенные системы должны также относительно легко поддаваться расширению, или масштабированию. Эта характеристика является прямым следствием наличия независимых компьютеров, но в то же время не указывает, каким образом эти компьютеры на самом деле объединяются в единую систему.
Для того чтобы поддержать представление системы в едином виде, организация распределенных систем часто включает в себя дополнительный уровень программного обеспечения, находящийся между верхним уровнем, на котором находятся пользователи и приложения, и нижним уровнем, состоящим из операционных систем (рисунок 1.11).
Соответственно, такая распределенная система обычно называется системой промежуточного уровня (middleware). Отметим, что промежуточный уровень распределен среди множества компьютеров.
К особенностям функционирования распределенных систем относятся:
· наличие большого количества объектов;
· задержки выполнения запросов (так если локальные вызовы требуют порядка пары сотен наносекунд, то запросы к объекту в распределенных системах требует от 0.1 до 10 мс);
· некоторые объекты могут не использоваться на протяжении длительного времени;
· распределенные компоненты выполняются параллельно, что приводит к необходимости согласования выполнения;
· запросы в распределенных системах имеют большую вероятность отказов;
· повышенные требования к безопасности.
В связи наличием повышенных задержек интерфейсы в распределенной системе должны быть спроектированы так, чтобы снизить время выполнения запросов. Это можно достичь путем снижения частоты обращения, а также укрупнением выполняемых функций.
Для борьбы с отказами клиенты обязаны проверять факт выполнения запросов сервером. Безопасность в распределенных приложениях может быть повышена путем контроля сеансов связи (аутентификация, авторизация, шифрование данных).
|
Рисунок 1.12 – Схема доступа к серверу СУБД через Интернет |
В настоящее время существуют три различных технологии, поддерживающие концепцию распределенных объектных систем: EJB, DCOM CORBA.
Основная идея, лежащая в разработке технологии EJB (Enterprise Java Beans) – создать такую инфраструктуру для компонентов, чтобы они могли бы легко вставляться и удаляться из серверов, тем самым повышая или снижая функциональность сервера. EJB-компоненты являются Java-классами и могут работать на любом EJB-совместимом сервере даже без перекомпиляции. Основными целями EJB-технологии является:
1. Облегчить разработчикам создание приложений, избавив их от необходимости реализовать с нуля такие сервисы, как транзакции, нити, загрузки и др. Разработчики могут сконцентрировать свое внимание на описании логики своих приложений, перекладывая задачи по хранению, передаче и безопасности данных на EJB-систему.
2. Описать основные структуры EJB-системы и интерфейсы взаимодействия между ее компонентами.
3. Освободить разработчика от реализации EJB-объектов за счет наличия специального кодогенератора.
Благодаря используемойJava-модели, EJB является относительно простым и быстрым способом создания распределенных систем.
Технология CORBA (Common Object Request Broker Architecture) специфицирует инфраструктуру взаимодействия компонент (объектов) на уровнях представления и приложения модели OSI. Технология позволяет рассматривать все приложения в распределенной системе как объекты. Причем объекты могут одновременно играть роль и клиента и сервера. Использование CORBA позволяет строить более гибкие системы, чем системы клиент-сервер, основанные на двухуровневой и трехуровней архитектурах. К основным достоинствам CORBA можно отнести межязыковую и межплатформенную поддержку, масштабируемость и широкая промышленная поддержка.
Дата добавления: 2016-02-09 ; просмотров: 6041 ; ЗАКАЗАТЬ НАПИСАНИЕ РАБОТЫ
Концепции распределенной архитектуры, с которыми я познакомился при построении крупной системы платежей
Я присоединился к Uber два года назад в качестве мобильного разработчика, имеющего некоторый опыт разработки бекенда. Здесь я занимался разработкой функционала платежей в приложении — и по ходу дела переписал само приложение. После чего я перешёл в менеджмент разработчиков и возглавил саму команду. Благодаря этому я смог гораздо ближе познакомиться с бэкендом, поскольку моя команда несёт ответственность за многие системы нашего бэкенда, позволяющие осуществлять платежи.
До моей работы в Uber у меня не было опыта работы с распределёнными системами. Я получил традиционное образование в Computer Science, после чего с десяток лет занимался full-stack разработкой. Поэтому, пусть я и мог рисовать различные диаграммы и рассуждать о компромиссах (tradeoffs) в системах, к тому моменту я недостаточно хорошо понимал и воспринимал концепции распределённости — такие, например, как согласованность (consistency), доступность (availability) или идемпотентность (idempotency).
В данном посте я собираюсь рассказать про несколько концепций, которые мне потребовалось изучить и применить на практике при построении крупномасштабной высокодоступной распределённой системы платежей, которая сегодня работает в Uber. Это система с нагрузкой до нескольких тысяч запросов в секунду, в которой критическая функциональность платежей должна работать корректно даже в тех случаях, когда перестают работать отдельные части системы.
Полный ли это список? Скорее всего, нет. Однако, если бы лично я сам узнал про эти концепции раньше, это сделало бы мою жизнь гораздо проще.
Итак, давайте приступим к нашему погружению в SLA, согласованность, долговечность данных, сохранность сообщений, идемпотентность и некоторые другие вещи, которые мне потребовалось выучить на своей новой работе.
В больших системах, которые обрабатывают миллионы событий в день, некоторые вещи просто по определению обязаны пойти не по плану. Вот почему прежде, чем погружаться в планирование системы, нужно сделать самый важный шаг — принять решение о том, что для нас означает «здоровая» система. Степень «здоровья» должна быть чем-то таким, что на самом деле можно измерить. Общепринятым способом измерения «здоровья» системы являются SLA (service level agreements). Вот некоторые из самых распространённых видов SLA, с которыми мне доводилось сталкиваться на практике:
Горизонтальное и вертикальное масштабирование
По мере роста бизнеса, который использует нашу свежесозданную систему, нагрузка на неё будет лишь увеличиваться. В определенный момент, существующая установка будет неспособна выдержать дальнейшее увеличение нагрузки, и нам потребуется увеличить допустимую нагрузку. Две общепринятые стратегии масштабирования — это вертикальное или горизонтальное масштабирование.
Горизонтальное масштабирование заключается в добавлении большего количества машин (или узлов) в систему для увеличения пропускной способности (capacity). Горизонтальное масштабирование — это самый популярный способ масштабирования распределённых систем.
Вертикальное масштабирование — это по сути «купить машину побольше/посильнее» — (виртуальная) машина с большим числом ядер, лучшей вычислительной мощностью и большей памятью. В случае с рапределёнными системами, вертикальное масштабирование обычно менее популярно, поскольку оно может быть более дорогостоящим, чем масштабирование горизонтальное. Однако, некоторые известные большие сайты, вроде Stack Overflow, успешно масштабировались вертикально для соответствия нагрузке.
Почему стратегия масштабирования имеет смысл, когда вы создаёте крупную платёжную систему? Мы на раннем этапе решили, что мы будем строить систему, которая будет масштабироваться горизонтально. Несмотря на то, что вертикально масштабирование допустимо использовать в некоторых случаях, наша система платежей к тому моменту уже достигла прогнозируемой нагрузки и мы с пессимизмом отнеслись к предположению о том, что единственный супер-дорогой мейнфрейм сможет выдержать эту нагрузку сегодня, не говоря уже о будущем. Помимо этого, в нашей команде было несколько человек, которые работали в крупных поставщиках платёжных услуг и имели негативный опыт попытки масштабироваться вертикально даже на самых мощных машинах, которые можно было купить за деньги в те годы.
Согласованность (consistency)
Доступность любой из систем важна. Распределённые системы часто строятся из машин, чья доступность по отдельности ниже, чем доступность всей системы. Пусть наша цель построить систему с доступностью в 99.999% (даунтайм составляет примерно 5 минут/год). Мы используем машины/ноды, которые в среднем имеют доступность в 99.9% (они находятся в даунтайме примерно 8 часов/год). Прямым путём достижения нужного нам показателя доступности является добавление ещё нескольких таких машин/узлов в кластер. Даже если некоторые из узлов будут «в дауне», другие будут продолжать оставаться в строю и общая доступность системы будет выше, чем доступность её индивидуальных компонентов.
Согласованность — это ключевая проблема в высокодоступных системах. Система согласована, если все узлы видят и возвращают одни и те же данные в одно и то же время. В отличие от нашей предыдущей модели, когда мы добавляли больше узлов для достижения большей доступности, удостовериться в том, что система остается согласованной, далеко не так тривиально. Чтобы убедиться в том, что каждый узел содержит одну и ту же информацию, они должны отправлять сообщения друг другу, чтобы постоянно быть сихронизированными. Однако, сообщения, отправленные ими друг другу, могут быть не доставлены — они могут потеряться и некоторые из узлов могут быть недоступными.
Согласованность — это концепция, на осознание которой у меня ушло больше всего времени, прежде чем я понял её и оценил по достоинству. Существует несколько видов согласованности, самым широко используемым в распределённых системах является сильная согласованность (strong consistency), слабая согласованность (weak consistency) и согласованность в конечном счёте (eventual consistency). Вы можете прочитать полезный практический разбор преимуществ и недостатков каждой из моделей в данной статье. Обычно, чем слабее требуемый уровень согласованности, тем быстрее может работать система — но тем вероятнее, что она вернет не самый последний набор данных.
Почему согласованность стоит учитывать при создании крупной платёжной системы? Данные в системе должны быть согласованы. Но насколько согласованы? Для некоторых частей системы подойдут только сильно согласованные данные. Например, нам необходимо сохранить в сильно согласованном виде информацию о том, что платеж был инициирован. Для других частей системы, которые не являются настолько важными, согласованность в конечном счёте можно считать разумным компромиссом.
Хорошо иллюстрирует это вывод списка недавних транзакций: они могут быть реализованы при помощи согласованности в конечном счёте (eventual consistency) — то есть, последняя транзакция может появиться в некоторых частях системы лишь некоторое время спустя, но благодаря этому запрос списка вернет результат с меньшей задержкой или потребует меньше ресурсов для выполнения.
Долговечность данных (data durability)
Долговечность означает то, что как только данные будут успешно добавлены в хранилище данных, они будут доступны нам в будущем. Это будет справедливо даже в том случае, если узлы системы уйдут в оффлайн, в них произойдёт сбой или данные узлов будут повреждены.
Различные распределённые базы данных имеют разные уровни долговечности данных. Некоторые из них поддерживают data durability на уровне машины/узла, другие делают это на уровне кластера, а некоторые вообще не предоставляют этой функциональности «из коробки». Некоторая форма репликации обычно используется для увеличения долговечности — если данные хранятся на нескольких узлах и один из узлов перестаёт работать, данные по-прежнему будут доступны. Вот хорошая статья, поясняющая, почему достижение долговечности в распределённых системах может стать серьёзным вызовом.
Почему долговечность данных имеет значение при построении платёжной системы? Если данные являются критическими (например, это платежи), то мы не можем позволить себе терять их во многих из частей нашей системы. Распределённые хранилища данных, которые мы построили, должны были поддерживать долговечность данных на уровне кластера — так что даже если инстансы будут «падать», завершенные транзакции будут сохраняться. В наши дни, большинство распределённых сервисов хранения данных — вроде Cassandra, MongoDB, HDFS или Dynamodb — все поддерживают долговечность на различных уровнях и все могут быть сконфигурированы для предоставления долговечности уровня кластера.
Сохранность сообщений (message persistence) и долговечность (durability)
Узлы в распределённых системах выполняют вычисления, хранят данные и отправляют сообщения друг другу. Ключевой характеристикой отправки сообщений является то, насколько надёжно эти сообщения прибудут. Для критически важных систем зачастую имеется требование того, чтобы ни одно из сообщений не было потеряно.
В случае распределенных систем, обмен сообщениями (messaging) обычно выполняется при помощи некоторого распределенного сервиса сообщений — RabbitMQ, Kafka или других. Эти брокеры сообщений могут поддерживать (или настроены так, что станут поддерживать) различные уровни надежности доставки сообщений.
Сохранность сообщения означает, что когда на узле, обрабатывающем сообщение, происходит отказ, то сообщение по прежнему будет доступно для обработки после того, как проблема разрешится. Долговечность сообщений обычно используется на уровне очереди сообщений. При помощи долговечной очереди сообщений, если очередь (или узел) уходят в оффлайн когда сообщение отослано, оно попрежнему получит сообщение когда оно вернётся в онлайн. Хорошая подробная статья по данному вопросу доступна по ссылке.
Почему сохранность и долговечность сообщений имеют значение при построении крупных платёжных систем? У нас были сообщения, которые мы не могли позволить себе потерять — например, сообщение о том, что человек инициировал платёж по оплате поездки. Это означало, что система обмена сообщениями, которую нам предстояло использовать, должна была работать без потерь: каждое сообщение должно было быть единожды доставлено. Однако, создание системы которая доставляет каждое сообщение ровно один раз нежели хотя бы один раз — это задачи, значительно различающиеся по своей трудности. Мы решили реализовать систему обмена сообщениями, которая доставляет хотя бы единожды, и выбрали шину сообщений (messaging bus), поверх которой мы решили её построить (мы остановили свой выбор на Kafka, создав кластер без потерь, который требовался в нашем случае).
Идемпотентность
В случае с распределёнными системами, может пойти не так всё, что угодно — соединения могут отваливаться посередине или запросы могут выпадать по тайм-ауту. Клиенты будут часто повторять эти запросы. Идемпотентная система гарантирует, что чтобы ни произошло, и сколько бы раз конкретный запрос ни выполнялся, действительное выполнение этого запроса происходишь всего один раз. Хороший пример — это осуществление платежа. Если клиент создает запрос на оплату, запрос успешен, но если клиент попадает в тайм-аут, то клиент может повторить тот же самый запрос. В случае с идемпотентной системой, с человека, производящего оплату, не будут дважды списаны деньги; а вот для не-идемпонетной системы это вполне возможное являение.
Проектирование идемпотентных распределённых систем требует некоего вида распределённой стратегии блокировки. Здесь в игру вступают концепции, которые мы обсуждали ранее. Скажем, мы намереваемся реализовать идемпотентность при помощи оптимистической блокировки во избежание параллельных обновлений. Для того, чтобы мы могли прибегнуть к оптимистической блокировке, система должна быть строго согласованной — благодаря чему во время выполнения операции мы можем проверить, начата ли другая операция, используя некую форму версионирования.
Существует множество способов достижения идемпотентности, и каждый конкретный выбор будет зависеть от ограничений системы и типа производимой операции. Проектирование идемпотентных подходов это достойный вызов для разработчика — достаточно взглянуть на посты Бена Надела, в которых он рассказывает о различных стратегиях, которые он использовал, которые включают в себя и распределённые блокировки, и ограничения (constraints) базы данных. Когда вы проектируете распределённую систему, идемпотентность может легко оказаться одной из частей, которую вы упустили из своего внимания. В нашей практике мы сталкивались со случаями, в которых моя команда «погорела» на том, что не убедилась в наличии корректной идемпотентности для некоторых ключевых операций.
Почему идемпотентность имеет значение при построении крупной платёжной системы? Самое главное: для избежания двойных списаний и двойных возвратов средств. Учитывая, что наша система обмена сообщениями имеет доставку типа «хотя бы раз, без потерь», мы должны предполагать, что все сообщения могут быть доставлены несколько раз и системы должны гарантировать идемпотентность. Мы приняли решения обрабатывать это при помощи версионирования и оптимистической блокировки, где наши системы реализуют идемпотентное поведение используя строго согласованное хранилище в качестве своего источника данных.
Шардинг и кворум
Распределённые системы часто должны хранить гораздо больше данных, чем может позволить себе один отдельный узел. Так как же нам сохранить набор данных на нужном количестве машин? Самой популярной техникой для этого является шардинг. Данные горизонтально партиционируются при помощи некоего хеша, присвоенного партиции. Пусть многие распределённые базы данных сегодня реализуют шардинг у себя «под капотом», он сам по себе является интересной темой, которую стоит изучить — особенно решардинг. У Foursquare в 2010 году был 17-часовой даунтайм из-за попадания на краевой случай шардинга, после чего компания поделилась интересным пост-мортемом, проливающим свет на корень проблемы.
Во многих распределённых системах есть данные или вычисления, которые реплицируются между несколькими узлами. Чтобы убедиться в том, что операции выполняются согласованно, определяется подход с голосованием, при котором для признания операции успешной нужно, чтобы определённое количество узлов получило один и тот же результат. Этот процесс называется кворумом.
Почему кворум и шардинг имеют смысл при построении крупной платёжной системы в Uber? Обе эти концепции являются простыми и используются практически повсеместно. Я познакомился с ними тогда, когда мы настраивали репликацию в Cassandra. Cassandra (и другие распределённые системы) использует кворум и местный кворум (local quorum) для того, чтобы обеспечить согласованность между кластерами.
Модель акторов
Привычный словарь, который мы используем для описания практик программирования — вещи вроде переменных, интерфейсов, вызова методов — предполагают системы из одной машины. Когда мы говорим о распределённых системах, то мы должны использовать другие подходы. Распространенным способом описания таких систем является модель акторов, в рамках который код видится нам в терминах коммуникации. Эта модель является популярной в силу того, что она совпадает с ментальной моделью того, как мы представляем себе, например, взаимодействие людей в организации. Другой, не менее популярный способ описания распределённых систем — это CSP, взаимодействующие последовательные процессы.
Модель акторов базируется на акторах, которые отправляют друг другу сообщения и реагируют на них. Каждый актор может делать ограниченный набор вещей — создавать других акторов, отправлять сообщения другим или решать, что сделать со следующим сообщением. При помощи нескольких простых правил, мы можем достаточно хорошо описать сложные распределённые системы, которые могут восстанавливать себя после того, как актор «падает». Если вы не знакомы с данным подходом, то я рекомендую вам статью Модель акторов за 10 минут за авторством Брайна Сторти. Для многих языков существуют библиотеки или фреймворки, реализующие модель акторов. Например, в Uber мы используем Akka для некоторых из наших систем.
Почему имеет смысл применить модель акторов в крупной платёжной системе? В разработке нашей системы принимало участие много инженеров, большинство из которых уже имело опыт работы над распределёнными системами. Мы решили следовать стандартной распределённой модели вместо того, чтобы заниматься «велосипедами» и изобретать свои собственные распределённые принципы.
Реактивная архитектура
При построении больших распределённых систем, целью обычно является сделать их отказоустойчивыми, эластичными и масштабируемыми. Будь то система платежей или какая-либо другая высоконагруженная система, паттерны достижения желаемого могут быть одними и теми же. Те, кто занимается подобными системами, регулярно обнаруживают и распространяют лучшие практики их построения — и реактивная архитектура является подобным популярным и широко используемым паттерном.
Для ознакомления с реактивной архитектурой, я предлагаю прочитать Реактивный манифест (на русском) и посмотреть 12-минутное видео по ссылке.
Почему реактивную архитектуру имеет смысл применять, если вы создаёте крупную платёжную систему? Akka, — библиотека, которую мы использовали для создания большей части нашей новой платежной системы, — находится под сильным влиянием реактивной архитектуры. Многие из наших инженеров, занимавшихся построением этой системы, уже были знакомы с лучшими практиками реактивного программирования. Следуя реактивным принципам — создавая отзывчивую, отказоустойчивую, эластичную систему, основанную на сообщениях (message-driven), мы пришли к этому выводу естественным путём. Возможность иметь модель, на которую можно положиться и при помощи которой можно оценить прогресс разработки и его направление, оказалась крайне полезной, и я буду полагаться на неё в дальнейшем при создании новых систем.
Заключение
Мне повезло принять участие в перестраивании широкомасштабной, распределённой и критически важной системы: той, что позволяет работать с платежами в Uber. Работая в этом окружении, я познакомился со многими распределёнными концепциями, которые мне не доводилось использовать ранее. Я собрали их здесь в надежде на то, что остальные найдут мой рассказ полезным для старта изучения распределённых систем или узнают для себя что-нибудь новое.
Данный пост был посвящен исключительно планированию и архитектуре подобных систем. Существует множество различных тонкостей, о которых стоит рассказать — про построение, деплой и миграцию высоконагруженных систем, — а ещё про их надёжную эксплуатацию; все эти темы я собираюсь поднять в последующих постах.
Сервис-ориентированная архитектура (SOA)
Сервис-ориентированная архитектура (service-oriented architecture, SOA) придумана в конце 1980-х. Она берёт своё начало в идеях, изложенных в CORBA, DCOM, DCE и других документах. О SOA написано много, есть несколько её реализаций. Но, по сути, SOA можно свести к нескольким идеям, причём архитектура не диктует способы их реализации:
SOA — это набор архитектурных принципов, не зависящих от технологий и продуктов, совсем как полиморфизм или инкапсуляция.
В этой статье я рассмотрю следующие паттерны, относящиеся к SOA:
Общая архитектура брокера объектных запросов (CORBA)
В 1980-х началось активное использование корпоративных сетей и клиент-серверной архитектуры. Возникла потребность в стандартном способе взаимодействия приложений, которые созданы с использованием разных технологий, исполняются на разных компьютерах и под разными ОС. Для этого была разработана CORBA. Это один из стандартов распределённых вычислений, зародившийся в 1980-х и расцветший к 1991 году.
Стандарт CORBA был реализован несколькими вендорами. Он обеспечивает:
Сегодня CORBA всё ещё используется для разнородных вычислений. Например, он до сих пор является частью Java EE, хотя начиная с Java 9 будет поставляться в виде отдельного модуля.
Хочу отметить, что не считаю CORBA паттерном SOA (хотя отношу и CORBA, и SOA-паттерны к сфере распределённых вычислений). Я рассказываю о нём здесь, поскольку считаю недостатки CORBA одной из причин возникновения SOA.
Принцип работы
Сначала нам нужно получить брокер объектных запросов (Object Request Broker, ORB), который соответствует спецификации CORBA. Он предоставляется вендором и использует языковые преобразователи (language mappers) для генерирования «заглушек» (stub) и «скелетов» (skeleton) на языках клиентского кода. С помощью этого ORB и определений интерфейсов, использующих IDL (аналог WSDL), можно на основе реальных классов генерировать в клиенте удалённо вызываемые классы-заглушки (stub classes). А на сервере можно генерировать классы-скелеты (skeleton classes), обрабатывающие входящие запросы и вызывающие реальные целевые объекты.
Вызывающая программа (caller) вызывает локальную процедуру, реализованную заглушкой.
Достоинства
Недостатки
Веб-сервисы
Хотя сегодня можно найти применение для CORBA, но мы знаем, что нужно было уменьшить количество удалённых обращений, чтобы повысить производительность системы. Также требовался надёжный канал связи и более простая спецификация обмена сообщениями.
И для решения этих задач в конце 1990-х начали появляться веб-сервисы.
[Веб-]сервисы можно публиковать, находить и использовать стандартным образом вне зависимости от технологий.
— Microsoft 2004, Understanding Service-Oriented Architecture
Благодаря микросервисам мы перешли в парадигме SOA от удалённого вызова методов объекта (CORBA) к передаче сообщений между сервисами.
Но нужно понимать, что в рамках SOA веб-сервисы — не просто API общего назначения, всего лишь предоставляющие CRUD-доступ к базе данных через HTTP. В каких-то случаях эта реализация может быть полезной, но ради целостности ваших данных необходимо, чтобы пользователи понимали лежащую в основе реализации модель и соблюдали бизнес-правила. SOA подразумевает, что веб-сервисы являются ограниченными контекстами бизнес-субдоменов (business sub-domain) и отделяет реализацию от решаемых веб-сервисами задач.
С точки зрения технологий SOA не просто сервисная архитектура, а набор политик, методик и фреймворков, благодаря которым мы предоставляем и получаем нужные сервисы.
— Microsoft 2004, Understanding Service-Oriented Architecture
Достоинства
Недостатки
Очередь сообщений
У нас есть несколько приложений, которые асинхронно общаются друг с другом с помощью платформо-независимых сообщений. Очередь сообщений улучшает масштабируемость и усиливает изолированность приложений. Им не нужно знать, где находятся другие приложения, сколько их и даже что они собой представляют. Однако все эти приложения должны использовать один язык обмена сообщениями, т. е. заранее определённый текстовый формат представления данных.
Очередь сообщений использует в качестве компонента инфраструктуры программный брокер сообщений (RabbitMQ, Beanstalkd, Kafka и т. д.). Для реализации связи между приложениями можно по-разному настроить очередь:
Запрос/Ответ
Все эти паттерны можно отнести к либо к pull- (polling), либо к push-подходу:
Достоинства
Недостатки
Сервисная шина предприятия (ESB)
Сервисная шина предприятия использовала веб-сервисы уже в 1990-х, когда они только развивались (быть может, некоторые реализации сначала использовали CORBA?).
ESB возникла во времена, когда в компаниях были отдельные приложения. Например, одно для работы с финансами, другое для учёта персонала, третье для управления складом, и т. д., и их нужно было как-то связывать друг с другом, как-то интегрировать. Но все эти приложения создавались без учёта интеграции, не было стандартного языка для взаимодействия приложений (как и сегодня). Поэтому разработчики приложений предусматривали конечные точки для отправки и приёма данных в определённом формате. Компании-клиенты потом интегрировали приложения, налаживая между ними каналы связи и преобразуя сообщения с одного языка приложения в другой.
Очередь сообщений может упростить взаимодействие приложений, но она не способна решить проблему разных форматов языков. Впрочем, была сделана попытка превратить очередь сообщений из простого канала связи в посредника, доставляющего сообщения и преобразующего их в нужные форматы/языки. ESB стал следующей ступенью в естественной эволюции простой очереди сообщений.
В этой архитектуре используется модульное приложение (composite application), обычно ориентированное на пользователей, которое общается с веб-сервисами для выполнения каких-то операций. В свою очередь, эти веб-сервисы тоже могут общаться с другими веб-сервисами, впоследствии возвращая приложению какие-то данные. Но ни приложение, ни бэкенд-сервисы ничего друг о друге не знают, включая расположение и протоколы связи. Они знают лишь, с каким сервисом хотят связаться и где находится сервисная шина.
Клиент (сервис или модульное приложение) отправляет запрос на сервисную шину, которая преобразует сообщение в формат, поддерживаемый в точке назначения, и перенаправляет туда запрос. Всё взаимодействие идёт через сервисную шину, так что если она падает, то с ней падают и все остальные системы. То есть ESB — ключевой посредник, очень сложный компонент системы.
Это очень упрощённое описание архитектуры ESB. Более того, хотя ESB является главным компонентом архитектуры, в системе могут использоваться и другие компоненты вроде доменных брокеров (Domain Broker), сервисов данных (Data Service), сервисов процессной оркестровки (Process Orchestration Service) и обработчиков правил (Rules Engine). Тот же паттерн может использовать интегрированная архитектура (federated design): система разделена на бизнес-домены со своими ESB, и все ESB соединены друг с другом. У такой схемы выше производительность и нет единой точки отказа: если какая-то ESB упадёт, то пострадает лишь её бизнес-домен.
Главные обязанности ESB:
Создавая структуры связи между разными процессами, мы видели много продуктов и подходов, в которых применяются очень развитые механизмы связи. Хороший пример — сервисные шины предприятий, часто включающие в себя сложные средства маршрутизации сообщений, хореографии, преобразования и применения бизнес-правил.
— Martin Fowler 2014, Microservices
У этого архитектурного паттерна есть положительные стороны. Однако я считаю его особенно полезным в случаях, когда мы не «владеем» веб-сервисами и нам нужен посредник для трансляции сообщений между сервисами, для оркестрирования бизнес-процессами, использующими несколько веб-сервисов, и прочих задач.
Также рекомендую не забывать, что реализации ESB уже достаточно развиты и в большинстве случаев позволяют использовать для своего конфигурирования пользовательский интерфейс с поддержкой drag & drop.
Достоинства
Недостатки
Микросервисы
В основе микросервисной архитектуры лежат концепции SOA. Назначение у неё то же, что и у ESB: создать единое общее корпоративное приложение из нескольких специализированных приложений бизнес-доменов.
Главное различие микросервисов и шины в том, что ESB была создана в контексте интеграции отдельных приложений, чтобы получилось единое корпоративное распределённое приложение. А микросервисная архитектура создавалась в контексте быстро и постоянно меняющихся бизнесов, которые (в основном) с нуля создают собственные облачные приложения.
То есть в случае с ESB у нас уже были приложения, которые нам не «принадлежат», и поэтому мы не могли их изменить. А в случае с микросервисами мы полностью контролируем приложения (при этом в системе могут использоваться и сторонние веб-сервисы).
Характер построения/проектирования микросервисов не требует глубокой интеграции. Микросервисы должны соответствовать бизнес-концепции, ограниченному контексту. Они должны сохранять своё состояние, быть независимыми от других микросервисов, и потому они меньше нуждаются в интеграции. То есть низкая взаимозависимость и высокая связность привели к замечательному побочному эффекту — уменьшению потребности в интеграции.
[Микросервисы — это] маленькие автономные сервисы, работающие вместе и спроектированные вокруг бизнес-домена.
— Sam Newman 2015, Principles Of Microservices
Главным недостатком архитектуры ESB было очень сложное централизованное приложение, от которого зависели все остальные приложения. А в микросервисной архитектуре это приложение почти целиком убрано.
Ещё остались элементы, пронизывающие всю экосистему микросервисов. Но у них гораздо меньше задач по сравнению с ESB. К примеру, для асинхронной связи между микросервисами до сих пор применяется очередь сообщений, но это лишь канал для передачи сообщений, не более того. Или можно вспомнить шлюз экосистемы микросервисов, через который проходит весь внешний обмен данными.
Сэм Ньюман, автор Building Microservices, выделяет восемь принципов микросервисной архитектуры. Это:
Сообщество предпочитает другой подход: умные конечные точки и глупые каналы. Микросервисы, из которых собираются приложения, должны как можно меньше зависеть друг от друга и при этом быть очень тесно связанными — они содержат собственную доменную логику и работают скорее как фильтры с точки зрения классического Unix: получают запросы, применяют логику и генерируют ответы. Они оркестрируются с помощью простых REST-подобных протоколов, а не сложных протоколов вроде WS-Choreography или BPEL либо какого-то централизованного инструмента.
— Martin Fowler 2014, Microservices
Достоинства
Недостатки
Антипаттерн: архитектура равиоли (Ravioli Architecture)
Архитектурой равиоли обычно называют антипаттерн микросервисной архитектуры. Равиоли получаются, если микросервисов слишком много, они слишком мелкие и не отражают доменных концепций.
Заключение
В последние десятилетия SOA сильно эволюционировала. Благодаря неэффективности прежних решений и развитию технологий сегодня мы пришли к микросервисной архитектуре.
Эволюция шла по классическому пути: сложные проблемы разбивались на более мелкие, простые в решении.
Проблему сложности кода можно решать так же, как мы разбиваем монолитное приложение на отдельные доменные компоненты (разграниченные контексты). Но с разрастанием команд и кодовой базы увеличивается потребность в независимом развитии, масштабировании и развёртывании. SOA помогает добиться такой независимости, упрочняя границы контекстов.
Повторюсь, что всё дело в слабой взаимозависимости и высокой связности, причём размер компонентов должен быть больше прежнего. Необходимо прагматично оценить свои потребности: используйте SOA, лишь когда это необходимо, поскольку она сильно увеличивает сложность. И если на самом деле вы можете обойтись без SOA, то лучше выберите микросервисы подходящего размера и количества, не больше и не меньше.