Обычно кодовая база унаследованных систем далека от идеала. Здесь можно обнаружить запутанные модели данных, непоследовательные соглашения об именовании и тесную связь между компонентами.
Если вы проводите миграцию по паттерну Strangler Fig, унаследованная система не только продолжит работать, но и будет обмениваться данными с микросервисами.
Проблемы монолита могут помешать разработке микросервисов и повлиять на их производительность:
можно повредить данные, которые новая и унаследованная системы передают друг другу,
затраты на обслуживание вырастут,
циклы разработки замедлятся.
В итоге команда вложит много сил в миграцию, а новая архитектура только усугубит проблемы приложения.
К счастью, все эти проблемы можно предотвратить. Для этого используют Anti-Corruption Layer (ACL). В этом уроке расскажем, что это такое.
Что такое Anti-Corruption Layer
Anti-Corruption Layer обычно переводят как «антикоррупционный слой». Это не совсем удачная адаптация. Точнее будет назвать его «слоем, который предотвращает повреждение данных».
📎 Anti-Corruption Layer (ACL) — это паттерн проектирования, который помогает создать границу между новой системой и унаследованной. Через этот уровень проходят все данные, которые системы передают друг другу. ACL знает их форматы и модели данных. Он адаптирует информацию под требования получателя.
Чтобы создать Anti-Corruption Layer, используют несколько популярных паттернов проектирования. Обычно это Facade и Adapter. Эти паттерны используют для сопоставления API монолитных систем с типами и интерфейсами, которые являются частью микросервисов.
ACL защищает микросервисы от нестабильности и потенциального повреждения старой системы. Этот уровень:
Изолирует микросервисы от сложностей и проблем унаследованной системы. Это повышает шансы на то, что новые системы будут работать эффективно.
Управляет маршрутизацией запросов между монолитом и микросервисами. Допустим, в монолитной архитектуре функциональность корзины зависит от каталога товаров. В процессе миграции каталог вынесли в микросервис. ACL будет передавать информацию от монолитной корзины к микросервису каталога и обратно.
Адаптирует данные под требования разных систем. Устаревшие системы зачастую используют устаревшие форматы данных или протоколы, которые несовместимы с современными микросервисами. ACL выступает в роли посредника и преобразует данные в формат, который понимает получатель.
Инкапсулирует монолитную систему. Инкапсулируя причуды и странности унаследованной системы, ACL позволяет микросервисам взаимодействовать с чистым и последовательным интерфейсом. Это упрощает разработку и сопровождение новых сервисов.
Как работает ACL
С этим уровнем алгоритм обмена данными выглядит так:
Микросервису нужна информация от монолитной системы. Он посылает запрос на ACL.
ACL передаёт запрос адаптеру, чтобы он перевёл запрос микросервиса в формат и семантику монолитной системы.
Адаптер переводит запрос и отправляет его монолитной системе.
Монолитная система обрабатывает запрос и отправляет ответ адаптеру.
Адаптер переводит ответ в формат и семантику микросервиса, а затем передаёт запрос ACL.
ACL отправляет переведённые данные микросервису.
Вот этот же процесс в виде схемы:
А теперь небольшое задание. Оно поможет проверить, насколько хорошо вы понимаете ACL.
ACL — это инструмент, который позволяет провести постепенную миграцию. Его используют только в процессе перехода. Теперь разберём, когда нужно внедрять и отключать ACL.
Когда внедрять и отключать ACL
➡️ ACL внедряют, как только команда начинает разработку микросервиса, которому нужно взаимодействовать с монолитом.
Возьмём для примера миграцию онлайн-магазина «Шайба». В монолитной системе пять функциональных областей, а между ними такие зависимости:
Корзина запрашивает данные у каталога товаров и системы обработки платежей.
Профиль пользователя обращается к корзине, системе обработки платежей и управлению заказами.
Обработка платежей обращается к управлению заказами.
Управление заказами обращается к каталогу товаров.
Каталог товаров не запрашивает данные у остальных систем, но отвечает на запросы.
Допустим, команда собирается выделить каталог товаров в отдельный сервис. После отключения монолитного каталога корзине и управлению заказами придётся взаимодействовать с микросервисом. Значит, нужен ACL.
Команда начинает писать сервис каталога и параллельно внедряет ACL. Когда сервис выкатят в продакшен, трафик переключат.
⬅️ ACL выводят из эксплуатации, когда все зависимые сервисы перенесли в архитектуру микросервисов.
В случае «Шайбы» ACL будет работать на протяжении всей миграции. До тех пор, пока не отключат последний монолитный компонент. Если бы в монолите была функциональность, которая работает автономно, ACL можно было бы отключить раньше.
Ещё возможен такой сценарий. Допустим, в монолите остаётся последний кусок функциональности — всё остальное уже вынесли в микросервисы. Тогда с монолитной системой можно общаться напрямую, через маршрутизацию. Фактически она превращается в микросервис.
Как и любой другой архитектурный паттерн, ACL — это не универсальное решение. Есть ситуации, когда от промежуточного слоя стоит отказаться.
Когда стоит отказаться от ACL
Anti-Corruption Layer находится в тесном симбиозе с паттерном Strangler Fig. Он заточен под миграцию, которая длится долго.
В зависимости от особенностей приложения вам может подойти другой формат перехода. Например, устаревшая система работает настолько плохо, что вам нужно заменить её сразу целиком. Или другой пример — в монолит нужно вносить изменения во время миграции. Такое возможно, к примеру, в банковском приложении. Экономическая обстановка нестабильна — регулятор часто вносит изменения на законодательном уровне, а вам нужно адаптировать к ним приложение.
Для этих примеров паттерн Strangler Fig не подойдёт. ACL не подойдёт тоже, потому что быстро устареет или не оправдает вложений.
В процессе итеративной миграции тоже бывают сценарии, когда ACL вводить не стоит. Таких ситуаций всего пять.
Сергей
Когда используем Strangler Fig без ACL?
1. Прямую интеграцию просто осуществить
В этом сценарии унаследованная система относительно проста и понятна, а ещё у неё чёткие и последовательные модели данных и протоколы. В таком случае добавлять ACL не выгодно. Прямая интеграция будет эффективней, а вы избежите накладных расходов на дополнительный уровень.
2. Вы разрабатываете краткосрочный проект или временное решение
Например, вы делаете быструю проверку концепции. Собираетесь писать сервис корзины, но не знаете, как лучше его реализовать. Рассматриваете две технологии — REST API или управление через события (event-driven подход). На этом этапе вам не нужно делать полноценный ACL, потому что PoC не будет взаимодействовать с монолитной системой. Такой же принцип действует и для временных — костыльных — решений. Разработка и внедрения ACL потребует много ресурсов. Прямая интеграция более практична в краткосрочной перспективе.
Если любая дополнительная задержка может негативно повлиять на работу пользователей или производительность системы, ACL — не лучшее решение. ACL разрабатывают так, чтобы он оказывал минимальное влияния на производительность, но дополнительный уровень абстракции — это всё ещё дополнительный уровень абстракции. Он может создавать задержки. Чтобы удовлетворить высокие требования к производительности, лучше использовать более прямой подход к интеграции.
4. У команды ограниченные ресурсы или нет опыта в создании ACL
Чтобы разработать ACL и управлять этим уровнем, нужны специальные навыки и ресурсы. Если в вашей организации их нет, попытка внедрения может провалиться. Команда получит не тот результат, на который надеялась, и увеличит технический долг.
5. С ACL система станет слишком сложной
Иногда сложность, которую привносит ACL, перевешивает его преимущества. Чрезмерная инженерия может привести к ненужной сложности, а она — к проблемам с обслуживанием. Очень важно найти баланс между потребностью в абстракции и простотой общей архитектуры. Если унаследованные системы небольшие или стабильные, современные и с хорошей документацией, ACL будет избыточным.
Если вы организуете миграцию по паттерну Strangler Fig и ваш кейс не описан выше, вероятно, вам стоит внедрить ACL.
Самое время — попрактиковаться. Перед вами несколько сценариев перехода с монолитной архитектуры на микросервисную. Определите, когда нужно внедрять ACL, а когда стоит обойтись без него.
Рассмотрим другой пример. Теперь из медицинской сферы.
Следующий пример — из сферы телекоммуникаций.
Теперь вы знаете, в каких случаях ACL пригодится, а когда лучше обойтись без него. Переходим к внедрению слоя.
Как внедрить ACL
1. Определите границы и зависимости
Сначала изучите унаследованную систему. Вам нужно понимать, какие бизнес-правила она содержит и какие модели данных и протоколы использует.
Затем определите границы между унаследованной системой и микросервисами. В этой точке нужно выяснить, какие части унаследованной системы будут взаимодействовать с новыми сервисами и должны быть доступны.
После этого определите зависимости между унаследованной системой и микросервисами. К ним относятся общие данные, процессы и функциональные возможности.
2. Разработайте интерфейс ACL
Сначала создайте интерфейс для ACL, который абстрагирует сложности унаследованной системы. Этот интерфейс нужно:
сделать чистым и чётко определённым,
согласовать с требованиями микросервисов, которые вы разрабатываете.
3. Внедрите ACL-компоненты
К ним относятся:
Адаптеры данных — они преобразуют форматы данных и обеспечивают совместимость унаследованной системы и новой.
Шлюзы сервисов — они нужны для управления взаимодействием между старой системой и новыми сервисами. Шлюзы занимаются преобразованием протоколов, маршрутизацией запросов и преобразованием ответов.
Ещё вам нужно инкапсулировать всю сложную бизнес-логику в ACL. Тогда новые микросервисы смогут взаимодействовать с упрощённым и согласованным интерфейсом.
4. Протестируйте ACL
Проведите тщательное интеграционное тестирование, чтобы убедиться, что ACL корректно транслирует данные и протоколы между старой системой и новыми сервисами. Протестируйте различные сценарии для проверки функциональности ACL.
Параллельно с этим проведите тестирование производительности, чтобы убедиться, что ACL не вносит значительных задержек или накладных расходов. При необходимости оптимизируйте компоненты ACL, чтобы поддержать производительность системы.
5. Разверните ACL и внедрите мониторинг
Когда ACL будет готов и протестирован, останется только развернуть его и настроить мониторинг.
Разверните ACL в управляемой среде, первоначально подключив часть микросервисов к унаследованной системе. Расширяйте развёртывание постепенно — по мере роста доверия к ACL.
Внедрите мониторинг для отслеживания производительности и надёжности ACL. Настройте оповещения о любых возникающих проблемах — например, об ошибках трансляции данных или сбоях связи.
API-шлюзы. Kong, NGINX и AWS API Gateway можно использовать для управления и маршрутизации запросов между старой системой и микросервисами.
Инструменты для преобразования данных. Такие технологии, как Apache Camel и MuleSoft, упростят трансформацию данных и преобразование протоколов.
Брокеры сообщений. Брокеры сообщений обеспечивают связь и обмен данными между старой системой и новыми сервисами. Например, можно использовать RabbitMQ, Apache Kafka или AWS SQS.
Service Mesh. Решения Service Mesh, такие как Istio и Linkerd, могут предоставить дополнительные возможности для управления взаимодействиями микросервисов. В том числе — управление трафиком, безопасность и наблюдаемость.
Настраиваемое промежуточное ПО. Можно самостоятельно разработать пользовательское промежуточное ПО с использованием языков программирования и фреймворков. Например, использовать Java с Spring Boot и Node.js. Такой вариант поможет обеспечить индивидуальные решения для конкретных требований ACL.
Итак, Anti-Corruption Layer — это паттерн, который помогает обезопасить взаимодействие между новой системой и устаревшей. В задачи паттерна входит маршрутизация запросов от старой системы к новой. Чтобы реализовать ACL, нужно использовать инструменты маршрутизации.
Паттерн мы рассмотрели. Теперь кратко опишем роль маршрутизации и её инструменты для микросервисной архитектуры.
Маршрутизация в микросервисах
📎 Маршрутизация — это способы управления и направления потока трафика между различными частями системы.
Эти технологии очень важны во время миграции. С помощью них вы направляете запросы от пользователей или других служб в соответствующие внутренние системы. Не важно, относятся эти системы к монолиту или к микросервисам.
Польза маршрутизации в период миграции
В процессе перехода от монолитной архитектуры к микросервисной нужно выбрать эффективные стратегии маршрутизации. Это важно, потому что только подходящие решения смогут гарантировать вам:
Безболезненное взаимодействие с пользователями. Маршрутизация может обеспечить минимальные перебои в работе пользователей и стабильную производительность, даже если вы заменяете часть системы или обновляете её.
Непрерывность работы. Она позволяет старой и новой системам сосуществовать и работать одновременно. Это способствует плавному и постепенному процессу миграции.
Инкрементное развёртывание. Поддерживает поэтапное развёртывание новых функций и услуг. Это позволяет проводить тестирование и проверку в реальной среде.
Управление рисками. Снижает риск полного отказа системы за счёт возможности отката или перенаправления трафика. Вы сможете использовать их, если с новыми сервисами возникнут проблемы.
Маршрутизация может решить множество болей миграции. Но важно понимать, что миграция значительно усложняет систему, из-за чего реализовать маршрутизацию становится труднее. Получается замкнутый круг: маршрутизация может серьёзно помочь, но для этого её нужно так же серьёзно спроектировать и внедрить.
Проблемы маршрутизации в период миграции
Маршрутизация трафика между монолитным приложением и новыми микросервисами сопряжена с рядом проблем, которые нужно решать с особой тщательностью. Среди них:
Сложность управления трафиком:
Множество путей. Управление несколькими путями трафика (как к монолиту, так и к микросервисам) повышает сложность. Необходимо тщательно определить правила маршрутизации и поддерживать их, чтобы обеспечить правильное направление трафика.
Согласованность. Обеспечение согласованности данных и состояния как монолитного компонента, так и микросервиса может стать сложной задачей. Особенно для выполнения операций записи.
Задержка и производительность:
Увеличение задержки. Маршрутизация через дополнительные уровни, такие как обратные прокси или API-шлюзы, может приводить к увеличению задержек. Необходимо оптимизировать эти уровни, чтобы минимизировать влияние на производительность.
Масштабируемость. Инфраструктура маршрутизации должна быть масштабируемой, чтобы справляться с изменяющейся нагрузкой, не превращаясь в узкое место.
Обработка сбоев:
Отказы сервисов. Новые микросервисы могут выйти из строя, а монолит продолжит работу. Чтобы предотвратить каскадные сбои, нужны надёжные механизмы обнаружения и обработки отказов.
Механизмы аварийного восстановления. Очень важно реализовать эффективные механизмы восстановления (fallback mechanisms). С ними вы сможете перенаправить трафик на монолит в случае отказа микросервиса.
Безопасность:
Безопасность данных. Нужно обеспечить безопасную маршрутизацию для конфиденциальных данных, а также последовательное применение политик безопасности. За этим важно следить как в монолитной среде, так и в среде микросервисов.
Управление доступом. Сложно управлять контролем доступа и аутентификацией между старой системой и новыми микросервисами. Этот аспект взаимодействия требует тщательного планирования.
Мониторинг и отладка:
Наглядность. Если вы задействуете много систем и уровней маршрутизации, может быть трудно достигнуть полной видимости потока трафика и быстро выявлять проблемы.
Устранение неполадок. Для отладки проблем в гибридной среде нужны инструменты и процессы, которые позволяют отслеживать запросы в разных компонентах и системах.
Сложностей немало. Чтобы с ними справиться, нужно выбрать подходящие техники маршрутизации.
Техники маршрутизации между монолитом и новыми сервисами
Их всего три:
обратный прокси-сервер,
API-шлюз,
Service Mesh.
Рассмотрим их по порядку.
Обратный прокси
📎 Обратный прокси-сервер (reverse proxy) — это промежуточный сервер, который ретранслирует запросы клиентов из внешней сети на один или несколько серверов внутренней сети.
При миграции из монолита в микросервисы обратный прокси может направлять трафик на монолит или микросервисы. Его настраивают так, чтобы он занимался маршрутизацией всех входящих запросов к нужному внутреннему сервису. Не важно — является сервис частью монолита или микросервиса.
Правила и условия маршрутизации определяют на основе шаблонов URL, заголовков или других атрибутов запроса, которые обозначают назначение трафика.
Чаще всего обратный прокси реализуют с помощью Nginx, HAProxy или Apache HTTP Server.
У обратного прокси такие преимущества:
Упрощённая маршрутизация. С помощью обратного прокси вы централизуете логику маршрутизации. Это упрощает управление и обновление в процессе миграции.
Балансировка нагрузки. Обратный прокси распределяет входящий трафик между несколькими экземплярами службы. Это повышает производительность и надёжность.
Безопасность. Он действует как барьер между клиентами и внутренними серверами. Так вы обеспечите дополнительный уровень безопасности.
Кэширование. Можно внедрить кэширование ответов, чтобы снизить нагрузку на внутренние службы и улучшить время отклика.
API-шлюз
📎 По сути шлюз API (Gateway API) — это продвинутая и многофункциональная альтернатива обратному прокси-серверу.
Когда шлюз развёртывают, он начинает обрабатывать все входящие запросы и перенаправлять их на основе заранее определённых правил. Ещё можно определить конфигурацию шлюза. Тогда вы сможете управлять эндпоинтами, применять политики безопасности и преобразовывать запросы или ответы.
К популярным API-шлюзам относятся Kong, Apigee, AWS API Gateway и Zuul.
У API-шлюзов такие преимущества:
Унифицированная точка входа. Шлюз обеспечивает единую, согласованную точку входа для всех сервисов. Это упрощает взаимодействие с клиентами.
Безопасность и аутентификация. Он централизованно управляет системами безопасности, аутентификации и авторизации. Так будет проще обеспечить последовательное применение политик.
Ограничение скорости и дробление. Шлюз контролирует скорость входящих запросов, чтобы защитить внутренние службы от перегрузки.
Аналитика и мониторинг. У этой технологии есть встроенные возможности аналитики и мониторинга для отслеживания шаблонов запросов, производительности и ошибок.
У каждого из перечисленных подходов есть также и недостатки. Например, упрощённая маршрутизация в обратном прокси не даст вам настроить сложные правила маршрутизации на основе данных в запросе. А используя API-шлюз и поставив унифицированную точку входа, мы получим и единую точку отказа.
Обычно команды выбирают между обратным прокси и шлюзом API. Однако эти варианты можно скомбинировать. Третья техника маршрутизации — Service Mesh — представляет собой объединение этих техник в среде Kubernetes. Этот вариант самый сложный для реализации.
Service Mesh вам подойдёт, если вы уже работали с Kubernetes на этапе монолита. Если для вас это новая технология, не советуем внедрять её в процессе миграции. Первичное поднятие и настройка — очень трудоёмкий процесс.
Service Mesh
📎 Service Mesh — это выделенный инфраструктурный уровень для обработки взаимодействия между сервисами в архитектуре микросервисов. Он обеспечивает расширенную маршрутизацию, управление трафиком и возможности наблюдения.
Service Mesh предполагает, что рядом с каждым экземпляром микросервиса развёртывается прокси-сервер Sidecar. Он управляет всеми сетевыми соединениями с микросервисом — координирует запросы к нему и от него.
Есть разные Sidecar-прокси. Например, Envoy и Linkerd. Их развёртывают в рамках одного пода или контейнера. Затем конфигурируют для обработки маршрутизации, балансировки нагрузки, повторных попыток и других сетевых проблем.
Если хотите больше узнать про Service Mesh, вот пара хороших статей на Хабре:
Выберите технику маршрутизации, которая подойдёт под условия проекта.
Крупный сервис осуществляет переход с монолитной архитектуры на микросервисы. В проекте задействованы опытные Kubernetes-администраторы
Service Mesh
Service Mesh работает с Kubernetes. Если в компании есть специалисты, которые могут управлять этим оркестратором, стоит использовать Service Mesh.
Компания часто испытывает неожиданные всплески активности пользователей. Нужно простое и быстрое решение для настройки маршрутизации
Обратный прокси-сервер
Обратный прокси-сервер — это достаточно простая техника. Она позволяет распределять трафик между несколькими экземплярами. С ней можно обеспечить надёжную работу сервиса.
Для компании важна бесперебойная работа и высокая отказоустойчивость. Инженеры по эксплуатации уже настроили работу с контейнерами с помощью Docker Swarm
API-шлюз
Обратный прокси-сервер имеет единую точку входа, а значит — низкую отказоустойчивость. Service Mesh работает вместе с оркестратором Kubernetes, а компания использует Docker Swarm — данная техника маршрутизации не подойдёт. В таких условиях лучше использовать API-шлюз.
Итоги
Если вы проводите миграцию по паттерну Strangler Fig, унаследованная система продолжит работать и будет обмениваться данными с микросервисами. Чтобы проблемы монолита не затронули новые системы, нужно использовать паттерн Anti-Corruption Layer (ACL).
ACL («слой, который предотвращает повреждение данных») помогает создать границу между новой системой и унаследованной. Он:
Изолирует микросервисы от сложностей и проблем унаследованной системы.
Управляет маршрутизацией запросов между монолитом и микросервисами.
Адаптирует данные под требования разных систем.
Инкапсулирует монолитную систему.
ACL переводит запросы и ответы унаследованной системы и микросервисов через адаптер, чтобы преобразовать формат и семантику сообщения под требования получателя.
ACL внедряют, как только команда начинает разработку микросервиса, которому нужно взаимодействовать с монолитом. Слой убирают, когда все зависимые сервисы монолита перенесли в архитектуру микросервисов.
Anti-Corruption Layer заточен под миграцию, которая длится долго. Если вы не используете паттерн Strangler Fig, ACL вам не нужен. При итеративной миграции есть пять сценариев, когда от него стоит отказаться:
Прямую интеграцию просто осуществить.
Вы разрабатываете краткосрочный проект или временное решение.
У команды ограниченные ресурсы или нет опыта в создании ACL.
С ACL система станет слишком сложной.
Ещё для микросервисной архитектуры важна маршрутизация. Как в процессе миграции — в составе паттерна ACL, — так и в целом для перенаправления трафика от клиента на нужный микросервис.
Есть три техники маршрутизации, которые можно использовать в микросервисной архитектуре:
обратный прокси-сервер,
API-шлюз,
Service Mesh.
Обычно команды выбирают между обратным прокси и шлюзом API. Service Mesh — это более сложный вариант, который развёртывается в среде Kubernetes. Подходит для команд, которые уже знакомы с этой технологией.