И вот настал тот день, когда я наконец соизволил встать с дивана и дописать следующую статью о микросервисах. Кто не в теме - в прошлой части мы выяснили, как сильно неправильная пунктуация и тупые приколы могут раздражать. Ну и немного обсудили, что такое микросервисы и зачем они вообще нужны. Не будем отходить от трендов и в этой части, продолжим погружаться в этот дивный мир машинного перевода, шуточек за 300 и микросервисов.
Глобально существует два способа перехода на новую архитектуру: либо мы делаем все за раз, либо по частям. Первый способ выглядит очень неплохо на бумаге: составляем структуру будущей микросервисной архитектуры, делимся на команды, закрываем разработку новых фич и полностью переключаемся на миграцию. Получается очень круто, модно и молодежно: один могучий потуг — и штаны стали теплыми система уже на микросервисах. Но где же в этом чудном плане хранится подвох? Давайте попробуем разобраться.
Сложность в оценке продолжительности работы. Из-за множества подводных камней и непредвиденных факторов точно оценить сроки переезда на новую архитектуру будет очень проблематично. Соответственно переезд может затянуться на неопределенный срок.
Сложность коллаборации большого количества программистов. Одной из причин перехода на микросервисы может быть сильно возросший штат на проекте. Как следствие сложность коллаборации и внедрения новых технологий (блокировки MR, деплой на каждый чих и т.д.). Даже если мы правильно разбили коллектив - резать всё за раз будет похоже на басню "Лебедь, рак и щука". Множество merge request'ов, перекрывающихся задач и сбоев могут сильно замедлить работу
Риск забросить. Маловероятно, но если все затянется очень сильно и не будет виден какой-то результат, лавочку могут прикрыть.
Остановка новых фич. Внедрение новых возможностей будет заблокировано на неопределенный срок. Это риск потерять пользователей и клиентов. Бизнес не может позволить себе паузу на месяцы или даже годы ради перехода на новую архитектуру. Убытки растут, а к миграции добавляются еще и финансовые проблемы. С другой стороны, в случае неудачи это будет шикарной возможностью найти себя на другом проекте, ну или открыть гусиную ферму
С другой стороны подход "по частям" гораздо более жизнеспособный. Суть его, как понятно из названия, заключается в поэтапной миграции. Вместо того, чтобы ломать систему целиком, вы постепенно выделяете отдельные компоненты и превращаете их в микросервисы. Остается дело за малым - определить приоритеты и те самые компоненты для микросервизации.
Мы, конечно же, можем как всегда кинуть монетку и случайно выбрать кусок кода для вынесения его в новую архитектуру. План, конечно, хорош но лучше подстраховаться и рассмотреть еще несколько способов. Итак, куда направить свой зоркий взгляд?
Область, где чаще всего происходит изменение кода. Миграция кода где изменения никогда не требуются - идея крутая, но не жизнеспособна. Зачем делать приоритет на то, что никогда не меняется и прекрасно работает. Нужно мыслить наоборот и смотреть на ту часть системы, которая постоянно дорабатывается и обновляется. Чем чаще происходят изменения, тем больше проблем вызывает процесс обновления всего монолита. Выделив эту часть в микросервис, можно упростить разработку и мердж реквесты, сократить частоту деплоя и
сохранитьсократить количество багов. Теперь данный участок будет независимо деплоиться и обновляться.Область, требующая наибольшей масштабируемости. Если есть участки системы, на которые приходится основная нагрузка - имеет смысл вынести их в первую очередь. Это улучшит масштабируемость и повысит отказоустойчивость. Также это позволит сократить нагрузку на основной сервер. При необходимости можно купить несколько небольших серверов и разбить нагрузку между ними через Load Balancer. При монолите это также возможно - но цена вопроса существенно дороже. Да и технически это существенно сложнее.
Область с наименьшим техническим долгом. Также начинать миграцию можно с тех компонентов, где наименьшее количество "костылей". Это позволит сократить количество нервных клеток при переходе на новую архитектуру.
Из плюсов данного подхода можно выделить
Нет жесткого дедлайна: переход можно проводить постепенно, не торопясь и не выжигая все ресурсы команды. Работа продолжается в нормальном режиме.
Видимый прогресс: каждый успешно мигрированный компонент — это ощутимый результат для команды и бизнеса.
Бизнес не страдает: поскольку процесс миграции идет параллельно с разработкой новых функций, бизнес продолжает развиваться и платить вам денежку.
Процесс миграции
Слышали ли вы что-либо об strangler fig? Звучит как название крутого блокбастера но на самом деле это вид тропических и субтропических растений, которых объединяет специфический «душащий» образ жизни. Если интересны детали - фикусы-душители. По аналогии с таким поведением Мартин Фаулер (Martin Fowler) создал шаблон программирования strangler pattern. Суть его проста - мы "обвиваем" старый код и начинаем выносить из него куски. Рассмотрим детальнее:
Для начала необходимо создать фасад для пользователей с целью перенаправления запросов на новые микросервисы.
Далее определяем область с наивысшим приоритетом и выносим данный функционал в отдельный микросервис.
Перенаправляем запросы из вынесеной области в новый блок кода. При этом старый участок удалять не рекомендуется:
Процесс переноса может иметь новые баги. Процесс починки займет какое-то время а сервис должен работать.
Всегда хорошо иметь возможность вернуть все как было без существенных усилий
Повторяем процесс.
По итогу полностью переходим на новую архитектуру. Profit.
Советы
Оставить стек без изменений. Если у вас была реляционная база дынных - оставьте ее. Использовали java? Во-первых - мое уважение, а во вторых - продолжаем также делать до полного перехода на микросервисы. В противном случае рискуете создать себе несколько неожиданных проблем. Помните золотое правило: "Работает - не трогай".
Не спешите рефакторить. Сначала полностью перенесите всю архитектуру иначе рискуете откусить больше чем проглотить. Причины все те же.
Чем больше тестов - тем лучше. Очень важно понимать, что в процессе переноса мы не создали новых багов и полностью совместимы с другими частями приложения.
Определить API. Заранее продуманные интерфейсы между микросервисами помогут избежать путаницы и сбоев при взаимодействии компонентов. Семь раз отмерь - один отрежь.
Изолировать компонент: Все внутренние зависимости должны быть вынесены из кода, чтобы каждый микросервис мог работать независимо от других частей системы. Другими словами - микросервис должен быть на столько обособленным на сколько это возможно.
На этом, пожалуй, все. Пишите комментарии - всегда интересно почитать на сколько я тупой и вообще все что написано - ересь. Ну а в следующей части мы поговорим о базах данных в микросервисах.