Re[11]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.04.25 22:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

G>>А давай прикинем как это будет в MSA. там будет точно такая же коллекция в одном из сервисов, и менять её будет не поток, порожденный программистом, а поток порожденный хостом для обработки запроса. А все остальное будет то же самое. И, как в случае монолитного приложения, так и в случае MSA падения как такового не будет. Восстановление после такого falure возможно только сбросом состояния путем насильного перезапуска, например по хелсчеку. Разница в случае MSA будет только в том, что будет перезапущен один маленький сервис, а не толстое приложение. Но при этом весь сценарий работать не будет, пока микросервис с разделяемой коллекцией в памяти не оживет.

S>Всё верно. MSA не гарантирует безошибочности. MSA гарантирует, что падение не затронет сценарии, в которых микросервис не задействован.
Смотря что значит "не затронет". Если сервис А зависит от срвиса Б, а сервис Б содержит ошибку, даже неважно приводящую к падению или нет, то и А не будет корректно работать.
Падение — не самая страшная часть, даже в проде. Плохо когда: после падения не может подняться, или вместо падения не работает корректно — висит в ожидании или отдает некорректные данные. Причем второе при несинхронной разработке весьма вероятно.

G>>Надежный способ решения это использовать какое-то хранилище, которое поддерживает acid транзакции. Но это и в монолите возможно. Причем в монолите есть простор для оптимизации. Так как можно использовать STM например. Но на практике, когда экземпляров приложения может быть больше одного, все разделяемое состояние надо хранить во внешних, желательно транзакционных, хранилищах.

S>Либо отказываться от разделяемого состояния. Потому что людей, умеющих изготовить полноценное клиент-серверное приложение внутри ACID-хранилища, на рынке не осталось (даже если предположить, что они когда-то были)
Его же не надо "внутри", надо чтобы разделяемое состояние польностью сохранялось и обрабатывалось ACID хранилищем, желательно внешним по отношению к самому приложению. Чтобы приложение можно было безопасно масштабировать и перезапускать.

G>>При горизонтальном масштабировании к этому все и придут обязательно. В принципе грамотный архитектор должен сразу на такое натолкнуть.

S>Вопрос открытый. Чего я только не видел в энтерпрайзе, при самых грамотных архитекторах.
Бывает конечно всякое, и архитекторы, которые не понимают как и почему базы работают. Но в целом это подход по умолчанию: "давайте состояние приложения положим в базу". Раньше по умолчанию выбирали РСУБД, но сейчас уговаривать приходится.

G>>Опять-таки MSA ничем не помогает в этом случае. Без разницы будет мусор писать в базу микросервис или монолит.

S>Нет, разница принципиальная. Микросервис физически не может записать в чужую базу кривую запись о переводе денег.
Ну физически то может. Но сделать это гораздо сложнее чем в монолите.
Но у этой медали есть и обратная сторона: если у вас разные базы, то сделать джоин в них крайне сложно. Задачи которые в монолите бы решались одной строкой в SQL в MSA начинают требовать тонны кода.
Пример реальный: профили пользователей лежат в одном сервисе, данные о туристических маршрутах в другом. Важная часть логики: для несовреннолетних доступна одна часть маршрутов, для соврешеннолетных — другая. Есть еще другие признаки для фильтров: по регионам, интересам итд.
Теперь нам надо сделать рассылку, подобрав подходящие маршруты для клиентов.
В монолите — один джоин. В MSA — пожалуйста напишите тонну кода.
В реальности ситуация была еще хуже. Данные о бронях групп и совершенных путешествиях лежали в третьем сервисе. И конечно же надо было из предложений исключить тех кто уже ездил.


G>>Так это самые важные вопрос. Я еще раз напомню тезис, который в этой теме и другие коллеги подтверждают: MSA это больше про оргструктуру, а не про архитектуру. В интернетах предлагают "правильную" MSA с разделением микросервисов по разным репозитариям исходного кода. Как в этом случае обеспечить синхронность изменений разных микросервисах, если изменяемый бизнес-процесс затрагивает несколько таких микросервисов?

S>Никак — MSA, собственно, и обеспечивает отсутствие синхронности. Это преимущество, а не недостаток.
А в чем собственно преимущество? Ну если в деньгах посчитать.

S>Изменения в бизнес-процессе накатываются постепенно: сначала мы обучаем новостям самый "нижний" микросервис в топологически отсортированном списке микросервисов, затем — чуть более "верхние".

S>Изменения в БП становятся видны в тот момент, когда мы выкатываем изменения "корневого" микросервиса, который оркестрирует весь БП.
Если сервисы имеют строгую иерархию и представляют из себя "слои" приложения, то возможно это и так.
Но сразу три замечания:
1) это цикл внедрения фичи удлиняет. Так как скорости выгоднее делать "вертикальное" деление проекта.
2) Это противоречит мысли самодостаточности сервиса. "Верхний" не работает без "нижних", а "нижние" не нужны без "верних".
3) При падении\ошибке в "нижних" "верхние" тоже ломаются.



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

G>>В msa весьма вероятна ситуация, что в принципе невозможно собрать работающее сочетание микросервисов. Я такое на практике видел. Было три микросервиса (А,Б,В) и два процесса(1,2), затрагивающие три сервиса. В один момент было так, что: А/HEAD, Б/HEAD, В/HEAD~1 работал сценарий 1, но не работал 2. А/HEAD, Б/HEAD~1, В/HEAD работал 2, но не работал 1 и при этом же А/HEAD~1, Б/HEAD, В/HEAD также работал 2, но не работал 1.

G>>И каждый разработчик миросервиса доказывал что "work on my microservice" (современный аналог work on my machine)

S>Это организационная проблема. В монолите все эти команды делали бы ровно то же самое ровно с тем же результатом.
Это в монорепе гораздо сложнее, до уровня "почти невозможно", так как версия всех компонент в монорепе всегда одна. Если вы не балуетесь выносом бизнес-логики во внешние пакеты.

S>А, ну и, возможно, неудачно были проведены границы между микросервисами. Это — отдельное искусство, настолько редкое, что я, ЕМНИП, видел только одно правильное решение (и с десяток заведомо неверных).

Может быть мне так везло, но я участвовал в 6 проектах с MSA и у десятка "стоял рядом" и везде были такие проблемы.
Более того я два проекта с MSA запилил назад в монолит и стало всем лучше. Но там четко одна команда работала над проектом.

G>>Дисциплина, современные среды, языки и библиотеки (я не про Go) позволяют создавать достаточную изоляцию и внутри монолитного приложения, не получая огромных затрат на внесение зависимостей когда они нужны.

S>Может быть. Я не говорю, что MSA — единственный верный способ деятельности
Я делаю более сильное утверждение: MSA пригодна только там, где есть соответствующая оргструктура: много несвязанных команд, каждая из которых работает на процессами, слабо связанными друг с другом. Такое в банках и маркетплейсах такое очень часто встречается, а они составляют основу русского бигтеха.
А например в корпоративных системах оно не надо, как при кастомной разработке, так и при разработке тиражируемого продукта.

G>>Доункаст к чему, если у него нет паблик класса, к которому даункастить?

S>Почему вы думаете, что нету?
S>А если нету — всегда можно запилить reflection. Пытливому уму все средства хороши.
Ну я точно также могу сказать про запись в чужую базу. Оно ведь все равно деплоится все в одно приложение докера\кубера и контейнеры видят друг друга. И все равно разраб сталкивается с тестовой средой, где может "в дикой природе" наблюдать какие еще сервисы работают и с какими хранилищами.

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

S>Как раз в JS-то можно. Но, опять же, можно!=делают.
Так и в MSA изоляция зачастую условная. Да, у каждого сервиса база своя, но сервер БД один. Дорого поднимать несколько экзепляров даже постгреса. И учетные данные одни.
Если разработчикам не прививать дисциплину, то никакая изоляция не поможет.

G>>Так можно и в базу другого микросервиса полезть.

S>Невозможно. Базу чужого микросервиса даже не видно. И даже если вдруг чужая база лежит на той же машине, то доступ к ней выдан другому сервис-аккаунту, чем тот, под которым бегает этот микросервис.
Ну-ну. Это на практике может быть в бигтехе, где базы нарезаются отдельной командой и не входят в профиль деплоя. Но пока все приложение это одни набор yaml файлов для docker\kuber — пролезть можно. Опять-таки если недостаточная дисциплина.

Один раз премии лишить за рефлекшн без необходимости и сразу желание пропадет так писать.

G>>В случае единой репы и нормального архитектора — на ревью бить по рукам (или по лицу) за такой код.

S>Это всё хорошо работает до определённых размеров кодовой базы, команды, и уровня ответственности за промахи. Там, где за ошибки принято тюремное заключение или суровые штрафы, делают именно так, не полагаясь на бдительность peer review и личность архитектора.
Ну давай честно: есть предел размера команды или предел структуры управления для монолита. С этим никто не спорит.
Далее возможно развитие или по пути MSA или по пути "ядро\платформа и прикладная часть".
Но до этого предела монолит превосходит MSA по любым параметрам.

G>>Я именно об этом и говорю. Знаю один банк где над таким ядром-"микросервисом" трудится команда из 40+ только программистов. То есть ни разу он не "микро", о чем я и говорю. А выдача кредитов это вообще с десяток связанных процессов, на каждом из которых команда в 10+ человек. То есть их тоже "микро" назвать сложно.

S>Так "micro" это же не про размер команды. А про "площадь поверхности".
Не очень понятно в чем она измеряется.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.