Поделиться через


Сравнение шаблона шлюза API с прямым взаимодействием клиента и микрослужбы

Совет

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

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

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

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

Возможный подход — использование архитектуры с прямым взаимодействием между клиентом и микрослужбой. При таком подходе клиентские приложения могут отправлять запросы к некоторым микрослужбам напрямую, как показано на рис. 4-12.

Diagram showing client-to-microservice communication architecture.

Рис. 4-12. Использование архитектуры с прямым взаимодействием клиента и микрослужбы

При таком подходе у каждой микрослужбы есть общедоступная конечная точка, иногда с отдельным портом TCP для каждой микрослужбы. Например, определенная служба может иметь следующий URL-адрес в Azure:

http://eshoponcontainers.westus.cloudapp.azure.com:88/

В рабочей среде на основе кластера этот URL-адрес будет указывать на подсистему балансировки нагрузки кластера, которая, в свою очередь, распределяет запросы между микрослужбами. В производственной среде можно использовать контроллер доставки приложений, например шлюз приложения Azure между вашими микрослужбами и Интернетом. Данный слой выступает как прозрачный уровень, который не только выполняет балансировку нагрузки, но и защищает службы благодаря завершению SSL-запросов. Это уменьшает нагрузку на узлах за счет разгрузки завершения SSL-запросов и других задач, активно использующих ЦП, в шлюз приложений Azure. В любом случае подсистема балансировки нагрузки и контроллер доставки приложений прозрачны с точки зрения логической архитектуры приложения.

Архитектура прямого взаимодействия клиента и микрослужбы достаточно хорошо подходит для небольших приложений на основе микрослужб, особенно если клиентское приложение представляет собой веб-приложение на стороне сервера, например приложение MVC ASP.NET. Однако при создании больших и сложных приложений на основе микрослужб (например, при обработке десятков типов микрослужб) и особенно в том случае, если клиентские приложения представляют собой удаленные мобильные приложения или одностраничные веб-приложения, этот подход приводит к появлению нескольких проблем.

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

  • Как клиентские приложения могут свести к минимуму число запросов к серверной части и уменьшить частоту обмена данными с несколькими микрослужбами?

Взаимодействие с несколькими микрослужбами для создания одного окна пользовательского интерфейса увеличивает число круговых путей через Интернет. Это увеличивает задержку и сложности на стороне пользовательского интерфейса. В идеальном случае ответы должны эффективно вычисляться на стороне сервера. Это сокращает задержки, так как можно возвращать несколько фрагментов данных в параллельном режиме, и в некоторых пользовательских интерфейсах данные можно отобразить сразу же после их появления.

  • Как вы можете обрабатывать сквозную функциональность, например проверку подлинности, преобразование данных и динамическую диспетчеризацию запросов?

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

  • Как клиентские приложения взаимодействуют со службами, использующими не поддерживаемые в Интернете протоколы?

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

  • Как создать интерфейс, специально предназначенный для мобильных приложений?

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

Преимущества шлюза API над прямым взаимодействием клиента и микрослужбы

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

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

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

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

  • Проблемы безопасности. Без шлюза все микрослужбы будут доступны извне, что значительно увеличивает уязвимую зону, если не скрыть внутренние микрослужбы, не используемые клиентскими приложениями напрямую. Чем меньше уязвимая зона, тем надежнее будет ваше приложение.

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

Что представляет собой шаблон шлюза API?

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

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

На рисунке 4-13 показано, как пользовательский шлюз API можно использовать в упрощенной архитектуре на основе микрослужб, которая включает всего несколько микрослужб.

Diagram showing an API Gateway implemented as a custom service.

Рис. 4-13. Использование шлюза API, реализованного в виде пользовательской службы

Приложения подключаются к одной конечной точке — шлюзу API, который настроен для пересылки запросов в отдельные микрослужбы. В этом примере шлюз API будет реализован в виде пользовательской службы ASP.NET Core WebHost, запущенной в виде контейнера.

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

Следует соблюдать осторожность при реализации шаблона шлюза API. Обычно не рекомендуется иметь один шлюз API, который агрегирует все внутренние микрослужбы вашего приложения. Такой шлюз выступает в качестве монолитного агрегатора или оркестратора и нарушает автономность микрослужб, связывая все микрослужбы друг с другом.

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

При разделении уровня шлюза API на несколько шлюзов API, если приложение включает несколько клиентских приложений, это разделение можно использовать в качестве основы для описания типов шлюзов API, то есть разработать индивидуальный фасад для каждого клиентского приложения. Такую схему иногда называют "Серверная часть для клиентской части" (BFF). Каждый шлюз API может предоставлять различные API с учетом каждого типа клиентского приложения (а возможно, и форм-фактора), на основе реализации кода адаптера, который вызывает несколько внутренних микрослужб, как показано ниже.

Diagram showing multiple custom API Gateways.

Рис. 4-13.1. Использование нескольких пользовательских шлюзов API

На рис. 4-13.1 показаны шлюзы API, разделенные по типу клиента: для мобильных клиентов и для веб-клиентов. Традиционное веб-приложение подключается к микрослужбе MVC, использующей шлюз веб-API. В примере показана упрощенная архитектура с несколькими детально настроенными шлюзами API. В этом примере границы для разделения шлюзов API строго основаны на шаблоне "Серверная часть для клиентской части" (BFF), то есть шлюзы реализуют только те API, которые нужны конкретному клиентскому приложению. Но в более крупных приложениях следует пойти немного дальше и использовать границы бизнес-процессов в качестве второго фактора разделения шлюзов API.

Основные возможности шаблона шлюза API

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

Обратный прокси-сервер или маршрутизация шлюза. Шлюз API предоставляет обратный прокси-сервер для маршрутизации или перенаправления запросов (маршрутизация уровня 7, обычно это HTTP-запросы) к конечным точкам внутренних микрослужб. Шлюз предоставляет единую конечную точку (URL-адрес) для клиентских приложений, а внутри сопоставляет запросы от них с конкретными группами внутренних микрослужб. Эта возможность маршрутизации помогает отделить клиентские приложения от микрослужб, но она не менее удобна при обновлении монолитного API. Между этим монолитным API и клиентскими приложениями размещается шлюз API, что позволяет добавлять новые API в формате микрослужб и продолжать использовать монолитный API вплоть до его разделения на множество микрослужб. Благодаря шлюзу API для клиентских приложений неважно, как реализованы конкретные API-интерфейсы: в виде внутренних микрослужб или монолитных API. И что более важно, в процессе развития, рефакторинга и разделения монолитного API на микрослужбы шлюз API защищает клиентские приложения от любых изменений URI.

Дополнительные сведения см. в разделе о шаблоне маршрутизации шлюза.

Агрегирование запросов. Шаблон шлюза можно дополнить агрегированием нескольких клиентских запросов (обычно HTTP-запросов), направленных к разным внутренним микрослужбам, в один клиентский запрос. Этот шаблон особенно удобен, когда клиенту для отображения страницы или экрана нужны данные из нескольких микрослужб. При таком подходе клиентское приложение отправляет на шлюз API один запрос, а шлюз преобразует его в несколько запросов к внутренним микрослужбам, затем объединяет полученные результаты и отправляет в клиентское приложение. Основное преимущество и цель этого шаблона разработки заключается в уменьшении объема данных, передаваемых между клиентскими приложениями и внутренними API. Это особенно важно для удаленных приложений, размещаемых за пределами центра обработки данных, где расположены микрослужбы, например для мобильных приложений или запросов от приложений SPA, созданных на JavaScript в браузерах на удаленном клиентском компьютере. Для обычных веб-приложений, которые выполняют запросы в серверной среде (например, веб-приложение ASP.NET Core MVC), этот шаблон менее полезен, так как сетевая задержка и так намного меньше, чем у удаленных клиентских приложений.

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

Дополнительные сведения см. в разделе о шаблоне агрегирования на шлюзе.

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

  • Проверка подлинности и авторизация
  • интеграция средства обнаружения служб;
  • кэширование ответов;
  • политики повторных попыток, размыкатель цепи и качество обслуживания;
  • ограничение скорости и регулирование;
  • Балансировка нагрузки
  • ведение журнала, трассировка, корреляция;
  • преобразования заголовков, строк запроса и утверждений;
  • Список разрешенных IP-адресов

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

Использование продуктов с функциями шлюза API

В зависимости от конкретной реализации шлюз API может поддерживать еще множество сквозных функций. Здесь рассматриваются следующие темы:

Управление API Azure

Служба управления API Azure (как показано на рис. 4-14) не только позволяет удовлетворить потребности шлюза API, но и предоставляет дополнительные функции, например сбор аналитических данных от интерфейсов API. Если вы используете решение для управления API, шлюз API является только компонентом в рамках полного решения по управлению API.

Diagram showing how to use Azure API Management as your API gateway.

Рис. 4-14. Использование управления API Azure для шлюза API

Azure Управление API решает, как шлюз API, так и управление, такие как ведение журнала, безопасность, измерение и т. д. В этом случае при использовании продукта, такого как Azure Управление API, тот факт, что у вас может быть один шлюз API, не так рискованный, так как эти типы шлюзов API являются "более тонкими", то есть вы не реализуете настраиваемый код C#, который может развиваться в сторону монолитного компонента.

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

Аналитические сведения, доступные из системы управления API, помогут вам понять, как используются ваши API и насколько эффективно они работают. Для этого вы можете просматривать отчеты практически в режиме реального времени и выявлять тенденции, которые могут повлиять на ваш бизнес. Кроме того, вы можете вести журналы запросов и ответов как для интерактивного, так и для автономного анализа.

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

В этом руководстве и в примере приложения (eShopOnContainers) архитектура ограничивается простой реализацией пользовательской контейнерной архитектуры, чтобы сосредоточиться только на контейнерах без использования продуктов PaaS, таких как управление API Azure. Но для крупных приложений на основе микрослужб, развернутых в Microsoft Azure, мы рекомендуем применить в рабочей среде шлюз API на основе управления API Azure.

Ocelot

Ocelot — это упрощенный шлюз API, рекомендуемый для более простых случаев. Шлюз API Ocelot с открытым кодом на основе .NET Core специально разработан для архитектуры микрослужб, в которой нужны единые точки входа в систему. Он не требует большого количества ресурсов, быстро работает, легко масштабируется, а также наряду с многими другими функциями поддерживает маршрутизацию и проверку подлинности.

Основная причина выбора Ocelot для эталонного приложения eShopOnContainers 2.0 заключается в том, что Ocelot — это упрощенный шлюз API .NET Core, который можно развернуть в той же среде развертывания приложений, где развертываются микрослужбы и контейнеры, такие как узел Docker, Kubernetes и т. д. И так как он основан на .NET Core, он кроссплатформенный, позволяющий развертывать в Linux или Windows.

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

Кроме него, существует много других продуктов с функциональностью шлюза API, например Apigee, Kong, MuleSoft, WSO2. Также есть много продуктов, например Linkerd и Istio, реализующих функции управления входящими данными.

После разделов с описанием базовой архитектуры и шаблонов мы переходим к описанию реализации шлюза API на примере Ocelot.

Недостатки шаблона шлюза API

  • Наиболее важный недостаток заключается в том, что при реализации шлюза API вы связываете этот уровень с внутренними микрослужбами. Такое связывание может привести к серьезным проблемам для вашего приложения. Клеменс Вастер (Clemens Vaster), архитектор команды по разработке служебной шины Azure, называет эту потенциальную трудность "новой служебной шиной предприятия (ESB)" в выступлении Messaging and Microservices (Обмен сообщениями и микрослужбы) на GOTO 2016.

  • Использование шлюза API микрослужб создает возможную дополнительную единую точку отказа.

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

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

  • Шлюз API требует дополнительных затрат на разработку и последующее обслуживание, если он включает пользовательскую логику и агрегирование данных. Чтобы предоставить конечные точки каждой микрослужбы, разработчикам необходимо обновить шлюз API. Кроме того, изменения в реализации внутренних микрослужб могут вызвать изменения кода на уровне API шлюза. Тем не менее, если в шлюзе API просто применяется безопасность, ведение журналов и управление версиями (как при использовании управления API Azure), эти затраты на разработку могут отсутствовать.

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

Дополнительные ресурсы