Русский
Русский
English
Статистика
Реклама

Модульный монолит

Как быть, когда все советуют растащить проект на микросервисы. А ты не готов

30.06.2020 12:04:28 | Автор: admin
Монолит часто обсуждают в негативном ключе. Но сразу перейти на микросервисы получится не у всех и вот уже не первая команда и компания делятся опытом построения переходного звена: модульной архитектуры. Давайте в деталях посмотрим, как делаются такие проекты.



Недавно я смотрел два доклада на эту тему: от Юлии Николаевой из iSpring и Антона Губарева из Skyeng. Так как с Антоном мы работаем в одной компании, для своего подкаста я решил поговорить с Юлей.



Ниже текстовая расшифровка основных идей из разговора.

Мы взвесили причины, по которым хотели перейти в микросервисы, и настоящие проблемы, которые мешали нам жить в монолитной архитектуре


Юлия: Когда мы начинаем разрабатывать приложение, функционала мало и его нужно запустить как можно быстрее. Но если дело идет, на определенном этапе кодовая база начинает неконтролируемо разрастаться а новых архитектурных решений, которые сдержали бы этот хаос, не принимается.

Это произошло с нашим проектом: он стартовал в 2009-м, но долго не было людей и времени, чтобы бороться с неконтролируемым разрастанием кодовой базы. А к 2018-му стало понятно: пора уже как-то реструктуризировать монолит.

Когда встал вопрос, что делать с нашим монолитом, мы, естественно, тоже рассматривали микросервисы. Но У распределенной архитектуры свои накладные расходы. И мы не были к ней готовы. Например, у нас не было команды девопсов от слова совсем.

Не было как такового нормального CI/CD, не было ни докера, ни кубернетеса вообще ничего такого.


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

Мы поняли: решив острые проблемы, сможем еще какое-то время жить в монолите. Но думали и о том, а как бы сделать так, чтобы потом легче было перейти в микросервисную архитектуру? Наша предметная область дистанционное обучение. И здесь можно выделить модули: геймификация, управление курсами, статистика, отчеты такие подобласти внутри основной предметной области. Мы стали представлять наше приложение как набор независимых модулей.

У нас все усугублялось тем, что кусок легаси написан Symfony 1.4 с использованием Propel 2, который не так просто использовать в парадигме DDD (Domain Driven Design). А нам очень хотелось DDD. Для этого хорошо подходит ORM Doctrine, которую к легаси так просто не прикрутишь.

Мы решили скрестить ужа с ежом и теперь живем с двумя фреймворками.


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


Буквально каждый день, на каждом шагу мы встречали множество вопросов, которые не знали, как решить


Мы, тимлиды, сначала вдвоем, потом втроем разрабатывали функционал в этой новой архитектуре. Было много вопросов. Начиная с того, как организовать папки в проекте: правда, когда сделали и поняли, как и зачем, находили в интернете просто массу источников, в которых все это написано. Наверное, не так искали)

Параллельно часть команды разработчиков ушла в девопсы.


Они занялись переездом в кубернетес, докер и все такое.

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

Да, поначалу тяжело. Но зато когда разработчик распробует и примет новую архитектуру, а ему прилетает фича, которую нужно сделать в легаси, у него сразу возникнет мысль: Как бы мне сделать так, чтобы было похоже на новую архитектуру.

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

На все у нас ушло, наверное, три с половиной месяца.


Мы не просто переделали архитектуру, но и реализовали новый функционал с вынесением частей из легаси. Плюс, все эти три месяца нам команда девопсов настраивала инфраструктуру, чтобы мы смогли взлететь в Kubernetes. Сейчас в новом коде у нас 14-15 контекстов плюс большой легаси, где можно было бы выделить несколько контекстов. Пока в легаси остается большинство контроллеров непонятно было, куда положить их код, потому что контроллеры могут получать и манипулировать данными разных контекстов.

И ура! Мы можем писать фичи в 3-4 потока командой из 12 бэкендеров.


Сергей: В PHP мы не можем дать программисту по рукам и запретить использовать какой-то внутренний класс другого модуля. Это же все держится на устных договоренностях внутри команды. Как это все организовать?


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

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

Мы нашли такую утилиту deptrac статический анализатор кода, который помогает контролировать зависимости.


Утилита встроена в наш CI/CD и запускается автоматически: фактически, большая часть договоренностей контролируется с ее помощью. Логические ошибки стараемся отлавливать еще на архитектурном ревью: это встреча, на которой разработчик, которому предстоит пилить фичу, представляет схемы, где все по слоям уже разделено. Там сразу понятно, что в каком контексте, какие взаимосвязи и т.д.

Сергей: А как такую архитектуру мэйнтэйнить?

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

Сергей: БД у нас одна, проект у нас один. Что мне делать, если в моем модуле нужны данные из нескольких других контекстов?

Юлия: Это один из самых сложных вопросов наверное, как в модульной, так и в микросервисной архитектуре. Мы пытались в одном из случаев реализовать объединение данных из разных API: сделали запросы, объединение в памяти, сортировку, фильтрацию. Работало жутко медленно.

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

Сергей: И здесь мы подходим к проблеме с дублированием кода...

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

Сергей: А что делать, когда одному модулю нужно выполнить действие в другом модуле? Например, при оплате изменить баланс, создать уведомление это все разные контексты. Как в монолите быть с этим?

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

Все как в микросервисной архитектуре, грубо говоря.


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

Сергей: Но если приложение постоянно усложняется фичами и контекстами, модульный монолит все равно лишь промежуточный шаг к микросервисам?

Юлия: Да, конечно. Если подразумевается, что приложение будет непрерывно расти, если команды будут расти, это естественно. Например, у нас возникла проблема, что автотесты нереально долго выполняются перед релизом, а если что-то отвалится приходится повторно это все запускать.

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

P.S. Больше выпусков подкаста Между скобок с интересными людьми из мира PHP можно найти здесь.
Подробнее..

Без окон, без дверей как мы распилили монолит на сервисы

04.03.2021 12:16:30 | Автор: admin

Пост написан по мотивам доклада Антона Губарева @antgubarev, бывшего тимлида команды Teachers он готов ответить на ваши вопросы в комментариях.

Преподаватели Skyeng не сразу попадают на передовую для начала они проходят отбор и обучение. Направление найма и онбординга преподавателей появилось в 2015 году тогда же был сделан первый коммит в наш (уже бывший) легаси-монолит. Прежняя команда активно его поддерживала и старалась развивать, но в один момент ей стало объективно сложно справляться со всеми проектами. Так появилась моя команда.

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

Наши продукты

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

Исторически сложилось, что для ведения сделок используется внешний Мегаплан, который интегрирован с нашей TRM (Teachers Relations Management, внутри ее еще ласково зовут Tramway) системой, в которой хранятся данные по конкретным преподавателям и которую мы дополнительно используем при поиске учителя по узкому запросу.

Множество процессов и работа сотен людей зависят от этой связки.Множество процессов и работа сотен людей зависят от этой связки.

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

Так онбординг видят кандидаты в преподаватели. Асессоры выставляют свои слоты (время, когда они доступны для проведения уроков), а преподаватели бронируют уроки на время из слотов.Так онбординг видят кандидаты в преподаватели. Асессоры выставляют свои слоты (время, когда они доступны для проведения уроков), а преподаватели бронируют уроки на время из слотов.

Осенью 2019-го компания активно взялась за развитие этих систем, и за 2,5 месяца нам предстояло:

  • реализовать новые фичи. Школа росла: если раньше требовалось 100 преподавателей в месяц, то теперь 1000, и от нас во многом зависело, захлебнется или же выстоит подбор при масштабировании (кстати, те наработки здорово помогли в период карантина, когда многие педагоги решили попробовать онлайн-преподавание);

  • не утонуть в старом коде а значит, отрефакторить хотя бы те части, где рефакторинг назрел давно;

  • отделить свою работу от другой команды.

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

Какие были варианты

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

+

Точно успеем с фичами

Ничего толком не отрефакторим

Продолжим мешать друг другу с другой командой

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

+

Организуем фичи

Разберемся с легаси

Перестанем толкаться со второй командой

С высокой вероятностью не успеем по срокам

Нужно увеличить ресурсы на инфраструктуру: не факт, что их дадут

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

Мы взяли последнюю на тот момент LTS версию Symfony и принялись за работу.

Детали реализации

Структура папок. Все независимые сервисы-продукты мы стали складывать в папку modules. У нас получились выделить такие сервисы:

  • интеграция с Мегапланом;

  • бэкенд календаря тренировочных уроков преподаватель асессор;

  • бэкенд онбординга;

  • и несколько прикладных проектов: работа с очередями, декораторы, http-клиенты, мониторинг, метрики, логирование.

В папке src практически ничего не было только Kernel.php и некоторые совсем общие инфраструктурные вещи.В папке src практически ничего не было только Kernel.php и некоторые совсем общие инфраструктурные вещи.

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

Во всех сервисах независимая конфигурация и полное отсутствие межмодульных use.Во всех сервисах независимая конфигурация и полное отсутствие межмодульных use.

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

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

Конфигурация всех модулей лежит в самих модулях.Конфигурация всех модулей лежит в самих модулях.

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

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

Например, преподаватель записался на тренировочный урок и нам нужно записать это в карточку (она же сделка) в CRM. Модуль онбординга, используя пакет megaplan-client, положит в очередь сообщение, что нужно изменить конкретное поле. Модуль Мегаплана содержит в себе консьюмеры, которые разгребают эту очередь. Работает и в обратную сторону. Мегаплан пошлет нам веб-хук, когда что-то изменилось, мы положим его в сыром виде в очередь, а онбординг эту очередь вычитает и что-то поменяет. Да, тут есть задержка, но она не критична, а данные точно сохранны.

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

Мы замониторили все очереди: смотрим количество консьюмеров, количество сообщений в очередях. Плюс добавили алерты при каких-то аномалиях каждую неделю кто-то из команды назначается дежурным и решает такие проблемы, если они возникают (тьфу-тьфу, случается нечасто).

Также мониторим все http-запросы: пишем в Elasticsearch, смотрим в Kibana.Также мониторим все http-запросы: пишем в Elasticsearch, смотрим в Kibana.

У нас в компании есть общий request-id бандл, разработанный специально для таких целей. Его довольно просто использовать в контексте Symfony: можно либо handler вручную добавить, либо через контейнер сконфигурировать.

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

И если это не описано, то новый разработчик, придя в команду, будет очень долго вникать. Его онбординг будет занимать там, наверное, месяцы. Вот поэтому мы особое внимание уделяем документации, у нас там все время что-то пополняется.

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

Что получилось в итоге

Уже больше года мы живем на продакшене. При этом вышли за сроки буквально на пару недель, но смогли реализовать все фичи (так что у бизнеса претензий не было) и вынесли 2 из 4 сервисов.

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

У нас свои процессы. Мы не зависим от команды, с которой работали вначале. Ввели свой контроль архитектуры: если человек, который получил задачу, видит, что где-то надо что-то менять, он собирает всю команду. Мы исторически работаем распределенно, поэтому записываем встречу в Google Meet и тут же на ней фиксируем решения. А потом прикладываем все записи к задаче можно в любой момент пересмотреть и понять, почему было так.

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

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

P. S. На старте казалось, что будет проще, что возьмем больше и кинем дальше. Но ни я, ни кто-то еще из команды не жалеет, что мы пошли таким путем. Самое главное, что мы смогли отделить свою работу от другой команды, потому что это прям было очень болезненно. И по этому критерию все у нас получилось.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru