Comments 100
Переход на микросервисы — это не просто технический рефакторинг. Это полная смена парадигмы мышления для инженеров, тестировщиков и менеджеров.
Есть одно хорошее правило, как решать описанную в вашей статье проблему: если в вашей архитектуре появилось множество вызывающих друг друга микросервисов, значит, вам пришла пора переходить на монолит. Вы получите массу преимуществ - существенно, в разы увеличите производительность приложения, в разы уменьшите стоимость эксплуатации инфраструктуры, повысите надёжность, упростите отладку, тестирование. Ваши юнит-тесты начнут приносить пользу, а не тупо отрабатывать KPI по проценту покрытия кода, как это обычно в микросервисах. И заплатите вы за это, ну, может быть, несколько большим временем деплоя. Т.е. куча плюсом и крохотный минус.
И заплатите вы за это, ну, может быть, несколько большим временем деплоя
И меньшей способностью к масштабированию
Горизонтально монолит масштабируется так же, как и микросервисы, путём увеличения числа экземпляров. Вертикально нет, но потребность в вертикальном масштабировании с лихвой компенсируется куда более высокой пропускной способностью.
Так никто не говорит что монолит в принципе нельзя масштабировать.Но если у вас микросервисы, то можно масштабировать только ту часть сервиса, на которую растёт нагрузка. А вот нужно ли это конкретному продукту это уже отдельный вопрос.
А в чём профит? В том, что вы не несёте на сервера всю кодовую базу, а всего лишь один сервис? Всего то? Тут всё очень зависит от реализации монолита.
UPD Думаете это стоит того, что бы удорожать разработку в несколько раз?
Во первых разработка не обязательно дорожает в несколько раз. Откуда у вас такие цифры?
А во вторых вы например экономите на железе или там плате за облака.
Для меня порядки цены разработки очевидны - это минимум x3. Более того у меня огромный опыт работы и с тем, и с тем. Когда вы вместо простого вызова функции/метода начинаете городить всё вышеописанное в статье, то вам:
Нужна очень квалифицированная и добросовестная команда; скорее всего их несколько, ибо гонять сообщения/вызовы api самим себе по пять раз за запрос вот вообще смысла нет;
Удорожается отладка - вам нужно делать тестовые стеки из набора связанных микросервисов, потому что их десятки и они связаны; тестировать один сервис отдельно вы можете в самом начале его разработки, ибо потом он обрастает зависимостями и вам нужен будет стек и да, юнит-тесты уже не канают или это моковые монстры; в монолите - запустили инстанс, прогнали функциональные/интеграционные тесты - всё!
Не дай бог вы в качестве дефолтной изоляции для микросервисов используете докер - тут вообще всё плохо ибо это все еще теперь надо билдить и пайплайны будут идти часами. Цена ошибки и внедрения новой фичи в таких случаях очень велика, как и кол-во ресурсов на инфру (оно огромно) ну и конечно эмоции разработчиков! Не забудьте, что билдить надо будет так же и для того, что бы просто запустить интегр. тесты на стеке - а это то время, когда вы не можете работать с исходниками
Если вы не хотите репутационных проблем - вам ОБЯЗАТЕЛЬНО нужно будет делать всё, что описано в этой статье, а это далеко не для новичков;
Все апишки, контракты взаимодействия между сервисами нужно будет описывать и держать их в актуальном состоянии; мультиверсионность - та еще боль! ... я могу продолжать дальше, но работа ждёт)
Я вам так скажу. Раньше, где-то до появления докера (до середины 10ых), такие продукты были только у компаний с огромными нагрузками, изоляциями типо jail (FreeBSD, первая) и LXC (linux, позднее) и инфы про такие системы было мало, ибо это были их конкурентные преимущества, а в отрасли было чёткое понимание того, что когда ты выходиш из общего адресного пространства, да и ещё имеешь нагрузки выше среднего, ты получаешь возможность масштабировать и терминировать эту нагрузку, но тебе нужно будет обеспечивать целостность разделяемых ресурсов между разными окружениями, а это как в многопоточном приложении - самые трудноуловимые ошибки и даже сложнее - в многопоточке у тебя общее адресное пространство и там ты можешь использовать ipc примитивы а в микросервисной - всё гораздо жёсче. Так что как-то так, коллега)
Вы просто пройдитесь по плюсам микросервисов и вам будет всё понятно. Это Архитектурная преждевременная оптимизация по Кнуту.
Для меня порядки цены разработки очевидны - это минимум x3.
А для меня это очень зависит от ситуации. И в некоторых ситуациях микросервисы даже дешевле будут.
Нужна очень квалифицированная и добросовестная команда
Возьмите не квалифицированную и не добросовестную команду и попробуйте написать и поддерживать монолит на миллион строк кода.
Удорожается отладка - вам нужно делать тестовые стеки из набора связанных микросервисов
Вы про моки ничего не слышали?
Не дай бог вы в качестве дефолтной изоляции для микросервисов используете докер
Вообще смешной аргумент. Ну не используйте докер если видите в этом проблему.
Если вы не хотите репутационных проблем - вам ОБЯЗАТЕЛЬНО нужно будет делать всё, что описано в этой статье, а это далеко не для новичков;
Нет, совсем не обязательно делать всё, что описано в этой статье.
Все апишки, контракты взаимодействия между сервисами нужно будет описывать и держать их в актуальном состоянии
Это и в монолите надо делать.
Я вам так скажу. Раньше, где-то до появления докера (до середины 10ых), такие продукты были только у компаний с огромными нагрузками, изоляциями типо jail (FreeBSD, первая) и LXC (linux, позднее) и инфы про такие системы было мало,
Я вам так скажу: микросервисы существуют гораздо дольше. Только их далеко не всегда называли микросервисами :)
А для меня это очень зависит от ситуации. И в некоторых ситуациях микросервисы даже дешевле будут.
Это математически невозможно. Вы простой вызов метода заменяете сетевым взаимодействием.
Возьмите не квалифицированную и не добросовестную команду и попробуйте написать и поддерживать монолит на миллион строк кода.
Для монолита нужны просто программисты. Для микросервисов нужна гораздо более квалифицированная команда, для меня это очевидно. И кол-во строк кода будет в микросервисах гораздо больше, нежели в монолите. Вам нужно будет всё это сетевое взаимодействие выразить в коде.
Вы про моки ничего не слышали?
Еще как слышал, про моки и стабы, котрые нужно писать - это деньги. И в случае юнитов вы тестируете только код, но не то кол-во логики, которое вынесено на уровень инфраструктуры.
Вообще смешной аргумент. Ну не используйте докер если видите в этом проблему.
Я сказал "если" - а их, как правило и используют, не понимая, что это несет для компании. Прочитайте внимательно, что я написал.
Это и в монолите надо делать.
Только в случае внешних взаимодействий. Всё.
Я вам так скажу: микросервисы существуют гораздо дольше. Только их далеко не всегда называли микросервисами :)
Так я об этом и написал! И это всегда была боль ради распределения нагрузки.
Это математически невозможно
Зато постоянно происходит :)
Вы простой вызов метода заменяете сетевым взаимодействием.
Даже близко нет. И этот комментарий намекает мне что вы не особо разбираетесь в теме.
Для монолита нужны просто программисты
Ага. Я посмотрю на вас когда у вас пара сотен "просто программистов" начнут работать над общей кодовой базой в несколько миллионов строк кода :)
Еще как слышал, про моки и стабы, котрые нужно писать - это деньги
А в монолите их не нужно писать? У вас там только интеграционные тесты?
И это всегда была боль ради распределения нагрузки.
Нет. Особой боли там нет. И делается это не только ради распределения нагрузки.
Тут где то написали - если у вас бизнес масштаба Вайлдберриз - то микросервисы необходимы. Но в 95% случаев - это не так. Предположу, что у вас это тоже не так (хотя могу ошибаться) и все ваши сервисы только лишь приносят боль. Не вам - компании!
Зато постоянно происходит :)
Это ваши фантазии.
Тут где то написали - если у вас бизнес масштаба Вайлдберриз - то микросервисы необходимы
Это не значит что во всех остальных случаях они не нужны.
Предположу, что у вас это тоже не так (хотя могу ошибаться) и все ваши сервисы только лишь приносят боль. Не вам - компании!
У нас это по разному. И в отдельных проектах мы используем микросервисы(или точнее распределённую архитектуру} потому что монолит создаёт там гораздо больше проблем.
Это не значит что во всех остальных случаях они не нужны.
Перечислите.
Раздельный деплой? Деплойте весь монолит - это возможно.
Работа с репой нескольких команд? Организуйте исходники, используя DDD, домены и ограниченные контексты - и вы будете пересекаться именно в тех случаях, когда зависимости необходимы - это сигнал для "события предметной области". И да - монорепа - это благо.
Вам нужно масштабировать нагрузки? В правильном монолите это решается поднятием уровня изоляции с потока/корутины до процесса/контенера.
Вот и все плюсы микросервисов решены в монолите.
Монолит вам создаёт кучу проблем, потому что вы не умеете всё вышеперечисленное.
Перечислите
"Возможно использовать монолит" не означает "удобнее/дешевле использовать монолит".
Монолит вам создаёт кучу проблем, потому что вы не умеете всё вышеперечисленное.
Я точно так же могу вам сказать что микросервисы создают вам кучу проблем потому что вы не умеете их правильно использовать.
Ну и как бы расскажите мне как правильно использовать монолит когда:
-Часть функционала пишется не нами, а самими клиентами или нашими партнёрами или даже просто отдаётся на аутсорс.
Из-за сторонних зависимостей приходится использовать абсолютно разные тех-стеки.
Работать разные части кода должны на разном железе. Причём так что одна часть на винде, другая на соседней машине на линуксе, третья интегрируется в какой-нибудь TestStand, а четвёртая запускается в эмбеддед-окружении на каких-нибудь датчиках или производственном железе.
Часть функционала пишется не нами, а самими клиентами или нашими партнёрами или даже просто отдаётся на аутсорс.
Библиотеки не пробовали? :D Так написан весь линукс)
Остальное - частные случаи, которые редко встречаются в разработке и в данном контексте просто не применимы.
Еще раз - микросервисы дороже математически - не спорьте!!!
Библиотеки не пробовали?
Конечно пробовали. А вы не пробовали интегрировать в монолит библиотеки из кучи разных ЯП, фрэймворков, версий и так далее?
Остальное - частные случаи, которые редко встречаются в разработке и в данном контексте просто не применимы.
У вас есть статистика? Можете ссылочку дать?
Еще раз - микросервисы дороже математически - не спорьте!!!
Ещё раз: это просто голословное утверждение. Более того я вам привёл конкретный пример когда это не так.
Работать разные части кода должны на разном железе. Причём так что одна часть на винде, другая на соседней машине на линуксе, третья интегрируется в какой-нибудь TestStand, а четвёртая запускается в эмбеддед-окружении на каких-нибудь датчиках или производственном железе.
Так похоже вы сами себе и сделали подобный винегрет) а потом за уши притягиваете микросервисы/распределенные архитектуры. Так и живите с ним "счастливо". Я говорю о среднестатистическом веб-приложении, ибо в "коробке" о микросервисах даже и говорить не приходится)
Так похоже вы сами себе и сделали подобный винегрет) а потом за уши притягиваете микросервисы/распределенные архитектуры
Мы себе ничего не сделали. Это требования от клиентов на реальных производственных линиях.
Я говорю о среднестатистическом веб-приложении, ибо в "коробке" о микросервисах даже и говорить не приходится)
А весь мир ограничивается среднестатистическими веб-приложениями?
А весь мир ограничивается среднестатистическими веб-приложениями?
Представьте себе, в большинстве случаев - да!
Мы себе ничего не сделали. Это требования от клиентов на реальных производственных линиях.
Так вы микросервисы на производственных линиях используете? Без каких либо нагрузок? :big beautiful facepalm:
А вот с этим вот соглашусь с товарищем. Если так сложилось что какие-то модули написаны на чёрти-чём или тащят неведомые зависимости, то проще отколупать это и пусть живёт оно своей жизнью. Лишь бы контракт интерфейсов соблюдало.
Что до сетевого оверхеда - столь тесно связанные функции однозначно должны быть макисмально бинарно приближены друг к другу. В остальных же случаях, отколупать такой независимый модуль как минимум не возбраняется (но надо ли?).
Из-за сторонних зависимостей приходится использовать абсолютно разные тех-стеки.
Работать разные части кода должны на разном железе. Причём так что одна часть на винде, другая на соседней машине на линуксе, третья интегрируется в какой-нибудь TestStand, а четвёртая запускается в эмбеддед-окружении на каких-нибудь датчиках или производственном железе.
То, что должно работать в таком окружении - пусть в нем и работает. В остальном - монолит)
А теперь переходим к следующему уровню сложности: в теории 80-90% всего решения могут получить такую зависимость. Ну или точнее от проекта к проекту это реально происходит.
Не проще тогда построить инфраструктуру на микросервисах, написать "стандартные" сервисы для всего что надо и потом только по необходимости менять отдельные сервисы на проприетарные решения в отдельных проектах?
Во-первых - не фантазируйте! Такие зависимости появляются крайне редко.
Во-вторых - такие зависимости как-раз таки можно вынести в отдельные окружения, заставить общаться по апи и жить с этим.
В-третих - только нагрузки - объективная причина появления таких архитектур. Веб и Нетфликс всему виной! Все остальные вопросы можно так или иначе решить без распределения.
На этом заканчиваю. Спасибо!
Во-первых - не фантазируйте! Такие зависимости появляются крайне редко.
Так я не фантазирую. Я вам описываю реальную ситуацию.
Во-вторых - такие зависимости как-раз таки можно вынести в отдельные окружения, заставить общаться по апи и жить с этим.
Ну так что делать если в теории практически 99% кода могут словить такую зависимость? Что куда выносить? Как организовать архитектура чтобы в каждом новом проекте можно было переиспользовать как можно больше базового кода?
В-третих - только нагрузки - объективная причина появления таких архитектур.
Это вы сейчас сами придумали?
Так я не фантазирую. Я вам описываю реальную ситуацию.
Она реальна только для вас и только в вашей предметной области она может иметь более 80-90% наличия (возможно из-за специфичного оборудования и тд). Сейчас основные микросервисёры/распределёнщики - это веб и saas, там, где неконтролируемая сетевая нагрузка! А я имею ввиду именно эту область.
Ну так что делать если в теории практически 99% кода могут словить такую зависимость? Что куда выносить? Как организовать архитектура чтобы в каждом новом проекте можно было переиспользовать как можно больше базового кода?
маргинальные/форточные/и всякие остальные "тех.стеки" - в отдельные окружения с интерфейсами и докером (удобство, тормознутость) либо microvm (скорость/безопасность). Свои - в библиотеки. Всё просто!
Не проще тогда построить инфраструктуру на микросервисах, написать "стандартные" сервисы для всего что надо и потом только по необходимости менять отдельные сервисы на проприетарные решения в отдельных проектах?
Боюсь нет. Не вгоняйте компанию в долги, если имеете чуточку ответственности перед работадателем. Лучше почитайте правильную лит-ру а не хабр.
> В-третих - только нагрузки - объективная причина появления таких архитектур.
Это вы сейчас сами придумали?
Нет, не сам. Просто всё остальное действительно можно решить без микросервисов! А вот нагрузку уровня Вайлдберриз - вряд-ли.
Она реальна только для вас
Она реальна в принципе.
Свои - в библиотеки. Всё просто!
Прочитайте пожалуйста ещё раз входные данные. То, что вы предлагаете, не будет нормально работать.
Боюсь нет. Не вгоняйте компанию в долги, если имеете чуточку ответственности перед работадателем
Не пишите ерунды и не давайте глупые советы если не разбираетесь в теме. Вы кроме вашего веба что-то другое хотя бы видели?
Нет, не сам
Тогда дайте пожалуйста ссылку на источник этого вашего утверждения.
Есть одно хорошее правило, как решать описанную в вашей статье проблему: если в вашей архитектуре появилось множество вызывающих друг друга микросервисов, значит, вам пришла пора переходить на монолит
В монолите можно просто менять отдельные его части во время рантайма? Как насчёт вышеупомянутого масштабирования?
Не надо делать микросервисы просто ради того чтобы всё было стильно, модно и молодёжно. Микросервисы нужны когда требуются частые обновления и масштабируемость. Или например когда у вас над проектом работают большие разделённые команды с кучей разработчиков. Или когда по какой-то причине надо использовать разные технологии. Или например когда у вас данные по какой-то причине должны быть строго разделены(например из-за юридических требований). И так далее и тому подобное.
Можно конечно менять отдельные части. В чём проблема то?
То есть грубо говоря ваш монолитный сервер запущен и работает. И вы не останавливая работу меняете отдельные части?
То есть я понимаю что в принципе это решаемо. Через какие-нибудь плагины или динамическую загрузку библиотек. Но на мой взгляд это всё тоже не особо просто, удобно и самое главное стабильно в рантайме.
То есть грубо говоря ваш монолитный сервер запущен и работает. И вы не останавливая работу меняете отдельные части?
Почти. Я обновляю его целиком, но да, не останавливая работу. Этого достаточно, замена именно по частям не есть самоцель, цель - обеспечить бесперебойное обслуживание клиентов, монолит в этом плане ничуть не уступает микросервисам. Плагины (и вообще какие-либо доработки архитектуры) не требуются, всё это прозрачно обеспечивает инфраструктура облака. Вы поднимаете новый инстанс в новом слоте, существующие запросы дорабатывают на старом, новые запускаются на новом, старый инстанс после завершения запросов отключается.
Я обновляю его целиком, но да, не останавливая работу
И это гораздо сложнее и больше геморроя чем обновления в микросервисной архитектуре. Особенно если вам необходимо относительно часто делать относительно небольшие изменения.
Ещё раз: всё имеет свои плюсы и свои минусы. Микросервисы это не панацея и не серебряная пуля. Но в определённых ситуациях они лучше монолита.
И это гораздо сложнее и больше геморроя чем обновления в микросервисной архитектуре.
Вообще нет, ни капли не сложнее, просто больше машинного времени на сборку/развёртывание, но это делает глупая железяка, а не люди.
Ещё раз: всё имеет свои плюсы и свои минусы. Микросервисы это не панацея и не серебряная пуля. Но в определённых ситуациях они лучше монолита.
Я с вами абсолютно согласен, единственное, что я утверждаю, что этих ситуаций, где микросервисы лучше монолита, намного меньше, чем многим кажется. По сути дела, опросник по внедрению микросервисов должен выглядеть как-то так:
Ваш электронный бизнес размером с Вайлдбериз?
Нет? Значит, вам микросервисы пока ещё не нужны.
Вообще нет, ни капли не сложнее, просто больше машинного времени на сборку/развёртывание, но это делает глупая железяка, а не люди.
И например тестировать надо больше. И больше последствий при проблемах.
Я с вами абсолютно согласен, единственное, что я утверждаю, что этих ситуаций, где микросервисы лучше монолита, намного меньше, чем многим кажется.
У меня такой статистики нет. И по моему личному опыту большинство людей вообще не особо думают когда принимают такие решения. Кто-то из них просто принципиально за и поэтому пихает микросервисы везде где надо и где не надо. А кто-то принципиально против и выбирает монолит даже если это создаёт кучу проблем.
По сути дела, опросник по внедрению микросервисов должен выглядеть как-то так: Ваш электронный бизнес размером с Вайлдбериз? Нет? Значит, вам микросервисы пока ещё не нужны.
У нас вообще не электронный бизнес. Мы продаём решения для автоматизированных конвейрных линий для индустрии. Но всё равно вынуждены каждый второй проект делать на микросервисах.
И например тестировать надо больше. И больше последствий при проблемах.
Это не так на самом деле. Изменения в монолите стоят по тестированию/последствиям примерно столько же, сколько и в микросервисах. Исключения есть в гипотетических примерах, когда как вы и предположили, если вдруг кто-то затянул новую версию библиотеки, да эта библиотека вдруг используется везде, да в новой версии поломалась совместимость со старой, вот тогда опаньки. Сколько таких библиотек в природе существует? Newtonsoft json есть, но они совместимость не ломали. Зато есть у монолита и в тестируемости бонус: там легко заменить бестолковые юнит-тесты на эффективные интеграционные. И будет ваше тестирование тоже успешно делать железяка.
У меня такой статистики нет. И по моему личному опыту большинство людей вообще не особо думают когда принимают такие решения
Я согласен с вами, хайповая мотивация у нас вообще преобладает над осознанной.
Но всё равно вынуждены каждый второй проект делать на микросервисах.
Ну вы-то, вероятно, предлагаете архитектуру, соответствующую той, что уже есть у клиента, а не пишете ему что-то с нуля на голые серверы в чистом поле.
Это не так на самом деле. Изменения в монолите стоят по тестированию/последствиям примерно столько же, сколько и в микросервисах
Ну нет же. Зависимость сильнее. Единичные изменения могут затрагивать большее количество кода. Банально те самые общие библиотеки.
Сколько таких библиотек в природе существует?
Полно.
Newtonsoft json есть, но они совместимость не ломали.
Но это не значит что не может быть каких-то "побочек". И если у вас развлекательная платформа, то вы можете забить на тесты. В какой-нибудь медицинской технике или там финтехе придётся каждый раз всё проверять.
Ну вы-то, вероятно, предлагаете архитектуру, соответствующую той, что уже есть у клиента, а не пишете ему что-то с нуля на голые серверы в чистом поле.
Архитектура у нас чисто своя. Проблема в зависимостях и библиотеках от клиентов.
Ну нет же. Зависимость сильнее.
Ну так она сильнее по способу компоновки, а не по числу внутренних связей и зависимых компонент. И если вы вносите изменения в функционал какого-то сервиса в монолите, это касается только тех компонент, которые этот сервис вызывают, ровно так же, как и в микросервисах.
В какой-нибудь медицинской технике или там финтехе придётся каждый раз всё проверять.
Да, как и в случае микросервисов, я в mission critical софте тоже их все буду загонять в интеграционные тесты и проверять, при изменении всего лишь одного из них.
И если вы вносите изменения в функционал какого-то сервиса в монолите, это касается только тех компонент, которые этот сервис вызывают, ровно так же, как и в микросервисах
Нет. И я выше уже привёл пример с общими библиотеками.
Да, как и в случае микросервисов, я в mission critical софте тоже их все буду загонять в интеграционные тесты и проверять, при изменении всего лишь одного из них.
Но в монолите вам нужно не только интеграционные тесты делать, но и проверять отдельно каждый кусок кода, который имеет зависимость на библиотеку, которая поменялась. В отличии от микросервисов. То есть как ни крути, в в монолите будет больше тестов.
Нет. И я выше уже привёл пример с общими библиотеками.
Да. Я не ошибусь, если скажу, что 99.99% времени разработки вы не меняете общие библиотеки. А 0.01% можно пренебречь.
Но в монолите вам нужно не только интеграционные тесты делать, но и проверять отдельно каждый кусок кода, который имеет зависимость на библиотеку, которая поменялась.
Мне не надо его проверять, мне достаточно убедиться, что интеграционные тесты работают корректно, значит, и нижележащий код работает корректно. Тем более что, в отличии от микросервисов, я прекрасно знаю все куски кода, где та библиотека используется, и могу это контролировать.
Я не ошибусь, если скажу, что 99.99% времени разработки вы не меняете общие библиотеки.
Ошибётесь.
А 0.01% можно пренебречь.
Это где-то час в год если я всё правильно прикинул.
Мне не надо его проверять, мне достаточно убедиться, что интеграционные тесты работают корректно, значит, и нижележащий код работает корректно.
То есть у вас есть только интеграционные тесты? Но при этом такие, которые покрывают абсолютно всё? Не расскажите как вы такого добились?
Тем более что, в отличии от микросервисов, я прекрасно знаю все куски кода, где та библиотека используется, и могу это контролировать
Какой размер кодовой базы у вашего монолита? Ну что вы знаете все куски кода?
Это где-то час в год если я всё правильно прикинул.
Где-то так, да. А как часто вы там новые общие библиотеки в проекте меняете?
То есть у вас есть только интеграционные тесты?
Затрудняюсь сказать, как вы к этому выводу пришли.
Какой размер кодовой базы у вашего монолита? Ну что вы знаете все куски кода?
Я и не знаю. Мне их IDE в монорепе за секунду покажет, и напишет, кто каким куском занимался.
А как часто вы там новые общие библиотеки в проекте меняете?
Регулярно. Например присылает добрый клиент новую версию своей библиотеки. А там зависимость от условного NewtonsoftJson конкретной версии. И приходится везде эту версию использовать.
Затрудняюсь сказать, как вы к этому выводу пришли.
Ну вы же написали что вам не надо проверять отдельные куски кода.
Я и не знаю. Мне их IDE в монорепе за секунду покажет, и напишет, кто каким куском занимался.
Ну вот кто-то поменял версию того самого условного NewtonsoftJson. Вам IDE покажет все куски кода, которые из-за этого могут начать неправильно работать?
Ну то есть давайте представим что там баг и где-то какое-то поле при сериализации/десериализации получит неправильное значение в определённых ситуациях. Как вам IDE покажет все места, которые надо проверить?
Вообще нет, ни капли не сложнее, просто больше машинного времени на сборку/развёртывание, но это делает глупая железяка, а не люди.
Это зависит от различных факторов и процессов. Как правило, для деплоя монолита в крупной компании используются релизы, а не автоматический деплой после после каждого изменения. по этой причине, чтобы обновить монолит потребуется ждать следующего цикла. Или делать внеочередной релиз с хот фиксом.
Релизы + фиксы деплоят не потому что только так могут, а потому что это единственная правильная тактика чтобы крутить в проде стабильную систему. Автоматически деплоить в прод каждое изменение это конечно мощно!
Микросервисы нужны когда требуются частые обновления и масштабируемость. Или например когда у вас над проектом работают большие разделённые команды с кучей разработчиков. Или когда по какой-то причине надо использовать разные технологии.
Да и то, легко возразить по каждому пункту:
Масштабируемость у монолитов не особо и уступает микросервисам, вы точно так же можете добавлять инстансы по мере роста нагрузки. Да и сложность обновлений, это сильно преувеличенная проблема. Профиты от микросервисов в данном ключе совершенно незначительны по сравнению с привносимыми ими недостатками.
И в случае микросервисов, и в случае монолита, от распределённых команд требуется одно и то же - соблюдение контрактов у компонент приложения. И совсем не принципиально, как будет организована связность, через хттп в случае микросервисов, или через линковку в случае монолита.
Насчёт разных технологий - да, тут микросервисы придётся использовать, но следует упомянуть, что сама по себе ситуация, когда вы фрагментируете стек технологий в рамках одного проекта, это выстрел солью с перцем себе в жопу, и её надо избегать насколько это возможно.
Масштабируемость у монолитов не особо и уступает микросервисам, вы точно так же можете добавлять инстансы по мере роста нагрузки
Но при этом в монолите вы не можете масштабировать конкретно ту часть системы, на которую выросла нагрузка. Вам нужно масштабировать всю систему.
Да и сложность обновлений, это сильно преувеличенная проблема.
Вам надо апдейтнуть какой-то небольшой функционал. У него есть зависимость от сторонней библиотеки и вам надо взять новую версию этой библиотеки. Но эта библиотека используется практически во всём монолите. Получается после небольшого апдейта вам надо тестировать практически весь функционал монолита.
И в случае микросервисов, и в случае монолита, от распределённых команд требуется одно и то же - соблюдение контрактов у компонент приложения.
Если у вас над одной монолитной кодовой базой работает 100500 человек, то вам будет очень весело согласовывать апдейты зависимостей или банально развлекаться с конфликтами в MR.
но следует упомянуть, что сама по себе ситуация, когда вы фрагментируете стек технологий в рамках одного проекта, это выстрел солью с перцем себе в жопу, и её надо избегать насколько это возможно
Как будто это всегда возможно. Ну то есть у нас половина проектов это интеграция решений от нескольких клиентов и их партнёров. Одни присылают сишные библиотеки, другие net core, третьи джаву, четвёртые питон, а интегрировать жто надо в какой-нибудь сименовский TIA, который до сих пор сидит на винформс или там в TestStand.
Но при этом в монолите вы не можете масштабировать конкретно ту часть системы, на которую выросла нагрузка. Вам нужно масштабировать всю систему.
Мне это не принципиально. У меня каждое обращение к монолиту происходит точно так же, как и в микросервисе - точка входа, внутренний сервис с бизнес-логикой, хранилище, снова тот же сервис, возврат. Если у меня на какую-то одну точку входа и один внутренний сервис увеличивается нагрузка, я тоже могу увеличить количество инстансов, и всё будет работать точно так же.
Вам надо апдейтнуть какой-то небольшой функционал. У него есть зависимость от сторонней библиотеки и вам надо взять новую версию этой библиотеки. Но эта библиотека используется практически во всём монолите. Получается после небольшого апдейта вам надо тестировать практически весь функционал монолита.
А с микросервисами у меня будут зависимости на пять разных версий данной библиотеки, а потом ещё и вылезет разное побочное поведение из-за фрагментации версий. Лучше уж протестировать, благо, в нормальной разработке это делается автоматически.
Если у вас над одной монолитной кодовой базой работает 100500 человек, то вам будет очень весело согласовывать апдейты зависимостей
Почему? Наоборот, это будет делаться централизованно и контролируемо, ваши разработчики будут лишены возможности вот так с кондачка затянуть любую библиотеку, которая им понравилась, и будут вынуждены делать это осознанно.
Как будто это всегда возможно.
Конечно, не всегда. Но случаев, когда в проект тянут команды с разными стеками просто потому, что всем пофигу, лишь бы работало, их куда больше, чем случаев, когда это делается реально вынужденно.
Мне это не принципиально
И если вам это не принципиально, то это значит что всем остальным это тоже не принципиально?
А с микросервисами у меня будут зависимости на пять разных версий данной библиотеки
И в чём проблема? У вас же раздельная кодовая база. Можете хоть разные стеки использовать.
а потом ещё и вылезет разное побочное поведение из-за фрагментации версий
Ну так тестирование никто не отменял. Но вам нужно каждый микросервис тестировать отдельно. И если он работает, то его можно не трогать и не тестировать пока не нужно что-то менять конкретно в нём.
Наоборот, это будет делаться централизованно и контролируемо, ваши разработчики будут лишены возможности вот так с кондачка затянуть любую библиотеку, которая им понравилась, и будут вынуждены делать это осознанно.
То есть во первых у вас дополнительный организационный оверхед. Плюс если кому-то реально нужно аплейтить зависимости, то проблема остаётся.
Но случаев, когда в проект тянут команды с разными стеками просто потому, что всем пофигу, лишь бы работало, их куда больше, чем случаев, когда это делается реально вынужденно
Во первых хотелось бы посмотреть на эту статистику.
А во вторых даже если и так, то это тоже плюс для бизнеса. То есть он более свободен в вопросах найма новых сотрудников.
И если вам это не принципиально, то это значит что всем остальным это тоже не принципиально?
Там суть была не в том, что оно лично мне не нужно, а в том, что масштабирование монолита не стоит дороже, чем масштабирование микросервиса.
И в чём проблема? У вас же раздельная кодовая база. Можете хоть разные стеки использовать.
Ну как, если мы говорим про абстрактную библиотеку, которая якобы везде используется, то она может влиять на что угодно, например, на десериализацию данных. Вот буквально на прошлой неделе у меня у самого была ситуация - две разных версии одной и той же библиотеки восстанавливали состояние воркфлоу по-разному, и в итоге начатый в одном приложении флоу в ряде случаев не мог быть продолжен во втором. Это не микросервисы, но проблема абсолютно аналогичной природы. Кодовая база должна быть синхронизирована.
То есть во первых у вас дополнительный организационный оверхед. Плюс если кому-то реально нужно аплейтить зависимости, то проблема остаётся.
Мы этим организационным оверхедом решаем куда более дорогой и неприятный оверхед дублирования кодовой базы.
А во вторых даже если и так, то это тоже плюс для бизнеса. То есть он более свободен в вопросах найма новых сотрудников.
Ну так а бизнесу нафиг не надо "более свободен". Найти столько специалистов, сколько нужно по одной и той же платформе - это всего лишь ещё одна задача для менеджера нижнего звена и эйчара. А сэкономить гроши на найме и фрагментировать платформу, это уже ловушка для всего бизнеса в целом, когда расходы на развитие и сопровождение софта кратно растут, и назад дороги нет. Если (когда) у вашего бизнеса наступит мёртвый сезон, при гомогенной кодовой базе он может просто сократить разработку и пережить этот период. При фрагментированной ему ещё надо будет платить за поддержание экспертизы в каждой из притянутой в проект технологии.
Ну как, если мы говорим про абстрактную библиотеку, которая якобы везде используется, то она может влиять на что угодно, например, на десериализацию данных.
У вас есть сервис с этой библиотекой. Он протестирован и работает без проблем. У вас есть другой сервис тоже с этой библиотекой. Тоже протестирован и работает.
Вам зачем-то надо апдейтнуть библиотеку для первого сервиса. Его теперь надо тестировать заново. Но зачем трогать второй?
Мы этим организационным оверхедом решаем куда более дорогой и неприятный оверхед дублирования кодовой базы.
Но с увеличением количества программистов эти оверхеды будут расти по разному. В какой-то момент ситуация поменяется.
Ну так а бизнесу нафиг не надо "более свободен"
М чего вы решили что можете говорить за весь бизнес?
Найти столько специалистов, сколько нужно по одной и той же платформе - это всего лишь ещё одна задача для менеджера нижнего звена и эйчара
До 2022-го это так просто не работало. Готовы были брать кого угодно. Ситуации разные бывают.
Вам зачем-то надо апдейтнуть библиотеку для первого сервиса. Его теперь надо тестировать заново. Но зачем трогать второй?
Так я вам даже пример привёл. Второй сервис не надо тестировать, он-то свои юнит-тесты пройдёт. А вот что он пройдёт интеграционный тест, уже не факт, смотря за что библиотека отвечала, и каков был контракт между сервисами, надо будет тестировать.
Но с увеличением количества программистов эти оверхеды будут расти по разному. В какой-то момент ситуация поменяется.
Не поменяется, размер кодовой базы (а значит, и требуемое количество разработчиков) для монолита всегда будет меньше, чем кодовой базы для микросервисов. В монолите же у вас будут общие сервисы.
М чего вы решили что можете говорить за весь бизнес?
Опыт, прекрасное понимание проблем и задач бизнеса. Конечно, притянуть за уши какую-то надуманную ситуацию всегда можно, но ладно, давайте я буду говорить за 99.99% бизнеса, что это поменяет?
До 2022-го это так просто не работало. Готовы были брать кого угодно.
Это не из-за нехватки профильных программистов на рынке, а просто потому, что денег в индустрии было завались, на разумное их использование всем было начхать. Сейчас уже такой лафы нет, пора привыкать проектировать архитектуры, выбирать технологии, и подбирать себе штат.
Второй сервис не надо тестировать, он-то свои юнит-тесты пройдёт. А вот что он пройдёт интеграционный тест, уже не факт
В его поведении ничего не изменилось. Почему он не должен пройти тесты если он проходил их до этого?
и каков был контракт между сервисами, надо будет тестировать.
Контракты не менялись в этом примере.
Не поменяется, размер кодовой базы (а значит, и требуемое количество разработчиков) для монолита всегда будет меньше, чем кодовой базы для микросервисов
Но разработчиков микросервисов нужно меньше координировать. Они могут работать полностью независимо если не меняются контракты.
Опыт, прекрасное понимание проблем и задач бизнеса.
У меня опыт другой.
Это не из-за нехватки профильных программистов на рынке, а просто потому, что денег в индустрии было завались, на разумное их использование всем было начхать
Неважно почему. Ситуация такая была.
Сейчас уже такой лафы нет, пора привыкать проектировать архитектуры, выбирать технологии, и подбирать себе штат.
Сейчас нет. Завтра будет. Или послезавтра. Или...
В его поведении ничего не изменилось. Почему он не должен пройти тесты если он проходил их до этого?
Зато изменилось в поведении другого сервиса, который вы обновили. А откуда вы можете быть уверены, что его поведение в интеграции с другими сервисами теперь соответствует контракту?
Контракты не менялись в этом примере.
Контракт, это такая хитрая штука, которая как и тесты, не имеет 100% покрытия всего поведения. И ошибки любят возникать как раз в интеграции компонент, а не внутри. Те, которые внутри, которые явно нарушают контракт, отлавливаются легко.
Но разработчиков микросервисов нужно меньше координировать. Они могут работать полностью независимо если не меняются контракты.
Или наоборот, у разработчиков микросервисов должен быть свой выделенный внутренний микроменеджмент, чего не требуется в случае монолита.
Неважно почему. Ситуация такая была.
Важно. Причина "я не делаю, потому что не имею возможности", это аргумент, а "я не делаю, потому что мне пофиг", уже не аргумент :)
Сейчас нет. Завтра будет. Или послезавтра. Или...
Да уже прям сейчас. Рыночек-то поменялся.
Зато изменилось в поведении другого сервиса, который вы обновили
Вы это сейчас серьёзно? Если поведение другого сервиса ломает систему, то это проблема того самого другого сервиса. Этого не должно происходить если контракты не меняются.
Контракт, это такая хитрая штука, которая как и тесты, не имеет 100% покрытия всего поведения
Эээ, что?
Или наоборот, у разработчиков микросервисов должен быть свой выделенный внутренний микроменеджмент
Зачем?
Причина "я не делаю, потому что не имею возможности", это аргумент, а "я не делаю, потому что мне пофиг", уже не аргумент :
И опять: эээ, что?
Да уже прям сейчас. Рыночек-то поменялся.
Рыночек в мире меняется каждые 5-10 лет.
Вы это сейчас серьёзно? Если поведение другого сервиса ломает систему, то это проблема того самого другого сервиса. Этого не должно происходить если контракты не меняются.
Абсолютно серьёзно. Этого не должно происходить, но тем не менее, это как раз та самая категория проблем, которая
а) происходит
б) проходит через юнит-тесты
Контракт, повторюсь, практически никогда не имеет 100% покрытия. И сразу пояснение, раз уж спросили: в контракте может не быть влияющих на работу таймаутов, может быть упущен какой-то вид исключений, может не учитывать сайд-эффекты десериализации и так далее. Поэтому если у вас код критикал, его нужно дополнительно тестировать, несмотря на то, что он проходит на соответствие контракту.
Зачем?
Потому что если у нас микросервисы пишут разные команды, у них там и разные менеджеры будут. Это как раз в порядке вещей. А если разные программисты в одной команде, то у них вот вообще никак не будет проблемы синхронизировать между собой кодовую базу.
И опять: эээ, что?
Там всё настолько просто, что мне тут даже непонятно, что у вас вызвало непонимание :)
Абсолютно серьёзно. Этого не должно происходить, но тем не менее, это как раз та самая категория проблем, которая происходит
Не могу припомнить ни одного случая в моей практике. Наверное мы что-то делаем не так...
Потому что если у нас микросервисы пишут разные команды, у них там и разные менеджеры будут.
Совсем не обязательно. Но речь и не об этом.
А если разные программисты в одной команде, то у них вот вообще никак не будет проблемы синхронизировать между собой кодовую базу.
Если у вас все программисты, которые работают над всей вашей системой, вмещаются в одну команду, то естественно проблем не будет.
Но что вы будете делать если у вас над вашей системой работают сотни, а то и тысячи программистов?
Там всё настолько просто, что мне тут даже непонятно, что у вас вызвало непонимание :)
Формулировка. Вообще непонятно что вы хотели этим сказать.
Чисто из интереса - каков размер самого большого монолита, с которым вы непосредственно работали? И каким был размер команды разработчиков?
Я бы добавил еще один минус, с котором сталкивался в монолитах на java - это обновление версии библиотек или самой JVM, поэтому встречал корпоративный продукты которые работали на JDK 1.6, когда уже 11 версия существовала. Те же Spring обновления бывают ломают все и требуют обновление других компонентов и не понятно где это все вылезти может. А микросервисы намного проще в этом плане их можно постепенно переводить на актуальные версии библиотек и не доставлять боль другим.
Вы, конечно, знатно набросили на вентилятор. Но дальнейшее обсуждение меня сильно удивило - почему-то все упёрлись в проблемы масштабирования по CPU (тут монолит действительно горизонтально масштабируется не сильно хуже микросервисов) либо необходимость в разных ЯП на одном проекте (тут микросервисам альтернативы нет) либо управление зависимостями (тут решает монорепо, не важно в нём монолит или куча микросервисов). Хотя статья, вообще-то, про архитектуру, а архитектурные проблемы при использовании монолита никуда не исчезают.
Проблема №1 — Эффект домино: каскадные сбои и хрупкость системы
Недоступность сервиса может быть вызвана разными причинами. Если это проблема с сетью - то это специфика микросервисов. Но если это проблема с БД или внешними сервисами или дедлок - в монолите эта проблема не просто есть, она обычно будет намного больнее - потому что у вас заблокируется вызов функции, на который никто таймауты и graceful degradation не делает.
Тема изоляции разных пулов в монолите тоже актуальна, просто их будет меньше.
Проблема №2 — Сага о согласованности данных
В целом всё актуально и для модульного монолита. Особенно если у него внутри сплошной DDD. Включая даже внешний сервис для оркестрации саг - хотя бы потому, что часть бизнес-процессов вроде проведения оплаты обычно зависит от внешних интеграций.
Вопрос о необходимости Transactional Outbox зависит от того, изолированы ли БД разных модулей внутри монолита друг от друга или нет. Если да - он всё ещё нужен. Если нет - у нас резко выросла сложность координации модулей внутри монолита из-за общей БД плюс добавились сложности с её масштабированием.
Проблема №3 — Деградация производительности и «тысяча порезов»
gRPC не нужен, CQRS всё ещё нужен (он вообще обычно внедряется не ради локального кеша чужих данных, тут в статье не совсем корректно), API Gateway/BFF по-прежнему актуальны.
Проблема №4 — Тиски разработчика: локальная среда и тестирование
В целом тоже всё актуально. И сторонних сервисов вроде брокеров/БД/etc. монолиту обычно нужно больше чем одному микросервису, и моки для тестирования своего кода в изоляции всё ещё нужны. Но да, обычно проблем с монолитом тут в разы меньше.
Проблема №5 — Распределенная дилемма данных: Joins vs. Duplication
Тут снова вопрос как в монолите сделали БД - если одну общую то будут одни проблемы, если у каждого модуля собственную то эта проблема никуда не девается.
Проблема №6 – Системная слепота: наблюдаемость и отладка
На мой взгляд микросервисы просто сделали эту проблему очевидной. А по факту мониторить монолит нужно ровно так же (т.е. тут проще не станет).
Проблема №7 — Операционный хаос: обнаружение и конфигурация
И вот оно, где монолит реально упрощает!… А, не, показалось. :-)
Если серьёзно, то на первый взгляд у монолита тут всё проще. Но на второй взгляд выясняется, что это так только пока монолит запущен в единственном инстансе и в проекте кроме этого монолита больше ничего нет. Потому что как только инстансов монолита становится несколько появляется смысл в "Решение Б: Централизованный сервер конфигурации". А как только помимо монолита в проекте появляется парочка тривиальных микросервисов (для интеграций или из организационных соображений) то и "Решение А: Реестр сервисов" становится актуальным.
Проблема №8 — Эволюция API и версионирование
По-прежнему актуально (просто в монолите общее количество API будет намного меньше - только внешние клиенты и интеграции).
Проблема №9 — Дыры в безопасности: доверие и авторизация
И... вот оно! В монолите этой проблемы действительно нет.
Резюмируя: единственное серьёзное архитектурное отличие модульного монолита от микросервисов - это возможность иметь общую БД. Для микросервисов это однозначно плохо, но для монолита это вопрос не такой однозначный. Общая БД решает одни проблемы (в основном связанные с транзакционностью бизнес-процессов и консистентностью данных) но при этом создаёт другие проблемы (масштабирование, дополнительные связи между модулями) - и баланс этих проблем сильно зависит от конкретного проекта.
На мой взгляд, монолиты бывают двух типов: простые (всё в одной куче, как писали 20 лет назад) и модульные (с проектированием модулей по стратегическим паттернам DDD). Простые действительно позволяют всё сильно упростить относительно микросервисного подхода, но всегда ведут к архитектуре "большой комок грязи" (что не мешает их успешно использовать проектам, в которых активное развитие кодовой базы останавливается задолго до достижения этого финала). А модульные принципиально от микросервисов особо не отличаются и заметно проще разработку не делают.
Вообще, при современных распределенных БД не совсем понятно, в чем проблема в общей БД для множества сервисов. Контракт интеграции, особенно для чтения, легко реализуется через view и, при этом, будет много эффективнее, чем тот же gRPC.
Впрочем, в статье столько всякой чуши написано, что нет смысла даже критиковать. Как будто плохую книжку по сисдизайну пересказывают, еще и десятилетней давности...
Проблема в усилении связи между сервисами. Когда изменения одного случайно ломают другой. Общая БД создаёт явные (и неявные) контракты между сервисами, которые крайне сложно соблюдать. Данные твоего сервиса перестают быть только твоими, часть из них оказывается включена в контракт. А хуже всего то, что в БД нет явных механизмов декларирования и версионирования таких контрактов.
Да, для чтения можно сделать явные вьюшки, даже с версионированием в имени. Но чтение это мелочь, которую несложно решить и без этого - подпиской на события и ведением собственного зеркала нужных данных чужого сервиса в удобном текущему сервису виде. Основная проблема не в чтении, а в изменении (в рамках общей транзакции).
Впрочем, в статье столько всякой чуши написано, что нет смысла даже критиковать. Как будто плохую книжку по сисдизайну пересказывают, еще и десятилетней давности...
Да Вы что?! Изложите свой вариант, хотя бы тезисно?
Хм, а где там усиление связи? Какая разница, контракт описывает entrypoint или view или вообще strored procedure - это все описание контрактов. И версионирование для view сделать не сложнее, чем для http calls (и, в среднем, проще, чем для gRPC).
И чтение - это совсем не мелочь, подход с кэшированием данных в своей базе (то, что ты называешь подпиской) - очень сложный, очень трудоемкий (при обеспечении минимальных гарантий), очень сильно повышающий связность, почти никак не версионируемый и, в большинстве случаев, вообще антипаттерн.
Общие транзакции для разных сервисах, разумеется, не реализуемы. Но и подобных потребностей при "интеграции через БД" несколько меньше, так как не нужно инвалидировать кучу кэшей в других сервисах, достаточно поменять данные только в одном месте.
"Изложите свой вариант, хотя бы тезисно?"
Вариант чего? Проблемы взаимодействий в MSA? У меня минимум три доклада разных на эту тему - и это все равно про весьма поверхностный подход к теме.
Вот на этом месте я пошёл гуглить кто такой dph… оказывается, это Фил, и мы в одном ПК. :-) Тем не менее, я бы с удовольствием более глубоко обсудил эту тему как-нибудь, если у тебя будет настроение. Все варианты взаимодействий сервисов через БД, с которыми я сталкивался - не масштабировались. Т.е. какой-то частный use case работал отлично, но при попытке применить этот же подход более широко - начиналась беда. И какого-то определённого списка конкретных сценариев, где это можно безопасно применять, мне в явном виде (статьи/доклады) тоже не попадалось. Да и "отлично работающие" кейсы лично меня всегда напрягали, потому что попахивали распределённым монолитом.
Хм, например задача "реконсиляции" при обработке платежей. У тебя есть история эквайринговых транзакций банка (т.е. прошедших через банк транзакций магазинов, интернет-сайтов и так далее). И есть представление об этой истории у контрагентов (тех же магазинов, платежных систем и так далее). Раз в сутки нужно сверить твои представления о реальности с пришедшими от контрагентов файлами. Форматов файлов много, процессы сверки тоже заметно отличаются. По факту сверки нужно пометить транзакцию как "проверенную".
Одно из решений - каждый тип сверки делается отдельным сервисом, но при этом все эти сервисы смотрят в одну общую базу "истории транзакций". Сами транзакции пишутся процессингом, а вот сервисы реконсиляции умеют только читать из конкретной вьюшки и изменять одно поле.
Получается удобная интеграция через базу, с очень понятным и легко контролируемым контрактом (в том числе и через гранты). Прочие решения будут на порядок менее удобные.
Второй популярный кейс - аналитическая база. Куда пишут (через разные варианты ETL) куча разных сервисов и читают оттуда данные тоже куча разных сервисов для отдачи в bff или для долгосрочного хранения или для отчетности. Собственно, в МСА без этого вообще UI нормальный не сделать, не будешь же джойны и сложные фильтры делать ручками на bff?
А с распределенными базами типа YDB интеграция через базу вообще становится еще и масштабируемой по производительности.
Ну и, если честно, kafka, redis или hazelcast - это тоже все про интеграцию через общее хранилище (общую базу). А используются все эти паттерны для обмена между сервисами очень широко.
Для меня первые два кейса выглядят как "мы решили сэкономить и не написать один (причём обычно - тривиальный) микросервис, через который шли бы эти операции с БД, вместо этого используя в качестве такого микросервиса саму БД (с контролем доступа грантами)". Традиционный вопрос: что случится со всеми этими сервисами, если понадобится изменить схему или структуру (напр. добавить шардирование) БД или даже заменить одну аналитическую БД на другую (типа раньше не было ClickHouse, а потом он вышел, и решили на него мигрировать)? Стоял бы перед этой БД тривиальный микросервис-шлюз, можно было бы все эти изменения сделать исключительно в нём - он бы стал чуть менее тривиальным, но это всё ещё на порядок проще и дешевле обновления всех клиентов.
Ну и, если честно, kafka, redis или hazelcast - это тоже все про интеграцию через общее хранилище (общую базу).
Смотря как делать. Если сделать общий Redis для всего проекта - так и получится, но так делать не нужно, у каждого микросервиса Redis должен быть свой собственный.
Что до брокеров с персистентным хранением сообщений, то там проблема "общей базы" решается контрактами и версионированием формата передаваемых сообщений. Это всё ещё очень больно, но по сравнению с действительно общей БД ситуация всё-таки другая: старые сообщения не изменяются (в отличие от схемы БД при ALTER TABLE), при переходе на новую версию сообщения паблишером старые консьюмеры просто не видят или не обрабатывают новые сообщения пока их не обновят, если нужно удалить из кода поддержку старого формата сообщений то их можно перепослать в новом формате… Всё это больно, но эта боль рождается как раз из желания не превращать брокер в аналог общей БД. Зато изменения одного сервиса (напр. изменение формата публикуемых сообщений) не ломает остальные (которые этот формат пока не понимают) - в отличие от ситуации с общей БД.
Хм, а какой один сервис ты написал бы что для первой задачи, что для второй? Да, в первой задаче нужно пропускать несколько миллионов записей за десятки минут на относительно дешевом железе. Во второй - общее число дочерних сервисов для отчетности - десятки с БД до терабайта.
Да, при изменении схемы совместимым образом - нет проблем. При добавлении шардирования - вообще с реконсиляцией будет все нетривиально, проблемы работы с БД там будут вторичными (да, я знаю, пробовал). Замена одной СУБД на другую - всегда дорогая операция, для аналитических запросов - всегда требует их переписывать. Просто потому что все СУБД очень разные и с разными особенностями реализации. Кейсы, которые делаем на PG - нельзя сделать на CH и наоборот.
А вот обновление пяти-десяти сервисов - это весьма тривиальная задача, кстати. Что там сложного-то? Точно проще, чем с помощью PG научить CH притворяться Вертикой )
Да, в первой задаче нужно пропускать несколько миллионов записей за десятки минут на относительно дешевом железе. Во второй - общее число дочерних сервисов для отчетности - десятки с БД до терабайта.
А причём тут нагрузка? Нагрузка всегда упирается в БД, а не в наш сервис - от него требуется банально переложить ответ БД в ответ своего API, это всяко быстрее любой БД работающей с диском. Вот если бы данные брались из Redis на пределе его возможностей, то наш сервис перед ним мог бы добавить тормозов, это да. Но, в любом случае, это "перекладывание" упирается банально в CPU, так что в крайней ситуации решается запуском дополнительного инстанса.
При добавлении шардирования - вообще с реконсиляцией будет все нетривиально, проблемы работы с БД там будут вторичными
На этой задаче - возможно. Но тогда ты сводишь ситуацию к той, которую я упомянул выше: подход с общей БД работает только для какого-то частного случая (например конкретно этой задачи, где при шардировании сложности самого шардирования потеряются на фоне проблем предметной области). С частными случаями я и не спорю, у меня сомнение вызывает этот подход именно в качестве универсального (вроде описанных в статье).
Замена одной СУБД на другую - всегда дорогая операция, для аналитических запросов - всегда требует их переписывать.
Ну, отчёты-то бизнесу нужны те же самые. Соответственно, в моём подходе переписывать придётся только один микросервис, который их выдаёт. В этом и смысл, скрыть детали реализации за API микросервиса.
А вот обновление пяти-десяти сервисов - это весьма тривиальная задача, кстати. Что там сложного-то?
Это… интересная позиция. Обычно обновить один сервис намного проще десятка сервисов. В том числе и потому, что за этим десятком стоят разные команды, у которых свои приоритеты, и не все из которых готовы одновременно броситься переписывать конкретно эту часть функционала. Соответственно, выкатывать эти обновления по готовности не получится - их нужно переключить на новую схему/БД одновременно. А это значит нужно долго ждать пока этот функционал будет готов во всех и потом одновременно их выкатить… и потом откатить все, если что-то пойдёт не так - а оно обязательно пойдёт не так, и чем больше участников тем выше вероятность что что-то сломается. В целом, именно так и выглядят проблемы "распределённого монолита".
О, я понял, где у тебя иллюзии. Нет, в современных БД в IO уже довольно сложно уткнутся, проблема обычно в ядрах и в оперативке. И тут гораздо дешевле сделать выборку прямо из БД и потом сделать массовый update, нежели прокинуть десятки миллионов записей через какой-нибудь микросервис. На сериализацию-десериализацию уходит очень, очень много ресурсов, поэтому любые массовые выборки стоит делать из своей БД, а не через микросервис. Попробуй протащить через сеть protobuf на 10 млн. записей (даже кусочками по 10k) и замерь, сколько у тебя уйдет ядер на это развлечение. Увы. но все современные протоколы обмена микросервисов не очень быстрые и с кучей дополнительных проблем (но почему gRPC почти всегда плохой выбор - отдельная тема).
Ну и в конкретно этом случае у тебя еще и логика "сервиса доступа к базе" будет зависеть от всех сценариев реконсиляции, что увеличит зависимость.
И это не какой-то уникальный случай, это как раз нормальный кейс, который возникает всегда при работе со сколь-нибудь большими объемами данных и пристойной нагрузкой.
Обычно обновить один сервис намного проще десятка сервисов
Не, без разницы. Всегда нужно думать про миграцию данных, фичафлаги, совместимость и так далее. И когда вокруг этого сделан тулинг - то обновление делается тривиально. А если нельзя договориться с соседними командами - то это проблема культуры и она не решается техническими средствами и будет проблемой вообще всегда. Впрочем, в твоем сценарии "прокси к данным" она будет сказываться вообще постоянно, так как любое изменение логики реконсиляции потребует (с большими шансами) изменение этого "прокси-сервера". А это происходит гораздо чаще, чем, ээ, переход с одной СУБД на другую.
И, кстати, нет никакой проблемы выкатывать весь указанный функционал кусочками, с чего бы что-то не получилось?
Смотря как делать. Если сделать общий Redis для всего проекта - так и получится, но так делать не нужно, у каждого микросервиса Redis должен быть свой собственный.
Почему должен? Если Redis используем для взаимодействия (pub-sub, общие блокировки и т.п.), то как раз нужен общий Redis. А если это локальный кэш, то зачем Redis?
контрактами и версионированием формата передаваемых сообщений
А ты пробовал это делать корректно? Там сразу вылезает взаимозависимость всех консюмеров по деплою и версионированию, это не лучше любой интеграции через view, только еще и миграцию хранимых данные сделать нельзя, что сильно все усложняет.
То, что ты описываешь - обеспечивает потерю порядка и невозможность отката, так делать не надо )
На БД обеспечить совместимость гораздо проще, чем на очередях )
Почему должен? Если Redis используем для взаимодействия (pub-sub, общие блокировки и т.п.), то как раз нужен общий Redis.
Если это просто pub/sub, то в рамках этого обсуждения он попадает в категорию брокеров, а не общей БД.
А если это локальный кэш, то зачем Redis?
Затем, что бывает потребность в общем кеше для всех инстансов сервиса (напр. для учёта рейт-лимитов).
А ты пробовал это делать корректно?
Пробовал. Потому и сразу сказал, что это очень больно. Но вариантов обычно нет - ты меня пока не убедил, что общая БД это хорошая альтернатива, хотя я очень хочу в это поверить (потому что больно, да). :-)
Там сразу вылезает взаимозависимость всех консюмеров по деплою и версионированию
А вот эту мысль я не понял. Консьюмеры друг от друга обычно всё-таки никак не зависят, они зависят от паблишера. От одного конкретного паблишера и одного конкретного сообщения, которое он начал публиковать в новом формате. И никаких проблем обновить консьюмеры независимо друг от друга обычно нет. Другое дело, что если консьюмера обновить до паблишера, то новый формат он полноценно увидит уже на проде, и баги могут вылезти тоже на проде. А если обновить после паблишера, то какое-то время старый консьюмер просто не будет обрабатывать новые данные и потом новый может немного завалить новыми данными при первом запуске. В общем, сложности тут есть, но и подходы как это решать тоже есть.
То, что ты описываешь - обеспечивает потерю порядка и невозможность отката, так делать не надо )
Это тоже не понял, что тут имелось в виду?
На БД обеспечить совместимость гораздо проще, чем на очередях )
А в это очень хочется поверить, но пока ещё не получается. :) В простом монолите - безусловно, в модульном монолите - возможно но не уверен, в микросервисах - выглядит очень стрёмной идеей.
О, про зависимости при обмене через брокер весело.
1. У тебя для сценария с кафкой продюсер зависит от реализации консюмера, так как должен формировать ключ партиционирования в зависимости от требований консюмера.
2. Если ты хочешь что-то изменить на продюсере для одного консюмера, ты обязан убедиться, что все прочие консюмеры эту правку правильно отработают. Т.е. у тебя изменения одного консюмера зависит от всех прочих консюмеров, это очень жестко. Для http/grpc можно иметь несколько версий endpoint, а для брокеров это не пройдет (
3. С брокером ты не можешь обновить "события в пути", т.е. тебе придется как-то реализовывать сложную логику, ээ, договора между всеми консюмерами и продюсером о смене версии события. Я знаю только один гарантированный сценарий для этого, но его никто не использует, так как слишком сложно )
Толково
Спасибо за статью. Некоторые уточнения.
MSA это прежде всего про deployability: независимые команды, отдельные компоненты. Ответ на Conway's law. Остальные качества имеются и в других архитектурах.
CQRS не обязательно про данные, это еще и способ распилить мега-сервисы.
OpenTelemetry это скорее стек - набор сервисов, агентов и библиотек. Похоже, вы не имели с ним практики. Tempo, например, показывает трассировку и граф прямо в Grafana, нет нужды в Jaeger и Zipkin.
MSA это, в первую очередь, про упрощение арх.контроля и, реже, про возможность работать с разными НФТ для разных частей продукта (скорее про безопасность и надежность, чем про масштабируемость). Других плюсов там особо и нет. Но какой-нибудь ArchUnit вполне решает задачу контроля.
Автор статьи, подозреваю, вообще никогда не видел ни MSA, ни монолита. Так как при наличии хоть какого-то опыта в статье было бы хоть что-то содержательное )
Проблема прежде всего архитектурная. Там где микросервисы создают проблемы - там они скорее всего и не нужны. Правильная архитектура - модульная, с распределенным выполнением слабовзаимодействующих отдельных модулей, там где это приносит выгоды. Да даже монолит целиком может выполняться распределённо, в режиме разных ролей.
Проблема №1, Проблема №2, ... Проблема №N
а теперь представить сколько должно быть кода чтобы решать (не решить, а хотя бы пытаться) все эти проблемы. Заниматься бизнес логикой будет некогда.
Интересно что хотел сказать автор? Доказать утверждение:
И мечта превратилась в сложную, многомерную головоломку.
Представьте что вы имеете машину: Kia Picanto. Она вас довозит с точки А в точку Б и все бы ничего, но вот ваша семья растет и вас уже не двое а пятеро. Приходится делать две ходки чтобы всех перевезти. А теперь у вас еще и дача появилась, нужно туда инструменты перевезти, а оттуда 3 мешка яблок забрать. Да и дорога на дачу - ямы да ухабы. Решение? Меняете вы свою малютку на Dodge Ram. Все проблемы решились на раз. Большая, вместительная, мощная, проходимая! Но, содержание стало дороже, бензина жрет больше, в городе не развернуться, а найти стоянку вообще отдельная беда.
Это я к чему? Не существует серебряных пуль. Решая одну проблему, мы обретаем другую.
только некоторые монолиты бывают покрупнее целой кучи микросервисов, вы не видели из какого объема исходников компилируется какой-нибудь не самый навороченный андроид?
Потом вроде как монолит или микросервисы не покупают, а строят.
А проблемы действительно по одной не ходят.
Это просто мы ещё не дожили до адаптивных машин-трансформеров
Решая одну проблему, мы обретаем другую.
Ну а какие проблемы решают микросервисы? Горизонтальное масштабирование? Монолиты это умеют. Распределенная разработка? Грамотно спроектированный модульный монолит решает эту проблему. Деплой? Даже проще развёртывать и контролировать единый набор бинарников.
Есть специфические кейсы, когда например что-то требует и тащит за собой кучу конфликтующих зависимостей. Вот тот случай когда это выгодно отколупать и завернуть в персональный докер, выставив наружу пучок интерфейсов.
Вы же понимаете что с такими же аргументами можно объяснить что например те же DE на самом деле не нужны и все проблемы, которые они решают, можно решить как-то по другому.
И точно так же можно объяснить что современные ЯП и фрэймворки на самом деле не нужны. Ведь можно же обойтись и без них.
Естественно можно обойтись и без микросервисов. Но в каких-то ситуациях они удобнее. Вот и всё.
Но в каких-то ситуациях они удобнее.
Ну а я о чём? В каких-то ситуация они удобнее. Но вместо этого все ломанулись натягивать микросервисы на все ситуации подряд. Закономерно заимев кучу новых неоправданных проблем.
Кто "все" ломанулись? Да ещё и на все ситуации подряд? Мне реально интересно на основании чего делаются такие заявления.
Мне реально интересно на основании чего делаются такие заявления
Хм. На основании опыта. Вы-то в продуктовой компании работаете, судя по всему, у вас только ваши продукты. Я вот на разные проекты перехожу. Микросервисы суют везде. У меня за последнее десятилетие было с десяток разных проектов, все они были с микросервисами, только один из них реально в микросервисах нуждался, а два проекта были микросервисами убиты.
Хм. На основании опыта
Серьёзно? На основании личного опыта? Без всякой статистики или хотя бы репрезентативной выборки? Вы просто берёте и экстраполируете свой личный опыт на весь мир?
Вы-то в продуктовой компании работаете, судя по всему, у вас только ваши продукты
Я много где работал и общаюсь с кучей людей из разнообразных компаний. Но мне не кажется хорошей идеей экстраполировать это на всех.
У меня за последнее десятилетие было с десяток разных проектов, все они были с микросервисами, только один из них реально в микросервисах нуждался, а два проекта были микросервисами убиты.
Десяток проектов за десчтилетие. Это ваша "репрезентативная выборка"? Сколько разных фирм это было? Разных городов? Разных стран? Разных стеков?
Я много где работал и общаюсь с кучей людей из разнообразных компаний. Но мне не кажется хорошей идеей экстраполировать это на всех.
Просто не надо понимать квантор всеобщности буквально.
Проблема действительно существует. Притом "сующих" тоже можно понять: сделаешь всё как надо - а что тогда в резюме напишешь?
Гигабазированная статья, приятно читать новичку в мире микросервисов
Светлые головы, промытые идеями о "микросервисах", готовы титанически преодолевать какие угодно трудности, только чтобы в очередной SaaS системе, которую они строят, была "микросервисная архитектура". Микросервисы ради микросервисов, правильной дорогой идём!
Классика жанра:
https://www.youtube.com/watch?v=y8OnoxKotPQ
Взаимодействие микросервисов: проблемы, решения, практические рекомендации