«Наши компьютеры созданы так же, как и наши города: давно, без планов и на руинах прошлого».
Эллен Уллман написал это в 1998 году , но именно так мы создаем современные приложения сегодня: на долгое время, имея только краткосрочные планы и поверх устаревшего программного обеспечения.
В этой статье мы рассмотрим несколько шаблонов и инструментов, которые, по нашему мнению, хорошо подходят для продуманной модернизации устаревших приложений и создания современных.
системы, управляемые событиями .
Модернизация приложений в контексте
Модернизация приложения — это когда вы берете устаревшее приложение и модернизируете его инфраструктуру (то есть внутреннюю архитектуру), чтобы ускорить расширение его функциональности, повысить производительность и масштабируемость, включить новые варианты использования и т. д. К счастью, все виды модернизации и миграции приложений уже давно хорошо классифицированы, как показано на рис.1.
Рис.
1: Три типа модернизации и технологии, которые можно для этого использовать.
Существует несколько уровней обновлений, которые можно применять в зависимости от ваших потребностей и готовности к изменениям:
- Не трогать (удержание).
Это самый простой вариант, он имеет смысл, если необходимость модернизации не столь остра.
- Вывод из эксплуатации (выход на пенсию).
- Рехостинг .
Обычно это означает принятие приложения «как есть» и его повторное развертывание в новой инфраструктуре, например в облаке или платформе.
Кубернетес используя что-то вроде KubeVirt. Это хороший вариант, если ваше приложение не может быть помещено в контейнер, но вы хотите использовать свои навыки работы с Kubernetes, лучшие практики и новые возможности инфраструктуры для управлять виртуальными машинами как контейнерами .
- Реплатформинг .
Это тот случай, когда просто перейти на новую инфраструктуру недостаточно и хочется немного изменить внешнюю часть приложения, не затрагивая его архитектуру.
Например, изменив способ настройки приложения, чтобы его можно было помещать в контейнер, или переключиться со старой Java EE на современную среду выполнения с открытым исходным кодом.
Здесь вы можете использовать такой инструмент, как заводиться , который проанализирует вашу заявку и выдаст отчет, что необходимо сделать.
- Рефакторинг .
Сегодня модернизация приложений — это в основном перенос монолитных локальных приложений в облако.
микросервис архитектура для ускорения релизов.
В этом случае вам потребуется провести рефакторинг и перепроектировать архитектуру приложения.
Именно эти вопросы мы сегодня и рассмотрим.
Однако подходы, обсуждаемые ниже, можно использовать и в других сценариях, например при миграции в облако.
Ключевые проблемы при миграции монолитных устаревших приложений
Во-первых, это необходимость выпуска новых версий с необходимой периодичностью.Проблема номер два — масштабирование разработки, чтобы больше разработчиков и команд работали над общей базой кода, не наступая друг другу на ногу.
Масштабирование приложения для надежной обработки растущих рабочих нагрузок — задача номер три.
С другой стороны, преимущества модернизации включают ускорение вывода продукта на рынок, повышение автономности команды при работе с базой кода и динамическое масштабирование для эффективного реагирования на изменения рабочей нагрузки.
Каждое из этих преимуществ компенсирует усилия, необходимые для модернизации приложения.
На рис.
2 показан пример инфраструктуры, которая позволяет устаревшему приложению масштабироваться по мере увеличения нагрузки.
Рис.
2. Рефакторинг устаревшего приложения в микросервисы, управляемые событиями.
Постановка конечных целей и мониторинг прогресса в их достижении
В нашем случае конечной целью является архитектурный стиль, который следует принципам микросервисов и использует технологии с открытым исходным кодом, такие как Kubernetes. Апач Кафка И Дебезий .Результатом модернизации должны стать независимо развертываемые сервисы, смоделированные в бизнес-сфере.
Каждая служба должна владеть собственными данными, генерировать собственные события и т. д. Планируя модернизацию, важно подумать о том, как мы будем измерять прогресс наших усилий.
Для этого вы можете использовать такие индикаторы, как время выполнения изменений (время, необходимое для ввода нового коммита в рабочую среду), частота развертывания релизов, время восстановления, количество одновременно работающих пользователей и т. д. Ниже мы рассмотрим три шаблона проектирования и три технологии с открытым исходным кодом (Kubernetes, Apache Kafka и Debezium), которые можно использовать для преобразования производственного монолитного приложения в современную систему, основанную на службах, управляемых событиями.
И начнём мы с шаблона под названием Strangler, что на русский язык переводится как «душитель».
Шаблон душителя
Этот шаблон является наиболее популярным методом миграции приложений.Его представил и был популяризирован Мартином Фаулером, которого в Австралии впечатлил фикус-душитель.
Семена этих растений попадают в крону дерева и дают начало побегам, которые затем растут вниз, укореняются в почве и постепенно задушают давшее им приют дерево.
При чем тут миграция приложений? Несмотря на то, что наши сервисы тоже изначально построены таким образом, чтобы обертывать устаревшую систему.
Некоторое время старая и новая системы будут сосуществовать, затем новая вырастет и полностью заменит старую.
Основные компоненты паттерна Strangler при миграции устаревшего приложения показаны на рисунке.
3.
Рис.
3. Шаблон «душитель» для миграции устаревших приложений.
Основным преимуществом паттерна Strangler является возможность постепенного перехода от устаревшей системы к новой с низким уровнем риска.
Теперь давайте разобьем этот шаблон на ключевые этапы.
Шаг 1: Определение функциональных границ
Самый первый вопрос – с чего начать миграцию.Здесь вы можете использовать доменно-ориентированный дизайн определить агрегаты и ограниченные контексты, каждый из которых представляет собой потенциальную единицу декомпозиции и потенциальную границу для микросервисов.
Или вы можете использовать технику штурм событий , созданный Антонио Брандолини, чтобы получить общее представление о модели предметной области.
Еще один важный момент — как эти модели взаимодействуют с базой данных, и какая работа требуется для декомпозиции базы данных.
Ответив на эти вопросы, вы можете перейти к определению связей и зависимостей между ограниченными контекстами, чтобы оценить, насколько сложно будет их извлечь из старого приложения.
Вооружившись этой информацией, вы можете перейти к следующему вопросу: с какого сервиса начать? От чего меньше всего зависимостей, чтобы быстрее получить первый результат или, наоборот, взять на себя самую сложную часть системы? Наш совет: начните с самой типичной услуги, которая похожа на многие другие.
Это поможет, во-первых, построить правильную технологическую основу, а во-вторых, послужит основой для оценки и миграции других модулей.
Шаг 2. Миграция функциональности
Чтобы шаблон Strangler работал, нам необходимо четко сопоставить входящие запросы с тем функционалом, который мы хотим передать.Также нам нужна возможность перенаправлять эти запросы на наш новый сервис (и обратно, если необходимо).
В зависимости от состояния устаревшего приложения, клиентских приложений и других факторов оценка возможных вариантов такого перехвата может быть как простой, так и очень сложной:
- Самый простой вариант — изменить клиентское приложение и перенаправить входящие запросы на новый сервис.
- Если устаревшее приложение работает через HTTP, это очень хорошо.
HTTP легко перенаправить, и у нас есть широкий выбор всевозможных прозрачных прокси.
- Однако на практике приложение, скорее всего, будет использовать не только REST API, но также SOAP, FTP, RPC или некоторые традиционные конечные точки обмена сообщениями.
В этом случае вам может потребоваться написать свой собственный уровень трансляции протокола, используя что-то вроде Апач Верблюд .
Создавая собственный уровень трансляции протоколов, который будет использоваться сразу несколькими сервисами, мы рискуем реализовать слишком много интеллекта на уровне общего прокси для всех этих сервисов.
А это противоречит принципу» умные микросервисы, тупые конвейеры "Поэтому лучше всего использовать Шаблон коляски , как показано на рис.
4.
Рис.
4: Шаблон коляски.
Поэтому мы не размещаем нашу собственную логику прокси на общем уровне, а делаем ее частью сервиса.
При этом мы не встраиваем этот прокси в сам сервис на этапе компиляции, а используем Шаблон боковой панели Kubernetes и привязать прокси к сервису уже на этапе исполнения.
При этом старые клиенты используют транслятор прокси-протоколов, а новые клиенты работают через API нашего нового сервиса.
Прокси транслирует звонки и направляет их на наш новый сервис, что позволяет при необходимости повторно использовать этот прокси.
Что еще более важно, как только прокси-сервер больше не понадобится устаревшим клиентам, мы сможем легко вывести его из эксплуатации с минимальным влиянием на новые сервисы.
Шаг 3. Миграция базы данных
Определившись с функциональными границами и перехватом запросов, пришло время решить, как мы будем задушить базу данных , то есть отделить устаревшую базу данных от служб приложений.Здесь есть несколько подходов.
Подход к базе данных
Здесь мы начнем с секционирования схемы данных, которое потенциально может повлиять на устаревшее приложение.Например, для SELECT может потребоваться получение данных из двух баз данных, а для UPDATE — распределенные транзакции.
Подход на уровне базы данных требует модификации кода приложения и не помогает быстро получить первые результаты.
Поэтому это не наш случай.
Подход на уровне кода
Такой подход позволяет быстро перейти к независимо развернутым сервисам и повторно использовать устаревшую базу данных, но сопряжен с риском создания ложного ощущения прогресса.Разделение базы данных может оказаться сложной задачей и вызвать проблемы с производительностью в будущем.
Но это шаг в правильном направлении, который помогает прояснить принадлежность данных и то, что именно необходимо совместно использовать на уровне базы данных.
Подход как на уровне базы данных, так и на уровне кода
Может быть сложно одновременно начать работать и над кодом, и над базой данных, но в конечном итоге это конечный результат, которого мы хотим достичь.Не важно как, но в итоге мы хотим получить отдельные сервисы и базу данных.
Если мы изначально учтем это, то в будущем нам не понадобится рефакторинг.
Наличие двух отдельных баз данных требует синхронизации данных.
И здесь мы снова можем выбрать один из нескольких стандартных технологических подходов.
Триггеры
Большинство баз данных позволяют настраивать свое поведение при изменении данных.Более того, это может быть даже вызов веб-сервиса или интеграция с другой системой.
Но реализация триггеров и то, что с ними можно делать, сильно различаются в зависимости от СУБД.
Еще одним существенным недостатком триггеров является то, что их использование требует изменения устаревшей базы данных, что не всегда приемлемо.
Запросы
Вы можете регулярно проверять исходную базу данных на наличие изменений с помощью запросов.Для обнаружения изменений обычно используются стратегии реализации, такие как временные метки, номера версий или изменения столбцов состояния в исходной базе данных.
Независимо от выбранной стратегии всегда возникает дилемма: часто опрашивать и создавать дополнительную нагрузку на исходную базу данных, или опрашивать редко, но рисковать пропускать обновления, если они выполняются часто.
Хотя запросы легко настроить и реализовать, этот подход имеет существенные ограничения.
Поэтому он не подходит для критически важных приложений, которые часто взаимодействуют с базой данных.
Анализаторы журналов
Анализаторы журналов обнаруживают изменения путем сканирования файлов журнала транзакций базы данных.Эти файлы предназначены для резервного копирования и восстановления баз данных и надежно записывают все изменения, включая УДАЛЕНИЕ.
Использование анализаторов журналов — наиболее беспроблемный вариант, поскольку нет необходимости модифицировать исходную базу данных и нет накладных расходов в виде дополнительных запросов.
Основным недостатком такого подхода является отсутствие единого стандарта для файлов журналов транзакций, поэтому для их обработки потребуются специализированные инструменты.
Вот тут-то и пригодится Дебезиум.
Прежде чем перейти к следующему шагу, давайте посмотрим, как Debezium работает с анализом журналов.
Дебезиум и отслеживание изменений данных
Когда приложение записывает данные в базу данных, изменения сначала записываются в журнал, а только потом обновляются в таблицах базы данных.В MySQL файл журнала называется binlog, в PostgreSQL — write-ahead-log, в MongoDB — op. К счастью, в Debezium есть коннекторы для различных баз данных, что избавляет нас от необходимости иметь дело с форматами журналов.
Debezium может читать журналы и создавать общие абстрактные события в системе обмена сообщениями, такой как Apache Kafka, которые содержат изменения данных.
На рис.
5 показаны коннекторы Debezium как интерфейсы к различным базам данных.
Рис.
5: Коннекторы Debezium в микросервисной архитектуре.
Debezium — наиболее широко используемый инструмент CDC (сбор данных изменений) с открытым исходным кодом, который благодаря много разъемов и обширный функционал отлично подходит для модернизации методом Душителя.
Почему Дебезиум хорошо подходит для Душителя?
Одной из ключевых причин миграции устаревших монолитных приложений с использованием шаблона Strangler является снижение риска и возможность всегда вернуться к исходному устаревшему приложению.Debezium хорошо вписывается в эту схему, поскольку он полностью прозрачен для устаревшего приложения и не требует каких-либо изменений в устаревшей модели данных.
Пример использования Debezium в микросервисной архитектуре показан на рис.
6.
Рис.
6: Использование Debezium в гибридном облаке.
При минимальной дополнительной настройке старой базы данных можно организовать сбор всех необходимых данных.
Соответственно, при необходимости мы всегда можем удалить Дебезиум из системы и вернуться к исходному устаревшему приложению.
Функциональность Debezium для миграции устаревших приложений
Давайте кратко рассмотрим некоторые функциональные возможности Debezium, которые пригодятся при миграции монолитного устаревшего приложения с использованием шаблона Strangler:- Снимки.
Debezium может сделать снимок текущего состояния исходной базы данных, который затем можно использовать для массового импорта данных.
Как только снимок будет сделан, Debezium начнет потоковую передачу изменений, чтобы синхронизировать целевую систему.
- Фильтры.
Debezium позволяет вам выбирать, из каких баз данных, таблиц и столбцов отправлять изменения, что очень полезно, поскольку с помощью шаблона Strangler мы не перемещаем все приложение.
- Функция преобразования одного сообщения (SMT) – может использоваться в качестве дополнительного уровня защиты данных от повреждения и защищает нашу новую модель данных от устаревших имен, форматов данных и даже позволяет нам отфильтровывать устаревшие данные.
- Использование Debezium в сочетании с реестром схем, например.
Иногда это может помочь предотвратить негативное влияние изменений в исходной базе данных на потребителей новых сообщений.
- Использование Дебезиума с Apache Kafka – эти два инструмента прекрасно дополняют друг друга при миграции и модернизации приложений.
Вот лишь некоторые преимущества их совместного использования: гарантированное упорядочение изменений в базе данных, сжатие сообщений, возможность перечитывания изменений столько раз, сколько необходимо, отслеживание смещений в журналах.
Шаг 4. Сервисные релизы
Итак, после краткого обзора Дебезиума, вернемся к работе над шаблоном Strangler. Предположим, что мы уже сделали следующие вещи:- Были определены функциональные границы.
- Функционал перенесен.
- База данных перенесена.
- Развернутые сервисы в среде Kubernetes.
- Перенес данные с помощью Debezium и оставил его включенным для синхронизации текущих изменений.
В зависимости от возможностей нашего уровня маршрутизации мы можем использовать такие методы, как темный запуск, параллельное выполнение или канареечное развертывание, чтобы уменьшить или устранить риск при развертывании новых сервисов, как показано на рисунке 1.7.
Рис.
7: В новую службу поступает только трафик чтения.
Поэтому все, что нам нужно сделать, это убедиться, что запросы на чтение изначально отправляются в наш новый сервис, а запросы на запись по-прежнему отправляются в устаревшую систему.
Это необходимое условие, поскольку пока мы тиражируем изменения только в одном направлении – от старой системы к новой.
Убедившись, что чтение работает без проблем, можно начинать отправлять трафик записи в новый сервис.
Если на этом этапе по какой-то причине нам все еще нужно, чтобы устаревшее приложение работало, то нам необходимо выполнить потоковую передачу изменений из новых сервисов в базу данных устаревшего приложения.
Затем, когда устаревшее приложение больше не понадобится, вам нужно будет прекратить запись или изменение данных в нем, а также прекратить репликацию данных из него.
Описанная здесь фаза паттерна «Душитель» проиллюстрирована на рис.
8.
Рис.
8: Новая служба потребляет трафик чтения и записи.
Поскольку устаревшее приложение по-прежнему используется для чтения данных, мы продолжаем реплицировать в него данные из нового сервиса.
Со временем мы прекратим все операции с устаревшим модулем и остановим репликацию данных, после чего модуль может быть выведен из эксплуатации.
Заключение
На данный момент мы глубоко углубились в использование шаблона Strangler для миграции монолитного устаревшего приложения, но еще не закончили модернизацию нашей микросервисной архитектуры.В следующей и заключительной части мы рассмотрим некоторые распространенные проблемы, которые возникают позже в процессе модернизации, а также то, как Debezium, Apache Kafka и Kubernetes могут помочь с этой проблемой.
Теги: #Виртуализация #Управление разработкой #ИТ-инфраструктура #открытый исходный код #Kubernetes #kafka #Apache #Red Hat #Debezium
-
Индустриальная Психология
19 Oct, 24 -
Мега Сити
19 Oct, 24 -
Ужесточение Typescript. Отчет Яндекса
19 Oct, 24 -
Своё Облако В 10-15 Раз Дешевле Amazon Ec2
19 Oct, 24 -
Китайский Файрвол Как Торговый Барьер
19 Oct, 24 -
Давайте Поиграем В Городах
19 Oct, 24 -
Миранда Для Любителей Музыки
19 Oct, 24