Привет, Хабр!  

В прошлой статье мы начали разговор о паттернах микросервисов (Часть 1). Ну что ж, давайте продолжим!

Паттерн «API-шлюз» (API Gateway)

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

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

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

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

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

  • Gateway Routing. Шлюз используется как обратный Proxy, перенаправляющий запросы клиента на соответствующий сервис.

  • Gateway Aggregation. Шлюз используется для разветвления клиентского запроса на несколько микросервисов и возвращения агрегированных ответов клиенту.

  • Gateway Offloading. Шлюз решает сквозные задачи, которые являются общими для сервисов: аутентификация, авторизация, SSL, ведение журналов и так далее. 

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

Паттерн «Бэкенды для фронтендов» (Backends for Frontends, BFF)

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

Такой подход удобен, когда планшеты, компьютеры или мобильные телефоны требуют разные данные. Но как выбирать между стандартным API Gateway и BFF? 

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

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

Переходим к следующим паттернам, связанным с построением пользовательского интерфейса. Я объединил на одной схеме два паттерна, которые сейчас популярны в разработке UI.

Паттерны построения пользовательского интерфейса «Client-Side UI Composition» и «Server-Side Page Fragment Composition»

Как реализовать экран или страницу пользовательского интерфейса, которая отображает данные из нескольких служб? 

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

Существуют два основных подхода к сборке пользовательских интерфейсов

Первый подход — сборка на стороне клиента. В этом случае интерфейс собирается непосредственно на клиенте. Для реализации этого подхода часто используются фронтенд-фреймворки, такие как Angular.js или React.js. Эти инструменты позволяют динамически подгружать отдельные блоки данных, что особенно полезно, если каждый блок обслуживается отдельным микросервисом. Это позволяет оптимизировать загрузку страниц, разбивая её на части и избегая передачи большого объема данных сразу.

Когда UI становится сложным, а объем передаваемых данных велик, имеет смысл разделить страницу на несколько блоков (например, A, B и C). Каждый такой блок может получать свои данные от соответствующего микросервиса. При таком подходе клиентская сторона самостоятельно обращается к различным сервисам для получения необходимых данных. 

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

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

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

Паттерн «Защита от каскадных сбоев» (Circuit Breaker)

Шаблон Circuit Breaker отслеживает сбои и предотвращает дальнейшие запросы к неработающему сервису, предоставляя ему время на восстановление и защищая систему от полного отказа. 

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

Что это значит? Проблема заключается в следующем: если микросервис выходит из строя, попытки обращения к нему только усугубляют ситуацию, мешая восстановлению. Чтобы избежать окончательного сбоя, применяется паттерн Circuit Breaker. Эта прослойка контролирует работу микросервиса. Пока всё работает нормально, запросы от одного микросервиса беспрепятственно доходят до другого. Однако, если количество ошибок достигает определённого порога (что задаётся в настройках Circuit Breaker), система определяет, что с сервисом возникли проблемы, и мгновенно возвращает ошибку запрашивающему микросервису, не передавая запрос дальше. Таким образом, неисправный микросервис получает шанс на восстановление, поскольку новые запросы к нему временно прекращаются.

Circuit Breaker периодически проверяет состояние микросервиса. Если микросервис начинает отвечать корректно, он позволяет проходить обычным запросам. Если же микросервис всё ещё не функционирует должным образом, Circuit Breaker возвращается в режим блокировки, продолжая защищать систему от перегрузки. 

Часто механизм Circuit Breaker уже используется в IT ландшафте в который мы встраиваемся. Тем не менее, если подобная защита отсутствует, нам придётся самостоятельно реализовывать меры против каскадных сбоев. Как системным аналитикам, нам необходимо убедиться, что в нашей архитектуре предусмотрена защита от каскадных сбоев. Если её нет, нам следует подумать над тем, как её внедрить. 

Теперь переходим к следующему паттерну — агрегация логов.

Паттерн «Агрегация логов» (Log Aggregation)

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

Паттерн «Распределённая трассировка» (Distributed Tracing)

Паттерн Distributed Tracing предназначен для решения задачи отслеживания распределённых транзакций. Он предполагает назначение уникального идентификатора (TraceId) каждому внешнему запросу, который затем передается всем сервисам, участвующим в обработке этого запроса, и фиксируется в логах.

Хотя тема мониторинга может показаться несвязанной с задачами системного анализа, она часто становится источником серьёзных проблем, особенно при запуске системы в эксплуатацию. Чтобы избежать таких ситуаций, существуют определённые паттерны: паттерн централизованного ведения логов и паттерн распределённой трассировки. Эти подходы тесно связаны с такими концепциями, как Saga (см. первую часть статьи), распределёнными транзакциями и управлением ими. Например, при использовании любого метода управления распределёнными транзакциями (оркестровка или хореография), каждый микросервис записывает свои логи по данной транзакции. Вопрос в том, как отслеживать одну и ту же транзакцию в разных записях логов?

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

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

Паттерн «Проверка здоровья» (Health Check)

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

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

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

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

Ну и пока завершающий, но очень полезный паттерн.

Шаблон «Корректное восстановление после ошибок» (Retry)

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

В чем суть? Бывают ситуации, когда нужно получить данные или отправить их в другой микросервис, но тот не отвечает. Мы получаем ошибку 500, и непонятно, что делать дальше. Тогда мы обращаемся повторно. Мы пробуем снова связаться с сервисом, надеясь получить необходимый результат. Важно при этом не перегрузить сервис запросами. Поэтому системный аналитик определяет стратегию retry: сколько попыток сделать, с каким интервалом и как поступить, если все попытки окажутся неудачными. Нужно решить, продолжать ли попытки или прекратить их после определенного количества неудач. 

Что делать, если ни одна попытка не увенчалась успехом? Продолжаем ли мы выполнение задачи или прекращаем ее? Здесь возникает дилемма: с одной стороны, нам нужно получить/передать данные, с другой — нельзя перегружать сервис. Если в системе предусмотрена защита от каскадных сбоев, можно повторять запросы неограниченное количество раз, поскольку это не навредит сервису. Если же такой защиты нет, приходится тщательно продумывать стратегию действий. Например, можно установить три попытки с интервалом в пять секунд. Если после этих попыток ответ не получен, дальнейшие попытки прекращаются. Иногда делают так: после получения ошибки вторая попытка — через пять секунд, третья — через десять секунд и так далее, постепенно увеличивая интервал. Через определенное время, скажем, через минуту, если ответ так и не был получен, процесс завершается. Но все эти настройки задержек между запросами индивидуальны и продумываются для каждого сервиса отдельно. 

Как системные аналитики, мы отвечаем за внедрение стратегии retry. Так что будьте готовы к вопросу от разработчиков: «Что делать, если сервис не отвечает?». Ответственность за принятие решения лежит на системном аналитике. Помните о шаблоне retry, особенно если в системе отсутствует защита от каскадных сбоев. 

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

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

 Всем удачи!

Комментарии (0)