Избавьтесь от мифа о микросервисах: избегайте перехода от монолита к распределенному монолиту

Микросервисы распределенный

В последнее время в сообществе часто появлялись различные голоса вопросов и размышлений о микросервисах, и они даже отказались от микросервисов и вернулись к монолитам. Эта статья начинается с проблемы «распределенного монолита» и знакомит с тем, как избавиться от неправильного понимания практики использования микросервисов путем внедрения неинтрузивных решений и внедрения Event/EDA: от монолита к микросервису, но в конечном итоге сведенного к распределенному монолиту.

Обзор: от монолитов к микросервисам и функциям

За последние несколько лет микросервисная архитектура стала основной в отрасли, и многие компании начали внедрять микросервисы и переносить исходные монолитные приложения на микросервисную архитектуру. С точки зрения архитектуры, самое большое различие между микросервисами и монолитами заключается в том, что степень детализации приложений в архитектуре микросервисов «меньше»: монолитные приложения, объединяющие всю бизнес-логику, делятся на несколько связанных и автономных приложений в соответствии с моделью предметной области «меньше». Приложения. Функция, с другой стороны, делает еще один шаг в разделении, и гранулярность разделения становится «единой операцией».На основе функции постепенно появляются форма FaaS и бессерверная архитектура.

evolation.jpg

В суматохе микросервисов и безсерверных технологий также раздается много голосов сомнений и возражений: все больше и больше людей обнаруживают, что, когда они с энтузиазмом переносят монолитные приложения на микросервисы и бессерверную архитектуру, преимущества, которые они получают, не так идеальны, как ожидалось. В последнее время прозвучали разные мнения и размышления о микросервисах и даже об отказе от микросервисов и возвращении к монолитам. Например, яВеб-сайт InfoQ КитайПросто выполните поиск по ключевому слову «микросервисы», и на первых трех страницах появится следующий контент:

Независимо от того, поддерживают ли они микросервисы или выступают против них, большинство из них сосредоточены на организационной структуре (закон Конвея, владение приложениями и кодом), разделении микросервисов (размер зерен, как идентифицировать модели предметной области и бизнес-границы), распределенных транзакциях (поддержание согласованности при вызовах между несколькими службами). микросервисы), инструменты (автоматическая сборка, развертывание, тестируемость, мониторинг, отслеживание распределенных ссылок, CI/CD), разделение базы данных (избегайте нескольких микросервисов, особенно за пределами модели предметной области, анализ рациональности и проработка точки зрения с точки зрения совместного использования микросервисов базы данных), д., думаю, у всех есть понимание этих вопросов.

В сегодняшней статье я рассмотрю недоразумения в практике микросервисов (в том числе бессерверных) с другой точки зрения — упорно работаю над переходом от одиночного к микросервису, но в итоге он становитсяРаспределенный монолит.

Распределенный монолит

"Распределенный монолит" - печальный технический термин. И это одна из «ловушек», в которую предприятия обычно чаще всего попадают после внедрения микросервисов. Фактически, многие из микросервисов, которые я видел, заканчиваются «распределенными монолитами» и не могут получить все преимущества микросервисов.

Проблема связана с тем, как реализованы микросервисы — разобрать мономер по бизнес-логике, разделить его на несколько микросервисов, определить API-интерфейсы, а затем сделать удаленные вызовы через REST или RPC и, наконец, объединить эти микросервисы для предоставления различных бизнес-функций. Проще говоря, на основе разделения бизнеса с использованием межпроцессногоудаленный вызовПростая замена оригинала в процессевызов метода. В течение этого периода для первоначально использовавшихся различных распределенных возможностей будет продолжать использоваться предыдущий метод.Проще говоря: метод остается тем же, но степень детализации становится меньше.

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

Одна из причин распределенных монолитов: доступ к распределенным возможностям через разделяемые библиотеки и сетевые клиенты.

Общие библиотеки и сетевые клиенты для распределенных возможностей являются одной из причин проблемы распределенного монолита, как пишет Мохамад Бьян из Verizon в своей статье под названиемAvoid the Distributed Monolith!!В его выступлении есть подробные пояснения, а его фотографии и мнения я привожу здесь:

shared-library-1.jpg

На приведенном выше рисунке представлена ​​логическая архитектура микросервисной системы, которая состоит из двух частей:

  1. Внутренняя архитектура (светло-голубая часть на рисунке) — это архитектура реализации каждой микрослужбы;
  2. Внешняя архитектура (желтая часть на рисунке) — это различные возможности, необходимые для создания мощной микросервисной архитектуры.Обычно существуют различные распределенные возможности, с которыми все знакомы;

Специальное примечание. Упомянутый здесь «сетевой клиент» — это клиент с различными распределенными возможностями, такими как обнаружение регистрации службы / промежуточное ПО MQ / Redis и другое хранилище пар «ключ-значение» / база данных / система отслеживания журналов мониторинга / система безопасности и т. д., а не услуги. Клиенты для взаимодействия, такие как RPC.

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

shared-library-2.jpg

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

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

too-many-sdk-dependencies.jpg

Вторая причина распределенного монолита: просто замените внутрипроцессные вызовы методов удаленными вызовами.

Во время трансформации микросервисной архитектуры разработчики, знакомые с монолитной системой и архитектурой, будут по привычке повторно использовать знания и опыт монолитной эпохи в новой микросервисной архитектуре. Наиболее типичный подход: при следовании модели предметной области для разделения существующего монолитного приложения на несколько микросервисов в соответствии с границами бизнеса часто выбираются методы удаленного вызова, такие как REST или RPC.простая заменаУстаревшие внутрипроцессные вызовы методов.

Когда есть необходимость во взаимодействии двух логических бизнес-модулей:

invoke.jpg

От мономера к микросервису прямой вызов метода заменяется удаленным вызовом (REST или RPC), даже если используется Service Mesh, он только добавляет к ссылке дополнительные узлы sidecar, но не меняет характер удаленного вызова:

invoke2.jpg

Это приводит к вышеупомянутому «распределенному монолиту»:

  • До микросервисов: приложения состояли из несколькихмодулькомпозиция, эти модули вызывают вызовы методов через пространство памяти.....
  • После микросервисов: приложение состоит из несколькихМикросервисысостав, эти микросервисы совершают удаленные вызовы по сети.....

Глядя на системную архитектуру до и после внедрения микросервисов, не считая различий в методах вызова, вы обнаружите, что они почти одинаковы! !

same-architecture.jpg

А версия с микросервисами в некоторых случаях может работать хуже: потому что вызов более хрупок, потому что сеть гораздо менее надежна, чем память. А сеть мы используем как «клей», пытаясь просто склеить разрозненные модули бизнес-логики (разбитые на микросервисы) так же, как и в эпоху монолита, звонки становятся еще более ненадежными.

В связи с этим в«Восемь заблуждений распределенных вычислений»Подробно описано в статье.

Точно так же при использовании функции, если вы все еще используете описанный выше метод, создайте архитектуру FaaS/бессерверная с режимом мышления и проектирования монолитной или микросервисной архитектуры:

invoke3.jpg

Суть не меняется — он просто превращает микросервисы в более мелкие функции, что приводит к огромному увеличению количества удаленных вызовов в системе:

same-architecture2.jpg

Связь внутри системы не изменилась, и Serverless не может изменить эту внутреннюю проблему связи в микросервисах: где звонок, там и связь! Просто изменил степень детализации компонентов с «микросервисов» на «функции».

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

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

Монолитное приложение ≈ Распределенный монолит ≈ Бессерверный монолит

Сводка распределенных монолитных причин

Выше мы перечислили две основные причины, по которым легко сформировать «распределенный монолит» в микросервисах и бессерверной практике:

  • Доступ к распределенным возможностям через общие библиотеки и сетевые клиенты;
  • Просто замените внутрипроцессные вызовы методов удаленными вызовами;

Ниже мы обсудим идеи и контрмеры для решения этих двух проблем.

Представляем ненавязчивое решение: физическая изоляция + логическая абстракция

Одной из причин создания упомянутых выше распределенных монолитов является «доступ к распределенным возможностям через общие библиотеки и сетевые клиенты», что приводит к сильной связи между микросервисами и функциями Lambda и распределенными возможностями. Ненавязчивое решение в лице Service Mesh является эффективным средством для решения этой проблемы.Другие подобные решения включают в себя RSocket/Multiple Runtime Architecture, а также продукты Mesh для баз данных и сообщений.Основные идеи заключаются в следующем:

  1. доверить: Доступ к распределенным возможностям через Sidecar или Runtime, чтобы избежать жесткой привязки, вызванной прямой связью между приложениями и компонентами, предоставляющими распределенные возможности ——Развязка через физическую изоляцию;
  2. Аннотация: скрыть детали реализации внутренних микросервисов, предоставить доступ только к сетевому протоколу и контракту данных, предоставить различные распределенные возможности периферийной архитектуры в форме API и скрыть конкретные реализации, предоставляющие эти возможности ——Развязка через логическую абстракцию;

Возьмем в качестве примера sidecar Service Mesh. После того, как sidecar будет имплантирован, распределенные возможности, к которым бизнес-приложения должны напрямую подключаться, значительно сокращаются (физическая изоляция):

servicemesh-sidecar.jpg

Недавнее появление архитектуры Multiple Runtime/Mecha и продукта Microsoft с открытым исходным кодом Dapr, который следует этой архитектурной идее, подталкивает этот подход к более распределенным возможностям, выходящим за рамки взаимодействия между службами.

dapr-overview.png

В дополнение к делегированию он также обеспечивает абстракцию распределенных возможностей. Например, в Dapr бизнес-приложениям нужно использовать только стандартный API, предоставляемый Dapr, чтобы использовать эти распределенные возможности, не обращая внимания на конкретные продукты (логическая абстракция), которые предоставляют эти возможности:

В качестве примера возьмем обмен сообщениями в модели pub-sub, это API SDK клиента Java, предоставленный Dapr:

public interface DaprClient {
	Mono<Void> publishEvent(String topic, Object event);
   Mono<Void> publishEvent(String topic, Object event, Map<String, String> metadata);
}

Видно, что при отправке событий Dapr полностью скрывает конкретную реализацию базового механизма сообщений, предоставляет приложению высокоуровневую абстракцию отправки сообщений через клиентский SDK и подключает базовую реализацию MQ в Dapr Runtime — полностью разделяет приложение и MQ:

dapr-publish-event.jpg

Введение в архитектуру Multiple Runtime/Mecha здесь не является подробным Заинтересованные студенты могут просмотреть мои предыдущие сообщения в блоге.«Меха: доводя сетки до конца».

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

Вводное событие: излишне сильная связь

После решения проблемы тесной связи между микросервисами/бессерверными системами и внешними распределенными возможностями мы продолжаем рассматривать проблему тесной связи внутри микросервисов/бессерверных систем. Как обсуждалось ранее, от монолита к микросервисам и функциям/бессерверным, если вы просто замените прямые вызовы методов удаленными вызовами (REST или RPC), из-за этого тесно связанного вызова будут сформированы два взаимодействующих модуля. проходить вместе с цепочкой вызовов, в результате чего формируется древовидная сеть зависимостей, которая характеризуется высокой степенью связанности между системами:

dependency.jpg

Чтобы решить эту проблему, основная идея состоит в том, чтобы изучить коммуникационное поведение между двумя компонентами.бизнес-семантика, а затем решите, использовать ли режим Command/Command или режим Event/Event между ними.

Уроки прошлого: события и команды

Прежде всего, давайте рассмотрим концепции и различия между Event и Command, позаимствуем картинку и очень хорошо обобщим ее:

event-command.jpg

Что такое событие?

Событие: «Значительное изменение состояния» — К. Мани Чанди.

Событие представляет в полеЭто произошлоВещи: Обычно означает, что Произошло Действие, и Статус изменился.

потому чтоЭто произошловещи, поэтому:

  • Событие можно понимать как объективную констатацию того, что произошло;
  • Это означает, что События обычно неизменны: информация о Событии (представляющая объективные факты) не может быть изменена, а генерация События не может быть отменена;
  • Именование: Событие обычно называют в честь совершенного времени глагола, например, UserRegistredEvent;

Целью создания события является распространение следующего события:

  • Уведомить заинтересованных наблюдателей о произошедшем Событии;
  • Наблюдатель, который получает Событие, будет судить и принимать решения на основе содержания События: может быть следующее действие (Действие), и некоторым действиям может потребоваться связь с другими модулями для запуска команды (Команды). состояние продолжает запускать новые события (Event);

Как событие распространяется:

  • Событие имеет четкий «источник/источник», то есть место, где происходит генерация Событий (или изменение состояния);
  • Но поскольку производитель не знает (не желает/не заботится), какие наблюдатели будут заинтересованы в Событии, Событие не содержит информации «назначение/назначение»;
  • События обычно распространяются в режиме pub-sub через механизм MessageQueue;
  • События обычно не требуют ответа или отклика;
  • Событие обычно используется для публикации (публикации);

Что такое команда?

Команда используется для передачи запроса на выполнение действия (Action).

Команда означаетслучитсявещи:

  • Обычно означает, что действие еще не произошло, но должно произойти (если запрос принят и выполнен);
  • Существует вероятность отказа: нежелание выполняться (сбой проверки параметров, недостаточно прав), невозможность выполнения (сбой получателя или ресурс недоступен);
  • Именование: команда обычно называется по обычной форме глагола, например, UserRegisterCommand;

Целью создания команды является выполнение следующей команды:

  • Отправьте Команду нужному исполнителю;
  • Исполнитель, получивший Команду, будет выполнять ее в соответствии с требованиями Команды: в процессе выполнения может быть несколько действий (Действий), и некоторые действия могут нуждаться в обмене данными с другими модулями для запуска команды (Команды). изменение состояния домена для продолжения запуска новых событий (Event);

Как распространяется команда:

  • Команда имеет явный источник (Source), то есть инициатор Команды;
  • У команды также есть очень специфический исполнитель (и обычно один), поэтому имя обычно содержит информацию «назначение/назначение»;
  • Команда обычно осуществляется через механизм удаленной связи «точка-точка», такой как HTTP / RPC, обычно синхронный;
  • Команде обычно требуется ответ (Response): ответ на то, выполнена ли Команда (потому что она может быть отклонена), результат выполнения (потому что выполнение может не выполниться);
  • Команда обычно используется для отправки (Send);

Сводка команд и событий

Резюме. Существенная разница между командой и событием заключается в их намерении:

  • Цель командованияскажи чего ожидать;
  • Цель события –расскажи что случилось;

Различия в намерениях заканчиваются, в частности, зависимостями между службами:

denpendency-direction.jpg

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

Зависимости команды просты и понятны: Инициатор "явные зависимости" получатель;

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

Зависимости событий немного сложнее: инициатор указан явноне зависеть отполучатель, получатель существует для инициатора"неявная обратная зависимость" - Обратное означает, что направление обратное по сравнению с отношением зависимости команды, и получатель в свою очередь полагается на инициатора; неявное означает, что эта зависимость отражается только в "получатель зависит от события, а событие публикуется инициатор. В косвенной связи ", нет прямой зависимости между получателем и инициатором.

С точки зрения бизнеса: реляционные модели определяют коммуникативное поведение

После рассмотрения Command и Event давайте вернемся к нашему предыдущему вопросу: почему неправильно просто заменять прямые вызовы методов удаленными вызовами (REST или RPC)? Основная причина заключается в том, что в этом процессе замены так называемаяПростойЭто означает, что нужно выбрать удаленный вызов напрямую, не задумываясь, то есть выбрать метод полной команды:

dependency-command.jpg

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

busness-handling.jpg

  1. Бизнес-ввод: микросервис A на рисунке получает ввод бизнес-запроса (может быть в командном режиме или в режиме событий).
  2. Логика бизнеса»выполнить» процесс выполнения:
    • Микросервис A будет выполнять множество действий в процессе выполнения Команды (или запускаться Событием);
    • Некоторые из них являются внутренними действиями микросервиса A, такими как операционная база данных, операционное хранилище ключей и значений, обработка бизнес-логики в памяти и т. д.;
    • Некоторые взаимодействуют с внешними микрослужбами, например выполняют запросы или просят другую сторону выполнить определенные операции.Эти методы связи представлены в форме команд, например связь с микрослужбой B, как показано на рисунке;
    • После завершения этих внутренних и внешних действий процесс выполнения завершается;
    • Если это Command, нужно вернуть результат операции Command в виде ответа;
  3. изменение статуса бизнесакурокПоследующее поведение:
    • После завершения вышеуказанного процесса выполнения, если есть изменение в бизнес-состоянии, для этого необходимо опубликовать событие;
    • События распространяются на другие микросервисы, заинтересованные в событии, через шину событий: обратите внимание, что этот процесс не связан, микросервис A не знает и не заботится о том, какие микросервисы заинтересованы в этом событии, и событию не нужно реагировать;

Во время выполнения и обработки бизнес-логики вышеуказанного микросервиса A ему необходимо взаимодействовать с другими микросервисами в форме команды или события, такими как микросервисы B/C/D/E на рисунке. Для этих микросервисов B/C/D/E (рассматриваемых как подчиненные сервисы микросервиса A) их поток обработки после получения бизнес-запроса аналогичен потоку микросервиса A.

Таким образом, мы можем просто вывести сценарий, когда логика бизнес-процессинга распространяется от микросервиса A до нижестоящих сервисов микросервиса A (микросервис B/C/D/E на рисунке):

busness-handling-deeper.jpg

Обобщая поведение микросервисов A/B/C/D/E, задействованных на рисунке в обработке бизнес-логики, можно сказать, что поведение при обмене данными примерно такое же:

busness-handling-cases.jpg

Абстрактно коммуникационное поведение типичного микросервиса в бизнес-процессе можно резюмировать в виде следующих четырех пунктов:

microservice-abstraction.jpg

  1. входить: принять в качестве входных данных запрос команды или уведомление о событии, что является отправной точкой бизнес-процесса;
  2. Внутреннее действие: внутренняя логика микросервисов, обычно такая как операции с базами данных, доступ к хранилищам ключей и значений, таким как Redis (соответствует различным распределенным возможностям в архитектуре Multiple Runtime/Mecha). Необязательно, обычно 0-N;
  3. внешний доступ: доступ к другим внешним микросервисам в форме Command. Необязательно, обычно 0-N;
  4. Уведомление об изменениях: Опубликовать события в форме событий, чтобы уведомить изменения в бизнес-статусе, созданном вышеуказанными операциями. необязательно, обычно 0-1;

В этом паттерне поведения 2 и 3 расположены не по порядку и могут выполняться поэтапно, тогда как 4 обычно выполняется в конце процесса: только когда выполняются различные внутренние Действия и внешние Команды, завершается реализация бизнес-логики и завершаются изменения состояния. , "Лодка сделана" может быть выпущена в виде События: "Операция выполнена, статус изменен, пожалуйста, знайте".

Здесь мы рассмотрим предыдущее резюме - существенное различие между событием и командой заключается в их назначении:

  • Цель события — сообщитьЭто произошловещи;
  • Цель командования - сообщитьнадеюсь, что это произойдетвещи;

С точки зрения обработки бизнес-логики, команда с внешним доступом и действие внутренней операции являются «бизнес-логикой».выполнить«Часть: эти операции составляют полную бизнес-логику — в случае сбоя этих операций бизнес-процесс окажет прямое влияние (сбой или частичный сбой). Публикация событий является продолжением после завершения бизнес-логики»Уведомление«Часть: когда бизнес-логика обрабатывается и состояние изменяется, последующая дальнейшая обработка управляется событиями. Обратите внимание, чтоводить машину, а не прямое манипулирование.

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

microservice-timeline.jpg

Проблема, доставляемая полной командой: ненужная сильная связь

Проблема с микросервисной системой всей команды заключается в том, что в ссылке «уведомление об изменении состояния» на последнем этапе выше модели событий и pub-sub не используются, но команда продолжает вызывать другие нижестоящие связанные микросервисы один за другим. :

all-commands.jpg

События могут разделять производителей и потребителей, поэтому на рисунке нет сильной зависимости между микрослужбой A и микрослужбой C/D/E, и нет необходимости блокировать существование друг друга. Но с Command все по-другому.После того, как метод Command будет принят, микросервис A и связанные с ним микросервисы C/D/E сформируют сильную зависимость, и эта зависимость будет распространяться, что в конечном итоге приведет к формированию огромного и глубокого дерева зависимостей, в то время как Function Проблемы имеют тенденцию быть более серьезными из-за более тонкой детализации:

dependency-command.jpg

Если события вводятся в ссылку «уведомление об изменении состояния», микрослужбы и нижестоящие уведомленные микрослужбы могут быть разделены, тем самым освобождая зависимости и избегая неограниченного распространения. Как показано на рисунке ниже, рисунок слева представляет собой зависимость после использования Event вместо Command для уведомления об изменении состояния.Учитывая разъединяющий эффект Event на производителей и потребителей, мы «отрезаем» зеленую стрелку Event, поэтому мы get Справа — граф системных зависимостей, разбитый на несколько небольших деревьев зависимостей:

event-decouple-system.jpg

Предложения по использованию событий и команд:

  • Когда монолитное приложение разбивается на микрослужбы, оно не должно просто заменить исходный вызов метода на Command;
  • Семантика бизнес-логики каждого вызова должна быть пересмотрена: является ли он частью выполнения бизнес-логики? Или уведомление о состоянии после завершения выполнения?
  • Затем решите, использовать ли команду или событие соответственно;

Оркестрация и координация

При использовании команд и событий есть еще две концепции: оркестровка и координация.

Сообщение в блоге настоятельно рекомендуется здесь,Microservices Choreography vs Orchestration: The Benefits of Choreography,авторJonathan Schabowsky, технический директор Solace. В этом блоге он обобщает два способа совместной работы микросервисов и проводит яркую аналогию:

  1. Оркестровка: все элементы и взаимодействия должны активно контролироваться, как дирижер, дирижирующий музыкантами оркестра — в соответствии с Командованием;
  2. Хореография: необходимо установить шаблон, и микросервисы будут танцевать под музыку без присмотра и инструкций — в соответствии с событиями;

Orchestration-VS-Choreography.png

Я также видел много статей с похожими взглядами, одна из картинок впечатляет, я взял их выдержки:

what-you-want-what-you-get.jpg

слеваожидатьИдеальная цель единообразия, полученная с помощью оркестровки (Orchestration), справадействительныйПолучите большую сцену опрокидывания.

Проблемы, вызванные всем событием: трудности развития и нечеткие границы бизнеса

В использовании Command и Event, помимо использования Command во всем процессе, есть еще одна крайность, использующая Event во всем процессе, которая чаще встречается в Lambda (FaaS):

all-events.jpg

Первая проблема с этим методом заключается в том, что он использует семантику Event вместо семантики Command, из-за разницы в семантике между Command и Event такая замена может показаться неудобной:

  • Команда является индивидуальной, и Событие, которое его заменяет, должно выродиться из «1: N» в «1: 1», и модели pub-sub больше не существует;
  • Команда должна возвращать результат, особенно команда класса Query должна иметь результат запроса.После использования события вместо этого она должна реализовать «событие, поддерживающее ответ», например, реализовать модель «запрос-ответ» в механизме сообщений;
  • Либо ввести еще одно Событие для оповещения результата в обратном порядке, то есть заменить синхронную Команду двумя асинхронными Событиями — это требует дополнительной подписки и обработки инициатором, а сложность разработки гораздо больше, чем использование простой Команды;
  • Кроме того, возникает очень неприятная проблема с состоянием: контекст межсервисного взаимодействия обычно зависит от состояния, а событие ответа должно быть отправлено в конкретный экземпляр инициатора события запроса, и ни одно из них не может быть выбрано произвольно. Это делает Reply Event привязанным не только к сервису подписчика 1:1, но и к конкретному экземпляру этого сервиса — такое Reply Event больше нельзя называть Event;

two-events-as-one-command.jpg

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

Для микросервисных систем с большей степенью детализации обычно сложно добиться безгражданства, поэтому обычно неудобно использовать Event во всем процессе микросервисов, и на самом деле мало кто этим занимается. В системе Function/FaaS с очень малой степенью детализации чаще используется метод Event во всем процессе.

Что касается использования событий на протяжении всего процесса, у меня лично есть оговорки, и я склонен надлежащим образом сохранить использование Command даже в FaaS: если операция является неотъемлемой частью выполнения «бизнес-логики», то тесная связь Командный метод Вместо этого он может лучше отражать наличие этой «бизнес-логики»:

command-event-in-faas.jpg

Если метод Event будет полностью принят и «полностью» развязан, возникнут новые проблемы (независимо от дополнительной сложности в кодировании) — при массовых мелкозернистых вызовах Event бизнес-логику было трудно отразить, а модель предметной области ( Моделирование предметной области) и Ограниченный контекст (Bounded Context) погружены в эти вызовы событий и их трудно идентифицировать:

all-command-in-faas.jpg

Примечания: Эта проблема называется «Лямбда-пинбол», и здесь она подробно обсуждаться не будет.

Выбор команды и события: искать истину в фактах и ​​беспристрастности

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

Мое личное мнение состоит в том, что я склонен судить о семантике фактической обработки «бизнес-логики»:

  • Если это бизнес-логика»выполнить” часть: обычно предпочитают использовать Command;
  • Если это продолжение после завершения бизнес-логики "Уведомление”: Настоятельно рекомендуется использовать Event;

microservice-timeline.jpg

Резюме и размышления

Осторожно: не сводитесь к распределенному монолиту

Выше мы перечислили две основные причины и меры противодействия легкому формированию «распределенного монолита» в микросервисах и бессерверной практике:

  • Получите доступ к распределенным возможностям через общие библиотеки и сетевые клиенты: внедрите ненавязчивые решения для разделения приложений и различных распределенных возможностей;
  • Просто замените внутрипроцессные вызовы методов удаленными вызовами: различайте Command и Event и введите Event, чтобы удалить ненужную сильную связь между микросервисами; Первый еще не является технически зрелым, типичные проекты, такие как Istio/Dapr, все еще нуждаются в усилении, а сопротивление приземлению пока относительно велико. Но последнее было зрелой практикой в ​​отрасли в течение многих лет и широко использовалось еще до появления микросервисов и бессерверных технологий, поэтому рекомендуется немедленно приступить к улучшению.

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

Рефлексия: спокойное мышление за пределами шума и оскорблений

Если всегда оставаться на уровне «просто заменить внутрипроцессные вызовы методов удаленными вызовами» в практике микросервисов и бессерверных, придерживаться привычек единой эпохи и вводить различные SDK, тоРаспределенный монолитПроблемы неизбежны. Наша трансформация микросервисов и бессерверная практика часто заканчиваются:

Превращение монолита в... хуже распределенный монолит.

Конечно, микросервисы могут стать распределенными монолитами, но это не означает, что архитектура микросервисов — ложь, и не означает, что она хуже, чем монолитная архитектура. Бессерверные системы также могут столкнуться с распределенными монолитами (и с Lambda Pinball, о котором будет подробно рассказано), но это не означает, что бессерверные технологии нежелательны — и микросервисы, и бессерверныеинструменты для решения конкретных задач, как и все инструменты, прежде чем использовать инструменты, нам нужно изучить и понять их и научиться правильно их использовать:

  • Необходимо создать правильную архитектуру для микросервисов, которая обязательно будет сильно отличаться от монолитной архитектуры: ее нельзя «не трогать» для замены вызовов методов удаленными вызовами, и лучше всего не использовать общие библиотеки классов и сети. клиенты напрямую, использование различных распределенных возможностей;
  • Serverless требует от нас тщательного переосмысления архитектуры, необходимо изменить образ мышления, чтобы преимущества перевесили недостатки;

Ссылки и рекомендуемая литература

Официальная учетная запись: распределенная архитектура финансового уровня (Antfin_SOFA)