Как стать автором
Обновить

Комментарии 44

tldr:
Усилия моей команды по возвращению микросервисов в монолит благоприятно сказались на расходах компании.

Попробую резюмировать.


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

Изначально был выбран неверный критерий разбивки монолита на микросервисы. Сам автор это признает.


По мере миграции команд на современную платформу сервисы, за которые отвечали эти команды, приходится передавать остающимся legacy-командам.

Не самый рациональный подход к миграции, когда не во время, а уже после после перехода на новую платформу надо все равно поддерживать старую.


Микросервисы — это не «микро». У них «правильный размер»

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


большинству технологий не требуется «независимое масштабирование»

Я несколько раз перечитал этот раздел, и вроде начало написано там правильно, а выводы — неверные. Такое ощущение, что они еще сами не до конца отрефлексировали, что причина их бед не в том, что независимое масштабирование нужно не везде (с этим сложно спорить), а в том, что они этого не поняли изначально. Т.е. они представляют свое непонимание технологии как ее недостаток.


Вот и весь рассказ. История одного конкретно взятого провала проектирования архитектуры и тех, кто за это отвечал. Зачем лить столько "воды" про Таноса и гордость за команду? Мне кажется, вместо Таноса тут больше бы подошла отсылка к фильму "Идиократия".

Про «Идиократию» в точку. Хотя у меня лично пословица вспоминается: Научи дурака богу молится — он себе лоб расшибет. Тобишь будет делать неправильно.

Поддержу про словоблудие. А ещё похоже на «переливание из пустого в порожнее» — как ещё оправдать наличие большой команды разработки, как сначала не разбивая монолит на микросервисы, а потом, напротив, сливая из нескольких «микро»сервисов один большой? Аргумент про репозитории вообще убил — при правильно организованных процессах вообще без разницы — 100500 репозиториев или монорепозиторий.
Вообще удивительно как авторы изначального поста «эффективно» работают.
Предполагаю, что все-таки проблема в другом и действительно на изначальном этапе MSA была неверно понята и, соответственно, вместо кучи микросервисов был получен «распределённый монолит», а теперь это рефакторят так, что реальность соответствовала факту )

Неужели реально где-то есть взрослые люди, которые воспринимают технические термины буквально?

А вы сомневаетесь? Даже антипаттерн такой придумали — «распределенный монолит». Сейчас с таким работаю — это большая боль в прикручивании новых фич и поддержки существующих.
Я бы не был столь резок в оценках. Да, очевидно, ребята изначально допустили ошибки в проектировании. Важно то что они признали их и смогли как минимум начать их исправлять. Поверьте, есть немало компаний, которые в период хайпа сделали свои «распределенные монолиты» с «микро»сервисным подходом, не задумываясь о границах контекста. И они до сих пор продолжают мучиться с их развитием, упорно не желая признавать ошибок проектирования.

Причина резкости оценок очень проста, и вы ее правильно указали. Вместо того, чтобы открыто и честно признать свои ошибки, написав статью в духе "Как не надо переходить на микросервисы" или "В каких случаях использование микросервисов не оправдано", чуваки наводят тень на плетень. Они пишут, что криво сделанные микросервисы хуже монолита, делая негативный акцент на микросервисах. А мне кажется, акцент надо делать на то, что они были криво сделаны. Криво сделанное что угодно хуже, чем нормально сделанное что-то другое.

Я бы не был столь резок в оценках

А как по-вашему это нормально, когда люди принимающие такие решения — понапроектировали «наносервисы», а потом как эта махина начала трещать по швам — руками помахали, и разбирайся без них.
Кажется это вообще больше не про микросервисы/монолит, а про монорепозиторий/полирепозиторий.
Когда кодом владеет одна небольшая команда, удобнее монорепозиторий. Когда много команд/людей — полирепозиторий.
И из того и из другого можно собирать микросервисы/монолит. И использовать независимое масштабирование. И да, немного платить за это дополнительными метриками и логами, которые могут оказаться полезными.
Часто случается, что разработка на монолите в 2-3 раза дешевле, чем на микросервисах, хотя, конечно, у микросервисной архитектуры есть свои плюсы.
дешевле, приятнее и быстрее. когда к одному сервису обращаются скажем так извне, клиенты которые вообще никак не относятся к данному приложению, т.е. такой настоящий сервис облуживающий абсолютно разные приложения тогда конечно имеет смысл выделять его отдельно.
но если нафигачили кучу мелких сервисов в рамках одного приложения и когда каждый сервис общается только с одним из остальной кучи, еще случается каждый в отдельном контейнере докера, даже если при этом приходится дублировать некоторые данные в базах сервисов либо делать лишнии промежуточные межсэрвисные запросы, и это считается сейчас правильно… хз это либо бред или игры в «ынтерпрайз программиcтоф»

Есть аргументы за такой подход — например, когда есть технические причины вроде необходимости масштабировать каждый компонент отдельно (у них профили нагрузки разные)

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

Ну, мы же БД, которой заведует «микросервис», выносим в отдельную сущность зачем-то? Выносим. А не пытаемся миксовать функцию хранения данных и их обработки. Здесь так же.
Но соглашусь с тем, что определять границы сервисов — это достаточно сложно на самом деле

Лично я от микросервисов как правило получаю 2 огромных преимущества


  1. четко очерченные границы ответственности. Код в монолите имеет тенденцию протекать с самыми супердисциплинированными разработчиками, в микросервисах стена в виде ХТТП надежно защищает модули от взаимного проникновения
  2. АПИ модуля автоматически документируется в сваггере. Опять же супер-диспциплинированная команда наверное могла бы держать документацию в XML комментах и автоматически её собирать/обновлять, но на практике на это очень быстро забиваешь, ведь документацией не пользуешься. А вот сваггер-докой пользуются другие сервисы, общающиеся с этим (чтобы сгенерировать клиент для взаимодействия), поэтому она всегда абсолютно корректна и актуальна.

Ну и то что масштабировать можно кусками а не все приложение — приятный бонус. Так же как и возможность выкинуть сервис и написать другой такой же — берется АПИ, повторяется с новыми внутренностяями, профит. Уже несколько сервисов так переписали, без проблем вышло.


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

НЛО прилетело и опубликовало эту надпись здесь
Кроме прочего не упомянут вот такой трейд-офф:
+ Микросервис полезен тем, что он «бесплатно» даёт тебе протокол взаимодействия (не бесплатно, конечно, но даже самые говнокодеры вынуждены его делать).
— Микросервис плох тем, что внутри монолита правильность передаваемых данных контролируется компиляторами, а в микросервисах — формальный контроль отсутствует, только «глазками». Иногда бывает весьма грустно.

Не понял, где контроль в микросервисах отсутствует. Точно такой же как и в монолите

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

1. Сериализация \ десериализация на разных языках (к этому подталкивают микросервисы) — даёт меньше контроля над «корректностью бинарных данных».
2. Даже на одном языке сериализация данных, а потом их восстановление в общую структуру (возможно в бОльшую) подталкивает к ошибкам уже с логическим представлением данных.

  1. сериализация в JSON совершенно обычное дело. Могут возникнуть сложности с сериализацией ADT и прочих "продвинутых" вещей, но в подавляющем числе случаев никаких проблемн е возникает.
  2. Какая тут ошибка может возникнуть? Deserialize(Seialize(obj)) === obj. Все что мы имеем — оверхед произвоидтельности на то чтобы сделать преобразование. Это может быть проблемой. Но вот корректность-то никак не страдает.
Какая тут ошибка может возникнуть?

Любая. Порядок полей. Тип полей. Ошибки в самом сериализаторе/десериализаторе. Отсутствие схемы, по которой можно проверить данные. Потому что один сервис может пытаться десериализовать одним способом, а второй — другим (но это как раз вроде решаемо теми же устными договоренностями между потребителями и поставщиками сервиса). Я уж не говорю о необходимости проверок корректности данных при передаче (CRC, всякие избыточности и пр)

Порядок полей

Имеет значение только при бинарной сериализации, а я говорю про JSON


Тип полей

Описывается сваггер-схемой


Ошибки в самом сериализаторе/десериализаторе

Ничем не отличается от ошибки в вашем орм/логгере/...


Отсутствие схемы, по которой можно проверить данные.

Не может такого быть. Схема генерируетс из типов автоматически. Вы не можете не указывать типы в типизированном языке.


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

Устные договренности не нужны — есть схема.


Я уж не говорю о необходимости проверок корректности данных при передаче (CRC, всякие избыточности и пр)

https://iota.stackexchange.com/questions/1648/what-is-the-purpose-of-including-extra-crc32-packet-data-in-the-tcp-ip-communica

Какая тут ошибка может возникнуть? Deserialize(Seialize(obj)) === obj.

Где то так:


obj — дата. сериализация и десериализация — на разных серверах. Где настроены разные таймзоны да еще базу данных таймзон забыли на некоторых обновить. Ну просто потому что языки сервисов разные и они не одновременно это делают. В результате один сервер думает, что в Москве летнее время есть, а другой — что его нет. Оригинальный запрос — генерируется где-нибудь внутри бразуера у пользователя во Владивостоке. Ну и так далее.


Особенно весело, если сериализация — xml и для типа используется слишком правильный тип xsd:date. Который, сюрприз, от таймзоны зависит. У него смещение таймзоны есть. И как правильно работать с этим смещением — зависит от фантазии разработчиков библиотеки. В результате сериализуем одну дату на одном узле, а на соседнем, если не повезет, получаем на день меньше или позднее.

obj — дата. сериализация и десериализация — на разных серверах. Где настроены разные таймзоны да еще базу данных таймзон забыли на некоторых обновить. Ну просто потому что языки сервисов разные и они не одновременно это делают. В результате один сервер думает, что в Москве летнее время есть, а другой — что его нет. Оригинальный запрос — генерируется где-нибудь внутри бразуера у пользователя во Владивостоке. Ну и так далее.

Во-первых микросервисы не обязательно предполагают что их будут запускать в разных таймзонах.
Во-вторых не очень понятно как "разные языки делают что-то одновременно". Видимо имелось в виду что в СТД/либах разных япов переход времени может криво быть реализован. Ну, наверное можно, но пока что не встречал таких языков.
Во-третьих такая ситуация достаточно редкая: обычно вещи порядко которых важен генерируют UTC таймстамп, а какое время в данных нам не важно — оно там просто есть какое-то и все. Да и вообще если на то пошло то нужен единый источник времени, а то переведут время на сервере и все.
В-четвертых можно взять библиотеку типа NodaTime, которая по tzdb, имени таймзоны и времени восстанавливает какой там оффсет в это время (поэтому однотипно определяется есть летнее время или нет и т.п.). Кстати, именно этим подходом мы и пользуемся.


Особенно весело, если сериализация — xml и для типа используется слишком правильный тип xsd:date.

Забыл про XML лет 10 назад, чего и вам желаю.

Это все хорошо, но вопрос был, к каким проблемам может проводить Deserialize(Seialize(obj))


Ну вот именно к таким. И надо следить, чтобы они не возникли. Например, не пользоваться XML для формата сериализации даты. JSON, кстати, не сильно лучше — что получится при наивном подходе, если в бразуере, запущенном в таймзоне MSK попытаться сериализовать объект, представляющий сегодняшнюю дату?

А какие проблемы могут возникуть с десериализаций


{"myDate" : "2021-02-03T22:46:33.0640330+03:00"}

в объект ну например типа DateTimeOffset? Нам без разницы, в какой таймзоне что запущено.


И второй вопрос: при чем тут браузер?

Тем что это не дата. А timestamp. Нужно поле с типом даты. Как в "договор заключен 3 февраля 2021 года".


"2021-02-03T22:46:33.0640330+03:00" — передаем это в систему, находящуюся в зоне Владивостока. Десериализуем в локальную переменную. Пытаемся напечатать эту самую дату как дату и видим что?


при чем тут браузер?

В качестве примера одной из реализаций сериализатора-десериализатора.

Тем что это не дата. А timestamp. Нужно поле с типом даты. Как в "договор заключен 3 февраля 2021 года".

В редких случаях когда помимо даты нас интересует ещё где конкретно это сделано передается вот так:


{
   "myDate": {
      "value":"2021-02-03T22:46:33.0640330+03:00",
      "timezone":"Asia/Vladivostok"
   }
}

А дальше


Пытаемся напечатать эту самую дату как дату и видим что?

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

Есть хороший обзор http://seriot.ch/parsing_json.php, здесь были также переводы на русский.

Ну тут всякие эджкейсы и фразы типа "вот этого в стандарте нет, но многие считают это полезным расширением".


Все JSON сериализаторы очень консервативные и используют исключительно кор семантику JSON'а. Никаких комментариев, висячих запятых, странных вложенных [[[[]]]] и так далее.

А я всё же поддержу автора и его размышления о слове «микро», и это ни разу не словоблудие.
Мы, люди, общаемся при помощи слов. Более того, бОльшую часть времени мы мыслим при помощи слов. Слова важны.

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

Не берусь утверждать наверняка, но слово «микро» всё же обычно воспринимается в контексте размера, а не рассуждений о предметной области.
Многие разработчики изначально ограничились осознанием слова «микро» как указанием размера, оттого мы и имеем что имеем. Потребовалось много лет прежде чем до широких масс дошла идея про разбиение сервисов по фрагментам предметной области.

Поэтому, я категорически согласен, термин изначально был выбран не идеально. Но его ведь надо было как то продавать, чтобы затмить предыдущие идеи, вот и раскрутили звучное название.
Недавно смотрел прекрасный TED talk по этой теме с говорящим за себя названием: «How language shapes the way we think».

Нда, прямо наглядный пример как НЕ надо делать.
Вначале


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

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


мы меняем границы сервисов так, чтобы они совпали с границей зоны ответственности нашей команды. А именно, мы возвращаем их в монолит.

Они повторно упрямо пытаются натянуть архитектуру проекта на административную структуру компании.
У них было много сов и глобусов, зато теперь одна большая сова и один большой глобус.
Какие молодцы!

Т.е. у вас даже мысли не возникает, что на самом деле они все делали правильно? И был монолит для магазина. И две команды: одна для каталога, другая для заказов. И они разделили монолит на два сервиса: каталог и заказы. Разве так не могло быть? А теперь у них есть легаси версия из двух сервисов. Но команда на легаси осталась одна и небольшая. И вместо поддержки двух микросервисов, их объединили в один. Вин-вин. То что лично у вас по-другому, не значит что у всех так. Конечно, если бы автор дал больше деталей и примеров, то было бы интереснее. Но автор, наверное, хотел таки похайпить больше, чем принести пользы другим.

теперь у них есть легаси версия из двух сервисов. Но команда на легаси осталась одна и небольшая. И вместо поддержки двух микросервисов, их объединили в один. Вин-вин.

Как объединение двух сервисов в один уменьшает сложность поддержки? Одна команда легко может поддерживать и один сервис, и два сервиса, и 10. Лучше — понятные сервисы, чем сервис, который делает все сразу

Лучше — понятные сервисы

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

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

отдельного инструментария для observability

Поделитесь примером?
не по функционалу, а по командам

Кстати некоторые находят функциональную декомпозицию микросервисов — ошибочной. И я скорее скоро в этом соглашусь — есть негативный опыт.

Как тогда бить?

Если есть возможность пробовать другие методы. Вот читаю сейчас книгу www.piter.com/product/sovershennyy-soft
Там автор предлагает использовать метод декомпозиции основанный на осях нестабильности.

Важные детали:


  • речь только про legacy платформу
  • её отдали на поддержку небольшой команде
  • остальные коллеги пилят современную платформу

В такой ситуации оно вполне имеет смысл.
Если у вас старая версия сайта на битриксе, который распилили на микро, кхм, сервисы, возможно имеет смысл впилить все обратно (и оставить крутиться на паре виртуалок).


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


В целом, много воды и отвлеченных рассуждений.
Автор смотрит на свой, очень узкий случай, и простирает выводы на весь IT мир, в то время, как у него же в компании пилят современную платформу. И там все ОК с микросервисами. Может быть, про современную платформу и надо рассказать.

Текст сложно читать из-за внезапного болда там, где он логически не нужен.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий