Информация

Дата основания
Местоположение
Россия
Сайт
team.mail.ru
Численность
5 001–10 000 человек
Дата регистрации

Блог на Хабре

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

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

Да-а-а? Представим себе что это микросервис авторизации. Что, скажете нет, это не микросервис? Или его неработоспособность не отразится на работе всего приложения? Ха три раза.

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

fixed

И наоборот, если у меня один модуль (функция) сбоит, то это не значит, что оно приведет к сбою всего монолита. Тогда в каком месте у микросервисов тут выше доступность?
Я бы на самом деле сформулировал бы как-то так — микросервисы должны позволять избавиться от single point of failure. Путем например легкого и быстрого параллельного развертывания нескольких копий. А сами по себе они точно также могут быть этой SPOF, как и модуль в монолитном приложении. Ни больше, ни меньше.

Т.е., не большая доступность, а простота обеспечения этой доступности, путем применения таких-то решений.

А что мешает развернуть несколько копий монолита?

Ну, несколько копий монолита вероятно сожрут несколько больше ресурсов. А так ничего не мешает.

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

Не очень понял вас.


  1. Допустим в микросервисах есть точка отказа. Мы дублируем микросервис с этой точкой — профит.
  2. Допустим в монолите есть точка отказа. Мы дублируем монолит — профит.
    В чем разница?
Что тут понимать? Монолит жрет 16Gb памяти. Микросервис, который точка отказа — 128Mb. Дублируем монолит — 32Gb потребности, дублируем микросервис — 16Gb + 128Mb*2. Все числа только как пример.

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

А я разве обещал производительность?

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

Ну и да, сетевое взаимодействие вместо вызовов внутри процесса — это всегда минус микросервисам, без вопросов.
Ну и да, сетевое взаимодействие вместо вызовов внутри процесса — это всегда минус микросервисам, без вопросов.

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

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

вспоминается реклама Инферно как там всё просто так как есть только файлы.

с тем же успехом можно COM использовать — даже проще будет
Монолит жрет 16Gb памяти. Микросервис, который точка отказа — 128Mb.

Это что ж Вы такое делаете? Обычно 500 Mb под инстанс монолита более, чем хватает.
Хоть числа и только как пример, но их соотношение вызывает вопросы… На микросервис конечно меньше памяти приходится, но во-первых не в 100 с лишним раз, а раз в 5-10, да и сумма памяти, потребляемой всеми микросервисами скорее всего будет в пару раз больше, чем нужно монолиту.

>Это что ж Вы такое делаете?

То, что написано в ТЗ, а что?

>Обычно 500 Mb под инстанс монолита более, чем хватает.

Вот прямо так, без понимания того, какие задачи решаются? Хм.

У Вас, видимо, есть несколько примеров веб-приложений, которые могут по делу откушать 16 Gb оперативки?

Web приложений? С чего вы взяли, что обсуждаемые микросервисы каким-то боком специфичны для веба? И тем более — что монолитные приложения ограничены им?

В статье только аббревиатура HTTP встречается 6 раз, не считая множества других признаков… Так что уместнее вопрос, с чего Вы взяли, что тут обсуждается что-то кроме веб-приложений?

Видите ли, я вот видел массу приложений, где http налево и направо — просто потому, что SOAP это обычно через http. Но они ни разу не являются веб-приложениями.

И мы тут, между прочим, corba обсуждали. Она видимо тоже веб.

А заодно, кстати, видел веб-приложения, которые совершенно по делу жрут 32 гигабайта и более — самый яркий пример это пожалуй IBM BPM. Всего-то на 50 пользователей, примерно.

В классических клиент-серверных приложениях все эти микросервисы 10 лет назад уже были, может ещё и раньше были… чего тут обсуждать то? Или Вы их теперь через Docker стали разворачивать? xD


видел веб-приложения, которые совершенно по делу жрут 32 гигабайта и более — самый яркий пример это пожалуй IBM BPM. Всего-то на 50 пользователей, примерно.

Судя по описанию, какая-то web-IDE для описания бизнес-процессов. Хз как она умудряется столько памяти жрать… Интерфейс весь (сохранение взаимного расположения, drag-n-drop, etc.) можно на клиенте отрабатывать, к серверу запросы только при явном сохранении или авто-сохранение раз в минуту, плюс подгрузка запрашиваемых данных в JSON.
Я даже демо-видео посмотрел ради интереса и в упор не вижу с чего бы воркеру этой штуки хотя бы 1 Gb по делу съесть, не то что 32. Просто это IBM и им наплевать сколько вам придётся памяти докупить xD

Кстати, посмотрел требования к IBM BPM Advanced 8.5.7


For 64-bit systems, the minimum system memory requirement to support a clustered configuration with a deployment manager, node agent, and single cluster member is 6 GB. However, for optimal performance the recommended configuration is 8 GB.

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

Не описания, а описания и выполнения. И да, процессы тоже жрут память.

Намекаю: если вы чего-то в жизни не видели, это не значит, что этого не бывает.

Если в рекомендациях у IBM что-то написано — это не значит, что этому нужно верить.

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

Ох, как Вас бомбит, даже ссылку на официальные system requirements заминусовали… ну и ну.


Не описания, а описания и выполнения. И да, процессы тоже жрут память.

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


Намекаю: если вы чего-то в жизни не видели, это не значит, что этого не бывает.

А я и не спорю, что бывает. Но когда такое бывает, всегда можно улучшить и привести систему в более адекватное состояние, было бы желание и ресурсы.


Если в рекомендациях у IBM что-то написано — это не значит, что этому нужно верить.

Вот как! То есть Вы считаете, что когда разработчик заявляет, что для оптимальной работы его системы требуется N памяти (где N — это дофига Gb), а по факту система потребляет 4*N, то это адекватная работа системы? IBM слишком высокомерна по отношению к своим пользователям, примерно как Вы — к собеседникам )

Вы начали с самого начала делать выводы, исходя их взятых сугубо с потолка чисел, которые были просто примером. При этом я вам сразу сказал — вы пытаетесь что-то додумать, ничего не зная про требования. Т.е. вообще ничего.

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

Есть еще одна проблема. Даже условно нелсложные веб-приложения со временем обрастают "инфраструктурой". Нужно поставить супервизор для воркеров. Нужно ставить всякие специфичные екстеншены/приложения для обработки юзерских аватаров, парсинга больших прайсов от поставщиков и 100500 прочих вещей которые нуны монолиту. И тут приходит час Ч, когда вы решили замасштабироваться горизонтально. Вы покупаете еще один сервер и начинаете на него сетапать все вот это добро, которым годами обрастало ваше монолитное приложение. Может у вас парсер прайса запускается раз в месяц, но его надо ставить. Может картинки у вас ресайзятя раз в год, но будь-добр ставь. Микросервисы за счет того что фокусируются на чемто одном требуют при масштабировании только необходимую инфраструктуру. И это безусловно плюс.

Как правило, всё это добро сводится к запуску фоновых задач посредством того же монолита. Поэтому его сетап сводится к переносу crontab, если само приложение его не заполняет автоматически.
А если парсер прайса и ресайзер картинок — это отдельные приложения, то это уже и не монолит по сути.

По мегабайту на пользователя нормально? А пользователей может быть 16 000.

Нет, если потребляемое ОЗУ растёт линейно от кол-ва пользователей, то это нормально только для какого-нибудь кеша или in-memory БД, но там есть свои приёмы, чтобы ограничить потребляемую память сверху.
А для основного приложения — это совсем ненормально… Какой-нибудь reddit-эффект и у вас серваки вылетят с out of memory?

ну если балансер всех 16к одновременных реквестов на одну ноду пустит, то так и будет))

Под одновременными реквестами Вы имеете в виду в секунду или в минуту? Вообще, когда говорят про пользователей, обычно подразумевается, что в предыдущие N минут были какие-то запросы от 16 тыс. уников. Где N — время, исходя из которого границы визита определяются, для GA и Метрики — это 30 минут iirc. Напрямую rps из этого вывести сложно, не зная специфики приложения.

Линейный рост потребляемого ОЗУ это норма, а часто идеал, которого не могут достигнуть. А под одновременными запросами имеются в виду не в секунду или в минуту, а именно одновременно обрабатываемые. Грубо, если запрос пользователя обрабатывается 100 мс, то 16000 одновременных пользователей означает 160000 запросов в секунду — в каждый момент времени обрабатывается 16 000 запросов.

А начнут серваки вылетать, ставить запросы в очередь или ещё как разумно реагировать зависит от архитектуры.
Линейный рост потребляемого ОЗУ это норма, а часто идеал, которого не могут достигнуть.

Т.е. у Вас по графику потребления ОЗУ на сервере можно сразу видеть, где были пиковые нагрузки? Ни CPU, ни Network I/O, а именно ОЗУ?


Грубо, если запрос пользователя обрабатывается 100 мс, то 16000 одновременных пользователей означает 160000 запросов в секунду — в каждый момент времени обрабатывается 16 000 запросов.

Такое количество запросов (популярность на уровне Twitter) никто в здравом уме не будет одним инстансом обрабатывать, т.е. как-то мимо начального вопроса получилось. На всю ферму серверов и 256 Gb нормально будет, а вот 16 Gb на один инстанс (а инстансов и на одном сервере может быть много) всё равно дичь получается.

Т.е. у Вас по графику потребления ОЗУ на сервере можно сразу видеть, где были пиковые нагрузки? Ни CPU, ни Network I/O, а именно ОЗУ?

И по ОЗУ тоже, собственно обычно все эти графики хорошо коррелируют между собой. Обработка одного запроса требует и ОЗУ, и CPU, и I/O.

а вот 16 Gb на один инстанс (а инстансов и на одном сервере может быть много) всё равно дичь получается.

Пускай будет 1000 мс и 10 мегабайт на запрос — 16 гигов кончатся менее чем на 1600 пользователях по факту.

Я не понимаю, почему у Вас каждый запрос обязательно добавляет N мегабайт…
Возможно, у Вас какие-то очень специфичные задачи… У меня график занятого ОЗУ в течении дня обычно больше похож на горизонтальную линию, при том, что максимальная нагрузка в 20 с лишним раз больше минимальной.

Занимает память, чтобы развернуть граф объектов узлов так на пяток тысяч, выполняет операцию, освобождает память и сборщик мусора отдаёт её системе.

Пережатие видео и картинок, загружаемых пользователями, например.

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

когда уже есть ffmpeg, imagemagick

Которое ваше приложение будет использовать как микросервисы :)
Которые не выделываются и просто называются «библиотеками» и «приложениями».

Вы загоняете себя в ловушку терминологий.
Если динамическая библиотека или консольная тулза является микросервисом, то все стоны из монитора — пустая трата времени и сил. Все и так стараются делать модульные приложения там, где это даёт прирост, и ни один здравомыслящий человек не будет агитировать радикально против модульных систем.
В противном случае понятие «микросервисы» как самостоятельный термин обретает смысл. Но этот смысл — радикальная форма модульности, которая применима к узкому числу задач разработки высоконагруженных систем. За их пределами польза от радикалов очень сомнительна.
Динамическая библиотека не является — она действует в рамках одного процесса с приложением. (Микро)сервис является отдельным приложением, работающим в отдельном процессе, к которому основное приложение обращается средствами IPC. Традиционно в выражении «используем микросервис» имеется в виду «пользуемся средствами RPC для взаимодействия», то есть средствами удаленной коммуникацией, даже если приложение и сервис работают на одной логической машине, но это не обязательно.
В этом случае ваш предыдущий комментарий. как и многие другие в этой теме, в общем случае не верен. Так как тот же самый ffmpeg не обязательно используется в качестве микросервиса, а может быть включён в приложение в качестве динамической библиотеки. Что выводит приложение из категории «монолит», не приводит в категорию «микросервисов» и позволяет максимально гибко контролировать соотношение скорость/масштабируемость и связность/распределённость.

И, кстати, выводит практически все программы из категории «монолит», ибо очень сложно найти приложение уровня пользователя, которое вообще не использует библиотеки операционной системы, на которой оно запущено.
Использование ffmpeg или системных библиотек как подключаемых не выводит приложение из монолитов. Вызовы API ОС в теории выводят, но всё же монолитом считают приложение, которое обращается только к ОС, но не к другим приложениям напрямую или через средства ОС. Есть приложения, которые ОС (или вообще биосом, а то и при страте процессора) только запускаются, а потом работают полностью автономно, но это уже какие-то супермонолиты. Считать их обычными монолитами, значит на большинстве практических задач исключить монолиты из рассмотрения вообще, подавляющее большинство систем не будут считаться монолитными.
Выводит или не выводит — это очень дискуссионный вопрос. Взгляните на это не со стороны «единой программной памяти» (которой нет, у каждой библиотеки своя куча), а со стороны гибкости масштабирования приложения. Динамическая библиотека может быть загружена и выгружена на лету, средствами ОС (как и микросервисы), и может реализовывать как сам функционал, так и работу с микросервисами. То есть правильно построенный модульный проект может быть скомпанован в очень компактный альтруистичный дистрибутив, а может быть разделён на сеть микросервисов. И я бы не сказал, что это особо сложнее, чем просто микросервисная архитектура.
Конечно, тут же можно возразить, что это уже не монолитная архитектура, но, во-первых, вы уже написали «Использование ffmpeg или системных библиотек как подключаемых не выводит приложение из монолитов.», а во-вторых, динамические библиотеки с минимальными усилиями можно* превратить в статические (больше всего возни с глобальными объектами, которые не шарятся между модулями), а те собрать в единое неделимое приложение.
*Есть исключения.

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

Если мы говорим, что «монолит» — синоним «модульного», у меня для вас плохие вести.
Которое ваше приложение будет использовать как микросервисы :)

Какая-то ложная дихотомия получается… Этак, если в проекте используется cron, то он уже микросервисным резко становится? xD

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

"Резко" микросервисным не становится. Смотря что крон запускает. Если какую-то часть приложения, то приложение уже не монолит.

Тут зависит больш ене от того, что крон запускает, а о того кто кронтабы формирует.

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

Рискну: экономическая составляющая = рентабельность = стоимость?

Это довольно общие понятия. Можете пояснить конкретнее?

Имелось ввиду что это попросту может быть дорого.

Дополню ваш комментарий Ссылка статьей

с разоблачением мифов относительно микросервисов.
Да-а-а? Представим себе что это микросервис авторизации.

Будет работать публичная часть приложения. У вас это только форма аутентификации? Но ведь будет работать!
А почему она в монолитном приложении не будет работать? Форма будет открываться, точно также.
Потому что приложение работать не будет.
Почему это приложение работать не будет? все будет работать кроме формы аутентификации.

Наверное, имеются в виду отказы, приводящие к падению/недоступности приложения.


В одном случае упадет/недоступен только микросервис, в другом — весь монолит. Как то так.

Так и с монолитом также, не будет работать авторизация, а все остальное будет.
Монолит на то и монолит, что он или работает, или нет. Грубо, или слушает 80-й порт, или не слушает.
Может один endpoint(controller/action) не работать, а все остальные вполне могут работать.

Скажем в случае PHP, так и будет. А в случае компилируемых приложений, один раз упав приложение уже само не поднимется и станет недоступно по всех ендпойнтах.

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

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


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

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

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

За что минус не пойму, аргументируйте чтоли


Не ставил минус, но, видимо за это:

Скажем в случае PHP, так и будет. А в случае компилируемых приложений, один раз упав приложение уже само не поднимется и станет недоступно по всех ендпойнтах.


Автоподъем сервисов реализуется нынче в любом продакшене. Хоть с микросервисами, хоть с крупносервисами.
Средствами самого приложения?

Да, так тоже делают. Скажем, если в том же C# не использовать небезопасного кода, то довольно хорошо отрабатывает монитор в отдельном appdomain.


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

Средствами самого приложения?


Иногда. Чаще внешними средствами.

Такое впечатление, что вы в глаза не видели микросервисы, если считаете, что оно там как-то само поднимается.

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

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

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

Речь шла о том, что если упадет монолит, то пока его не понимут (админы, системные утилиты, верховные силы) он будет лежать. И будет лежать весь полностью.

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

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


Не все так просто.

1. Все до единого микросервисы поднимаются довольно долго. В сумме это заметно дольше, чем один монолит.

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

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

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

Вы не там ищете преимущества микросервисов.

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

И за эти преимущества приходится платить менее оперативным перезапуском именно системы микросервисов и задержками в их связанностях. У монолитов все проще и быстрее.
угу, проще и быстрей. Есть опыт деплоя монолита на продакшен ~ 3 часов.
угу, проще и быстрей. Есть опыт деплоя монолита на продакшен ~ 3 часов.


Компилировали новую, предварительно опустив старую версию???
Или это был recover аварийно прерванных транзакций?

Уверяю вас, проблем при старте микросервисов, по причине более сложной их связанности — намного больше.
В основном синк файлов на 2 дц.
В основном синк файлов на 2 дц


И каким боком это проблема монолита?

Синк файлов на 2 дц можно делать в том время, когда старая версия еще работает.

Пока перезагружает всё приложение работать не будет :) Давайте только не углубляться, что у приложения несколько воркеров и запрос на конкретный ендпоинт будет ложить только один воркер, а остальные продолжат работать.
Откройте для себя, например, Java и Spring, прежде чем утверждать подобное.
Вы не путаете «не работать» и «работать не корректно (на корректные запросы возвращать ошибку, например)»? Я говорю о ситуации «не работает» — API не доступен клиенту, отправляет запрос и или вообще не получает ответа, или получает ответ от инфраструктуры (сетевого стека ОС, например) «получатель не найден», «не могу установить соединение», «получатель разорвал соединение» и т. п. Не, может быть, конечно, несколько ендпоинтов, например основное приложение на 80 порту, а авторизация на 443 (защищаем только пароль/ключ клиента, а сессионный токен — нет) и 443 не работает (приложение при старте проигнорировало, что не смогло забиндить), но обычно всё же один делают.

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

А разве развертывание по частям не несет риски нарушения Согласованности (Consistency)?

А почему никто не пишет, что при разделении монолита тотально падает время отклика системы? Вызов, который ранее случался через стек за несколько тактов теперь передается аж по сети, да еще с сериализацией в текст (http же).


Также возможность горизонтально масштабировать случается в ущерб возможности вертикально.

Согласен. Замолчали о важном факте.
Я считаю это необходимо добавить в минусы микросервисов.

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

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

У микросервисов у каждого свое хранилище, они не конкурируют, а у монолита одно хранилище как правило, а если их несколько и с каждым работает независимая часть монолита, то это уже не монолит получается :)
Стоп, стоп. Вот не надо считать разработчиков монолита идиотами априори! )))

Если десять запросов можно сделать асинхронно — они и в монолите могут быть сделаны асинхронно — это не преимущество микросервисов.
Преимущество микросервисов — у каждого свое хранилище, запросы к ним не конкурируют.
Точно также и в монолите, есть сервисы(не микро) и они делают запросы к разным хранилищам.
Именно. Совершенно не понял, почему это я не могу сделать даже в рамках одной базы несколько файловых групп, размещенных на разных физических дисках, которые не конкурируют друг с другом за IOPs? Это делалось много лет назад, и делается.

А вот представить себе сто отдельных оракловых серверов вместо ста баз на одном физическом сервере мне как раз будет сложно — потому что это создаст лишние немалые расходы на их поддержку.
Конкурентность имелась в виду прежде всего транзакционная, а не за физические ресурсы.
Параллельное выполнение транзакций вполне себе решается в рамках баз данных уже много лет как. Микросервисы тут ничего нового ровным счетом не дают. Еще раз — не надо представлять себе монолит как скажем один класс из 100000 строк. Такого не бывает. Даже в самом монолитном приложении есть модули, которые все равно независимы друг от друга. Иногда даже могут быть отдельно перезапущены. Это было возможно до того, как вообще появилось слово микросервис.
Микросервис — разновидность сервисов. Если приложение разбито на сервисы, то оно уже не монолитно, а микро сервисы или «макро» — уже нюанс.
Нюанс в том, что не разбитых на части приложений уже лет 30-40 как не делают вообще. Оно может быть монолитом в том смысле, что деплоится целиком — но при этом вполне состоять из частей. У него один общий файл конфигурации — но оно все равно состоит из ядра и плагинов.

Вот именно! Почему-то многие проводит дихотомию "микросервисы — монолит", забывая об остальных вариантах архитектуры. И выдают за достоинства микросервисов любые недостатки монолита.

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

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

Насчёт сериализации в текст — вот вообще не понял. Если у вас были бинарные данные, они точно так же и останутся бинарными. Если нет, то там тот же незначительный оверхед.
Все еще не понимаю почему SOA и микросервисы идут параллельно? Кто-то считает их чем-то отдельным, другие ближе к истине и считают микросервисы подмножеством SOA, но на самом-то деле это одно и то же ведь. Где грань находится?
Да нет ее, этой грани. Знаете, мне как-то попался «рекламный» документ, о том, как мы будем внедрять микросервисы у себя в компании. Я его читаю, и вижу, что в нашем приложении, которое Java и OSGI, уже давно все микросервисы.

Вспоминаю, что было лет 10 назад — и понимаю, что EJB beans тоже были в значительной степени микросервисами. И те, и другие, не деплоятся сами по себе куда-то, а работают в контейнере — но это дает свои преимущества, скажем в плане мониторинга.

То есть, самой подобной архитектуре — ей сто лет в обед. Можно еще corba вспомнить, например. Скока это лет назад?

А дальше все зависит от того, где вы проведете границы между сервисами — может получиться хорошо, а может и не очень. Принципы — практически теже самые, что применяются «в малом» — сервис должен быть сильно связан внутри, и слабо снаружи. Так это верно для любого модуля, и это все знают.

Вот именно.
Отсюда возникает логичный вопрос: откуда такая шумиха?

Сам бы хотел это знать :). Но вообще есть одно предположение — произошло некоторое развитие средств виртуализации, и стало очень просто задеплоить еще одну виртуалку с готовым к работе linux, или docker контейнер, где уже развернута база данных или apache, или что-то еще подобное. В мире Java это случилось лет 10 назад, в виде EJB или OSGI, и поэтому там микросервисы уже давно достарочно типичны. А щас стало возможно развернуть что угодно, одним пинком. Шумиха может и несколько излишняя, но какой-то смысл во всем этом несомненно есть.

Появились средства контейнеризации, облака — и достали из закромов старый прием и назвали по-новому.

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

А по мне очевидно — о деньгах.
Ребекка Парсонс считает очень важным, что мы больше не используем даже внутрипроцессное взаимодействие между сервисами, вместо этого для связи мы прибегаем к HTTP, который и близко не бывает столь же надёжен.
Спрашивается, ради чего необходимо отказываться от технологии, которая позволяет сэкономить время и ресурсы? Очевидно, деньги. И дело не столько в экономии самих тактов, сколько в создании новых квазипродуктов и захвате рынка у классических инструментов. Что мешает создать генератор API под все платформы и языки над MPI, к примеру? Почему нет? Видимо, потому, что рост рынка будет незначительным, а все деньги уйдут разработчикам MPI.
Можно еще corba вспомнить, например. Скока это лет назад?

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

О преимуществах микросервисов стоит судить не с точки зрения "модули, которые общаються по хттп вместо in-process call, зачем?", а с точки зрения облачного развертывания. Это скорее набор микро-приложений (а не модулей), которые друг с другом взаимодействуют мало и редко.


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

Т.е. содержание облака с двумя микросервисами, которые получают 1000000 и 1000 запросов за день будет дешевле содержания облака с двумя монолитами, которые получают 500000 и 500 запросов за день?

У васв облаке сколько угодно инствнсов микросервисов (пропорционально нагрузке), и у вас ровно ресурсов под каждый столько, сколько надо. Монолит же будет есть больше ресурсов, так как он будет готов как к миллиону переводов, так и к миллиону курсов валют, что оверхед.

Вы утверждаете, что он, при низкой нагрузке, будет жрать больше ресурсов, чем система микросервисов.
"Размазывая" работу монолита по микросервисам вы не уменьшаете общую нагрузку.
Монолит не будет есть больше ресурсов только потому что он монолит.
Монолит потребляет столько же ресурсов, как и микросервисы при одинаковой нагрузке. Просто некоторые части из которых он сложен буду простаивать.
Так что никакого оверхеда нет.

Разве часть монолита которая простаивает не будет потреблять лишнего?

А что именно в простаивающем приложении может потреблять ресурсы?
Мне приходит на ум только "лишние" модули/библиотеки загруженные в память. Но это ничтожно мало.

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

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

Если монолит — полный stateless и содержит в себе только обработчики запросов — то разницы нету.
Если монолит содержит в себе какое-то состояние — явное или неявное (кеши, сессии в памяти, восстановленные CQRS агрегаты ), или поведение — задачи по расписанию и т.п. — то разница есть, и значительная.

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

Считаем, что один инстанс может обработать по CPU/IO 500000 запросов первого типа и требует 100 метров памяти, или 1000 запросов второго типа и требует 500 метров памяти. В случае монолита вам нужно будет два инстанса с 600 метров, чтобы обрабатывать 1000000 и 1000 запросов, причем 500 метров на одном из них будут простаивать, а в случае микросервисов нужно два по 100 и один на 500 и простоев не будет.
Считаем, что вам нужно не два инстанса по 100 и один 500 метров памяти, и не два по 600, а один на 700. Экономим на процессоре (и всем остальном кроме памяти), электричестве, аренде места в стойке.
Это нарушение условий, это получается что один инстанс может обработать 1000000 запросов, не упираясь в CPU/IO, хотя и потребует 200 метров памяти. По условиям вертикальное масштабирование уже невозможно практически, только горизонтальное. Монолит мы будем вынуждены масштабировать весь, в сервисах — только узкие места.
Независимая эволюция подсистем
Микросервис может развиваться и ломать обратную совместимость, не обременяя себя поддержкой старых версий, так как всегда можно оставить старую версию микросервиса работающей необходимое время.

Монолитное приложение делится на сборки (пакеты, динамические библиотеки).
Давно существуют технологии их параллельной (side-by-side) установки и выполнения.


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

НЛО прилетело и опубликовало эту надпись здесь
Пример монолита потребляющего больше ресурсов(как человеческих так и машинных) чем микросервисы:

Есть некий вебсервис, позволяет загружать и обрабатывать видео
Напиcан скажем на python, просмотров видео, комментариев и.т.д намного больше чем загрузок и обработки видео

backend можно разделить на две части — api для frontend-а и обработка видео
Обработка видео подразумевает, что система должна содержать в себе(а python, как правило. подразумевает и подгрузить) кучу библиотек, а в идеале иметь соответствующее железо

Фронтенду и бэкенду все это не нужно. Более того, они не должны страдать от бага в коде обработки видео и упасть при импортах.
При разделении на микросервисы отпадает необходимость оптимизаций и разделений на уровне кода, чтоб ни дай бог, бэкэнд api не попытался проимпортировать что-либо, что потянет за собой импорт, например opencv, которого и в помине нет на серверах api backend

Допустим баги это уже слишком, они должны выявляться раньше
Но в плане нагрузки — фронтенд и бэкэнд api нужно развернуть 100 раз, а сервис для обработки видео 10 раз
Монолит потребует загрузить тот же opencv все 110 раз. Либо быть аккуратней с импортами. А где нужно быть аккуратней — там опять таки баги

Докер же помогает поддерживать обе среды в постоянном состоянии, легко доступном как разработчикам, так и для деплоя. Отсюда и микросервис-бум. Раньше это было намного сложнее(не путать с невозможно)
Ответьте, с чего вы взяли, что «монолит» — это говнокод, в котором нет ни отлова ошибок, ни обработки исключительных ситуаций, ни, О УЖАС!, разделения на модули, которые можно обновлять по отдельности? Почему монолит — обязательно говнокод?

Вот вам контрпример, причём сильный. Никсовый bash обладает полным набором всех необходимых любому программисту функций. Большинство никсовых команд — приложения (читай — микросервисы). Иными словами, скрипты баша — одна из первых массовых микросервисных систем. Тем не менее, никто не программирует серьёзных приложений на bash. Все почему-то лезут то на плюсы, то на джаву, то на питон, то ещё куда. Вопрос: почему? И второй вслед: если эта логика справедлива на уровне построения модуля, то почему она перестаёт быть справедливой уровнем выше?

И под конец, хватит уже нахваливать докер. Это не панацея, а узко специализированная виртуальная машина под никсовые сервера. Которая за пределами своей задачи работает весьма херово.
ни, О УЖАС!, разделения на модули, которые можно обновлять по отдельности?

Если можно обновлять модули по отдельности без особых рисков — это уже не монолит.

Иными словами, скрипты баша — одна из первых массовых микросервисных систем.

Не верно. Скрипты баша — одна из первых массовых систем автоматической оркестрации микросервисов :)

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

Не виртуальная машина, а удобный инструмент для управления изоляцией процессов средствами ОС. Докер не изолирует процессы больше чем может сама ОС, вся инфрастуктура докера по сути заточена на то, чтобы было удобно запустить стандартный процесс (ну и взаимодействовать с ним) стандартными средствами ОС, передав им нужные параметры изоляции в легко понятной человеку форме. Какие ещё задачи вы пытаетесь на докер возложить, что он с ними хреново справляется не в никсовом серверном окружении?
Если можно обновлять модули по отдельности без особых рисков — это уже не монолит.
Но ещё не микросервис.
Не верно. Скрипты баша — одна из первых массовых систем автоматической оркестрации микросервисов :)
Хоть груздём назови, только в печку не кидай.
Какие ещё задачи вы пытаетесь на докер возложить, что он с ними хреново справляется не в никсовом серверном окружении?
Работать под виндой?.. В целом, докер — вполне себе виртуальная машина. То, что он не эмулирует оборудование, а протаскивает его от хоста — не показатель. Куда интереснее, запустится ли он с отключёнными средствами аппаратной виртуализации аля Intel VT/AMD-V? Я не знаю.

Docker — не ВМ. Это всего лишь удобный консольный интерфейс для запуска программ в ограниченном окружении, используя уже имеющиеся в ядре Linux технологии: capabilities, namespaces, cgroups, veth, aufs, overlayfs, iptables. Плюс эффективное хранение контейнеров в виде «слоёных» ФС и удобство их создания, получения, распространения (Docker Hub). Ещё маркетинг и пиар. Всё.


запустится ли он с отключёнными средствами аппаратной виртуализации аля Intel VT/AMD-V

Если у вас запустится свежий Linux (на ядре 3.сколько-то там), то у вас запустится докер. Все эти побрякушки ему не нужны. Процессы в контейнере — это процессы вашей ОС. Просто у них подрезаны capabilities, они засунуты в namespace, на них навешана cgroup, у них свой виртуальный ethernet-адаптер и отдельный chroot на каждый контейнер. Если захотите, то сможете сделать это всё и ручками.

для запуска программ в ограниченном окружении
Самое интересное что там можно запустить другой дистрибутив (ядро) отличное от хостовой ОС.
Самое интересное что там можно запустить другой дистрибутив (ядро) отличное от хостовой ОС.


Ключики в конфигурационном файле для другого ядра какие подскажите

Там можно запустить другой дистрибутив — но не ядро.

Дистрибутив — да, ядро — нет. Процесс в контейнере будет загружать и использовать библиотеки из дистрибутива в контейнере (libc, например), но работать он будет на ядре вашей ОС. Потому что это будет процесс именно вашей ОС, и вы его увидите в списке процессов вашей ОС (top, ps) и у него там будет PID и этот PID будет отличаться от того, что в контейнере (там он будет иметь PID 1, потому что в контейнере не запускается своей ОС).


Просто попробуйте выполнить uname для разных дистрибутивов:


➜  ~ docker run ubuntu:12.04 /bin/uname -a
Linux 1c89ad5dc611 4.9.6-moby #1 SMP Sat Jan 28 17:18:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
➜  ~ docker run ubuntu:16.04 /bin/uname -a
Linux 4ec17fded22d 4.9.6-moby #1 SMP Sat Jan 28 17:18:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
➜  ~ docker run centos:7 /bin/uname -a
Linux efba65e848c1 4.9.6-moby #1 SMP Sat Jan 28 17:18:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
На никсах — возможно. Я, как виндовый разработчик, могу говорить определённо только про виндовую ветвь. И что-то мне подсказывает, что в ней это всё сделано через виртуальную машину Hyper-V. Не знаю, быть может дело в том, что докер не ставится в отсутствии оной?

На других операционках да — ставится ВМ с Linux и на ней работает Docker. Про Windows не скажу — много лет уж не пользуюсь, но на макоси Docker безбожно тормозит и есть много геморроя с настройкой сети.

В последних релизах виндовс «ядро» линукс реализовано (не до конца, правда) нативно, без виртуализации, просто ещё относительно высокоуровневое API над Kernel API наряду с Win API или как там оно называется. И под виндовс докер запускается, афаик, тремя основными способами: виндовс-докер для виндовс-приложений нативно над Win API, линукс-докер для линукс-приложений в виртуалке, линукс-докер для линукс-приложений нативно над Linuх API.
Но зачем ему Hyper-V для нативных приложений Windows? Или это от лени, дабы не тратить время на отсталые оси и отсталых разработчиков?
Есть Docker под Windows для Linux-приложений от команды докера — он через виртуалку работает, есть поддержка Linux от Microsoft — она нативная :)
Немного вопрос не по теме, но: кто это такой «красивый» на главном фото?
Создайте базовую клиентскую библиотеку HTTP REST, оптимизированную для REST-вызовов, на основе которой можно строить конкретный микросервисный клиент, им будут пользоваться другие микросервисы. Этот оптимизированный клиент должен быть портирован на все языки, применяемые в вашей экосистеме.

HTTP REST сомнительное решение для API микросервисов, бизнес-логика которых не состоит большей частью из CRUD операций над сущностями, а состоит из масштабных изменений (включая создание и удаление) состояний сущностей в ответ на какие-то события в другом ограниченном контексте или явные команды пользователей с небольшой полезной нагрузкой.

Какие-то варианты RPC и(или) MQ в случаях когда большинство сценариев использования выглядит примерно как (в скобках полезная нагрузка):
— зарегистрировать нового клиента (куча персональных данных)
— создать (список товаров и их количества) и предоставить ему договор со статусом «черновик»
— при подписании (просто событие) изменить статус договора на «подписан» и сформировать и предоставить счёт на оплату
— при оплате (сумма) и её достаточности изменить статус договора на «доставка» и сформировать бухгалтерские проводки и ордер службе доставки
— … куча событий службы доставки в другом контексте
— при получении подтверждения о доставке (просто событие) изменить статус договора и ордера на «исполнен», перенести договор их оперативного хранилища в архив, поставить «лайк» менеджеру для системы мотивации
И это только идеальный сценарий и без получения оперативной и глобальной аналитики

По сути у нас лишь две операции явно создающие какие-то сущности/ресурсы и куча неявных побочных созданий, изменений и т. п. других сущностей, о которых часто даже информировать инициатора запроса не нужно, просто сообщить ему «ваш запрос принят к обработке», а информировать надо кого-то другого.
OMG, опять «микросервисы — это масштабируемость». Масштабируемость сервиса зависит от того, создали его масштабируемым, или нет.
Микросервисы гораздо легче (в том числе дешевле) масштабируются при прочих равных, если нагрузка на разные функции приложения в целом растёт непропорционально. Грубо, запросы к одной функции приложения стали делать в 10 раз чаще чем к остальным — в случае микросервисов мы отмасштабируем только эту функцию, в случае монолита или «макро»-сервиса будем вынуждены масштабировать и остальные, тратя зря ресурсы.
При правильной архитектуре, можно выдернуть эту функцию из монолита (подменить на «прокси») и сделать микросервисом либо внешней либой (на c/с++, если нужна оптимизация), с минимальными изменениями в монолите. Преимущество в том, что это будет сделано когда будет реальная необходимость.

А там в статье ровно это и написано — если у вас есть новый проект, не делайте его сразу на микросервисах. Но постарайтесь сделать его архитектуру такой, чтобы при необходимости, вы могли выдернуть из него компоненты и преобразовать их в микросервисы. "правильная архитектура" она же из нечего не появляется сама по себе. За ней должна какая-то идея стоять. Вот микросервисы и есть одна из таких идей. Примуществом этой идеи является то, что она достаточно внятно сформулирована.

Микросервисы, как и прочие технологии, не серебрянная пуля. Это все лишь инструмент для решения определенного класса задач.
Как и с любым инструментом, микросервисы нужно уметь правильно готовить. Не в смысле взял докер, разделил базы, выставил api в виде rest, etc. А в смысле, правильно оцениваешь риски и выгоды, и распределяешь их в оптимальном сочетании.
При «умелом подходе» на микросервисах запросто можно сваять известную коричневую органическую массу.
Точно так же как и при использовании монолита.

Верно и обратное, с головой можно качественно ваять и на микросервисах, и на монолите.

Главное преимущество микросервисов перед монолитами — собственно говоря почему про микросервисы говорят из каждой кофеварки — микросервисы лучше чувствуют себя в cloud.

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


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

Куски монолита тоже можно «вынести» на отдельные базы.
некоторые части должны все-таки работать с согласованным хранилищем.
Зависит от бизнес процессов.

Это должно быть заложено на этапе разработки. Просто запустить несколько инстансов, которые указывают на разные базы, не получится, т.к. запросы будут идти на случайный инстанс. Либо "умный" роутинг запросов на лоад балансере, но это, как мне кажется, крайняя и сложная мера.

Единственные преимущество микросервисов — горизонтальное масштабирование. Если оно вообще на вашем проекте нужно, так как дает снижение производительности, если оно не нужно.

Все остальное прекрасно реализуется на монолите.
Обсуждая микросервисы vs монолиты, нужно договориться, о каком монолите речь.
Просто у кого-то в голове возникает образ некого скомпилированного исполняемого файла, который при всем желании невозможно масштабировать количеством запущенных копий и балансировщиком перед ними.
А если представить RAILS-приложение(и подобные), которое вроде как монолит, то там прекрасно всё масштабируется. Тут единственный существенный минус — это выкатка новых версий подсистем монолита.
Масштабируется, но не прекрасно. Один только роутинг может занимать заметное время, если у вас тысячи роутов на регулярках. Да и сами обработчики займут место в памяти, даже если не вызываются. Прогретые кэши для всех них и т. п. А по факту реально используются юзерами с десяток, а все остальное раз в году для отчёта дергается или нового суперадмина назначить.
Согласен, но быстродействие и потребление ресурсов (а я не думаю, что уж так много лишний «груз» кушает, конкретно в рельсах) это лишь пара критериев. Да, оба показатели будут хуже заточенных решений, вопрос насколько.
Зато, например, какая хорошая утилизация железа. Есть 10 серверов, раскатываем монолит на все сервера и гоним через балансировщик запросы. А в случае с микросервисами придется решать задачку — какой сервис на какую/какие машины раскинуть. В итоге часть железа простаивает, ибо заложили под пики нагрузки. Это можно победить, но ценою усложнения системы.
Утилизация как раз обычно с микросервисами лучше. Например, редко используемая функция (ежедневный отчёт какой-нибудь) требует несколько гигабайт оперативки и грузит процессор длительное время на 100%, а остальные вполне работают на сотне мегабайт и в основном ждут ответа от СУБД. Выносим её в микросервис и нам нужна только одна машина с гигабайтами, остальные по сотне мегабайт.

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

Реплика тут не причём, говорим о формировании самого отчёта средствами приложения, а не СУБД. Из СУБД данные пришли (из реплики или нет — приложению не важно), а мы на их основе формируем представление для пользователя.

Так формирование отчёта по уже выбранным данным не требует гигабайтов оперативки, если это не отчёт на несколько тысяч листов. SQL для того и существует, чтобы из БД только нужные для отчёта цифры достать. Или Вы имеете в виду, что можно косячно формировать отчёт, но вынести это в микросервис и уже будет не так заметно, что отчёт формируется чёрти как?

Как вариант, да, не будет заметно. А вообще отчёты бывают разные, бывают и на тысячи листов для гос органов, например.

Забыли про ещё один момент: цена добавления и последующего удаления временной функциональности из монолита.
Когда есть монолит и есть запрос «доделать существующее, но хитро» то есть большой соблазн это сделать именно в рамках монолита, хотя и известно, что это нужно временно (спустя год эта функциональность уже будет не нужна). Что же, добавляем функциональность, дорабатываем её, развиваем, а через некоторое время её нужно будет удалять и «выкорчевать» вросший в монолит код уже будет непросто. А если не выкорчёвывать, то будет мёртвый код, который будет постоянно мешать обновлять фреймворки и языки программирования и т.д. и т.п.


А если сделать под этот запрос отдельное приложение, то удалить его будет очень просто :-)

И это хорошо если заранее известно, что фича временная.
Позвольте с вами не согласиться. Вам в любом случае нужно временную функциональность:
  1. Вызывать;
  2. Обрабатывать;
  3. Сохранять результат.
Это означает, что в любом случае эта функциональность, что в монолите, что в микросервисах будет:
  1. Вызываться;
  2. Обрабатываться;
  3. Сохраняться.
Это означает, что в любом случае вам нужно добавить, а потом и удалить код для:
  1. Вызова;
  2. Обработки;
  3. Сохранения.
И, если вы не глупый человек, то все файлы, реализующие эту фичу вы поместите в отдельный каталог, а в каждом месте использования вне этого каталога добавите себе комментарий BEGIN_TEMPORARY_FEATURE_NO <...> END_TEMPORARY_FEATURE_NO, по которому использование этой фичи можно будет найти (и удалить). То же самое для всех таблиц и прочего. В любом случае, что в микросервисах, что в монолите. А если пропустить часть кода, то приложение в любом случае либо не соберётся, либо будет нестабильным, что в случае монолита, что в случае микросервисов.

Если вы считаете, что я в чём-то ошибаюсь — скажите, в чём?
  1. Вызывать можно банальным редиректом или отдельным upstream'ом в Nginx.
  2. Обрабатываться оно будет в отдельном приложении-микросервисе
  3. Сохраняться будет в отдельную БД.

Сразу бонусом получаем лёгкость переноса этой функциональности (вместе с базой, которая в обычной архитектуре веб-приложений является «бутылочным горлышком») на отдельный сервер в случае резкого прилёта нагрузки на неё из-за которой начинает тормозить всё приложение.


Да, в монолите это всё тоже можно делать, но сложность монолита начинает расти, и разбираться в его коде тоже становится сложнее.

1) Его всё ещё нужно делать. Без разницы, как именно происходит вызов, данные для вызова должны быть подготовлены и упакованы. То есть код вызова в любом случае будет внедрён во все связанные модули. И должен будет удаляться оттуда. И если вы наивно полагаете, что код микросервисов не будет становиться сложнее, чем код монолита, (как минимум, столь же сложнее, как и) от того, что 20 микросервисов теперь будут дёргать нового временного друга, вы не очень умны.
2) Обработка не в смысле выполнение временной функциональности, а в смысле реакции остальной системы на возможные сценарии работы временной функциональности. Она в любом случае должна будет покрывать все стандартные ситуации работы Это я не про вылеты-перезапуски, а про вполне буднечные запросы-оповещения «я покушал» и «я покакал».
3) Данные подготавливаются не для повышения энтропии, а для вполне себе утилитарных нужд. Это значит, что они либо будут переводить систему в другое состояние (например, эмуляция оборудования), либо отображаться пользователю этой самой фичи (нужно будет создать запросы и, возможно, UIшки для отображения данных). То есть потребители данных должны получить унифицированный интерфейс, который возникнет не из воздуха, а будет внедрён в существующие модули соответствующей функциональности. А потом — удалён. И если вы думаете, что в микросервисах проще создавать эти самые связи внутри модулей, чем у монолита, опять же, вы либо не особо понимаете разницу, либо программировали монолиты в те времена, когда были говнокодером.

Иными словами, мантра «отдельное приложение» лично мне ничего не говорит. Да, есть лёгкость горизонтального масштабирования, а унифицированный API с удобным встраиванием есть? А отладка как, не хромает? Удобно ради какой-нибудь банальной мелочи целый микросервис городить и гонять тонны данных вместо внедрения пусть и неуместного в каком-нибудь контексте кода?

Да, сложность монолита растёт, но она растёт не быстрее, чем сложность взаимосвязей микросервисов.

У вас какой-то переусложнённый пример в голове, как мне кажется.


Пример из жизни, который доставил мне боль и думая про который я писал комментарии: тупо веб-сайт.


Дано: веб-сайт с функциональностью создания опросов для пользователей (не основная функциональность, но есть).
Задача: сделать более хитрые опросы да ещё в разрезе подчинённых организаций (что-то типа, устроило ли вас обслуживание). Аутентификация-авторизация не нужна, UI отдельный, нужна выгрузка результатов в Excel. Взаимосвязи с остальным сайтом 0 (ноль).
Как сделали: добавили новые типы опросов (куча условной логики везде), новые шаблоны, справочник долбаных организаций в админке и ещё одна библиотека для работы с Excel (чем не устроила предыдущая, история не сохранила). А потом ещё некоторые из организаций начали активно себе накручивать голоса (вот тут приехала нагрузка, часть из которой была вызвана логикой отложенной обработки голосов, не нужной именно этой функциональности).
Как надо было сделать: скопировать всю базовую функциональность в отдельное приложение с отдельной базой, доработать её там, навернуть любых библиотек и наворотов по желанию, развернуть на отдельном домене и сервере и после того, как оно поработало и заказчик получил свои результаты — удалить нафиг сразу вместе с той виртуалкой, на которой оно было развёрнуто.

Сферический в вакууме.

А приведённая вами в пример задача в её текущей формулировке звучит скорее «нам дали протухшую задачу, мы наспех дерьмово спроектировали модули и не сделали бекапов, поэтому не проехали на Оке и пришлось вызывать говномесные тачки». Ваше решение «сделать всё то же самое, но на бекапе». Иными словами, у вас в любом случае были бы и новые шаблоны, и справочник долбаных организаций в админке, и ещё одна библиотека для работы с Excel, и куча условной логики везде. Ничего бы не изменилось. Ваша основная проблема в том, что никто не подумал изначально сделать опросы максимально изолированным модулем, чтобы его изменение не требовало такой боли. Проблема не в том, что opinion_poll.php был куском Monolith, а в том, что он не был ограничен opinion_poll.php и opinion_poll.html

Кстати, роуты в Rails проверяются по порядку, так что если у Вас реально проблема с тысячами неиспользуемых роутов, то вынесите десяток реально используемых на самый верх routes.rb и остальные роуты будут отнимать ресурсы на проверку раз в году, или когда там до них дело дойдёт )

В память всё равно загрузятся сразу :) И речь не конкретно о Rails, а подобных фреймворках в целом, в которых могут проверяться все роуты, а выбираться наиболее точно совпадающий. Например, если для роута get_user с путем /user не указан метод, а для post_user с тем же путем указан метод POST, то роутинг должен выбрать второй, если запрос на этот путь отправлен методом POST, независимо от того какой указан раньше.

Естественно сопоставление роутов идёт с учётом метода. Это не значит, что из-за этого проверять придётся все. Но в память загрузятся все — это да… несколько десятков килобайт займут )))

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

А я понял, Вы про роуты, которые для всех методов подходят. В таком случае в Rails будут просто игнориться все последующие дубликаты этого роута с указанием конкретного HTTP-метода. Хотя допускаю, что где-то роутинг может искать best match до победного конца, но имхо это странный вариант… first match будет всегда работать быстрее.

Ничего странного, очень удобно.

Пример: небольшая компания делает внутренний проект, пользователей несколько десятков по стране. Делает один человек. Естественно получается монолит в каком-то смысле. Потом добавляется второй проект, как-то связанный с первым — второй монолит. Потом ещё несколько. Все они взаимодействуют. Потом оказывается, что внутри первого есть малосвязанные компоненты, как-то друг с другом общающиеся все по разному — кто через базу, кто через CGI скрипт со странными форматами передачи данных, кто-то поставляет на соседний сервер обновления через rsync — зоопарк. Так как проект растянулся на десятилетия, есть архаичные версии систем, языков, технологий и библиотек. Проект работает сам собой годами, без серьёзного вмешательства. И тут надо что-то поменять. Небольшое. Например добавить 1000 пользователей. И оказывается что поменяв в одном месте — поменяется и в другом, а даже наличие описания не помогает потому что архитектура требует одного сервера в узком месте. Перенести на новую ОС не удаётся — там давно не поддерживаются старые библиотеки. Базы данных, которые обслуживают части монолита, не поддерживаются уже 10 лет но там где запущены — работают как часы и все забыли что они есть. Вот реальная проблема реальных систем не топовых компаний. На этапе разработки термина "микросервисы" не было. Теперь понятно, что надо было стандартизировать общение между компонентами и разделять на куски в расчёте на поддержку некоторых кусков 20 лет без изменений, а других править каждый день.


Сейчас огромный плюс разделения на микросервисы — возможность разделения задачи на разные языки и технологии и поддержка маленьких компонентов случайными людьми — по мере необходимости нанимаем специалиста по эрлангу или перлу или яве на текущую задачу на пару месяцев и всё хорошо. Сервис маленький, описание простое, протестировать можно. 20 лет назад были модны программисты-универсалы, сейчас больше одного-двух языков/технологий знают единицы. А выбор языка диктуется самыми разными причинами — например описание API на swagger довольно жёстко задаёт выбор одной из 20-ти технологий из которых половина Java.


А облака… это всё хорошо, но как-то облачно. Масса организаций в облако не отдаст ничего.


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

Все правильно, но сама задача «Разбить проект на слабосвязанные компоненты с жесткими контрактами на взаимодействие между ним» очень непростая, особенно если надо заглянуть в будущее. И по идее уже не так важно, внутри монолита дробить или между сервисами.
Мне кажется оптимальным начать с монолита, а походу смотреть и находить линии «разреза». Так не только я считаю, и другие видят в этом нормальную стратегию.

Реальная стратегия для нового проекта — "как получится" :)

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

Микросервис вовсе не значит что он будет микро в плане количества стрчоек кода. Он микро в плане количества решаемых задач. Микросервис делает всего одну вещь, но делает её хорошо, быстро и надежно. Unix-way короче

А БД, вебсервер (mysql, redis, nginx...) относятся к микросервису? Отдельный процесс с коммуникацией «по сети», вроде подходит. Если да, то получается все изначально используют микросервисы.

не совсем)) эти вещи не решают бизнес-задач. Они решают технические вопросы хранения данных, общения с клиентом, еще чтото, но не решают бизнес-задач. Это инфраструктура для микросервиса)

бизнес-задач
Это очень расплывчатое понятие, а модуль авторизации, модуль суммирования массива или другая арифметика, модуль поиска числа в массиве — бизнес задачи или нет? А если сервис (node.js) просто пересылает данные из nginx в mysql и обратно — бизнес логика/микросервис?

Я считаю проще, если я делаю какой-то (сетевой) вызов в другой самостоятельный процесс, то этот процесс — (микро)-сервис. Просто mysql/redis — это уже обыденность и не хочется признавать это микросервисами, т.к. микросервисы — это вроде как повышенная сложность. К тому же некоторые хранят часть логики в самой БД.

Бизнес задачи это вполне конкретные понятия. Вы зачем собственно программу пишете? Вот сервис авторизации/аутентификации вполне решает бизнес-задачу по ограничению доступа к системе. Если бы он не решал, то его небыло бы в вашей системе, разве не так?

НЛО прилетело и опубликовало эту надпись здесь

Не совсем в тему микросервисов, но хочу заметить, что слово "бизнес" применительно к архитектуре приложения не имеет (в общем случае) отношения к коммерции, а обозначает ту "пользу", которую приносит конкретное приложение.


Поэтому сервис авторизации для конкретного приложения — это бизнес-функциональность, но в то же время используемая библиотека для OAuth2 — это уже не бизнес-часть, т.к. она универсальна и не привязана к предметной области.


Поэтому суммирование массива — не бизнес-функциональность, если у нас, конечно, не приложение по суммированию массивов (Excel).

Все (почти) используют, но не все пишут :)
Микро-сервис написанный не вами не перестает быть микро-сервисом.
Команда пишет приложение, реализующие какие-то функции. От того, что это приложение используется сторонними приложениями как сервис или даже микросервис, от того, что это приложение использует сторонние приложения как сервисы или микросервис, никак не зависит является ли архитектура самого приложения монолитной или сервисно-ориентированной.
Итак, отчего мы отказываемся в случае перехода на микросервисы
1) От транзакций. Главный минус
2) Получаем проблемы с версионной совместимостью этих микросервисов между собой
3) Вместо работы внутри процессора и системной шины мы гоняем данные по медленной сети и всему сетевому стеку. Сильное замедление работы. Получаем сильную зависимость от качества сети
4) Повышение надежности — миф. Приложение не может работать без какого-то компонента. Это будет некорректная работа.
5) Все эти микросервисы в сумме потребляют больше памяти и ресурсов, чем монолит
6) Вынужденное дублирование кода. Либо приходится делать какие-то отдельные проекты с общим кодом
7) Невозможность рефакторинга. Мы получаем кучу внешних интерфейсов, которые нельзя трогать. Либо придется править одновременно все микросервисы
8) Сложность при обновлении, если изменился внешний интерфес. Приходится обновлять одновременно несколько микросервисов. Если будет рассинхронизация — клиенты получат ошибки.
9) Сложность правки базы. Сложно понять, использует ли эту таблицу какой-то другой микросервис. Приходится пересматривать код всех микросервисов. И опять возникает проблема одновременного обновления.

Что получаем взамен? Мнимую красоту кода. И больше ничего. Очередная серебряная пуля

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

>У каждого микросервиса должна быть своя база
т.е. отказываемся от форенкеев и дублируем данные?

Если данные надо дублировать — значит, граница ответственности микросервиса обозначена неправильно.

Нормально она может быть обозначена, например, когда одна «физическая» сущность в одном контексте является полноценной доменной сущностью, а в другом лишь значением атрибута. Например, частый случай — физическое лицо. В разных бизнес-процессах требуются разные данные о нём, в одних может быть нужна самая актуальная информация о нём, в других — информация на момент совершения информации. И идея сделать единый микросервис, отвечающие за все данные физлиц не самая лучшая, даже если пренебрегать лишними сетевыми вызовами и т. п., просто с точки зрения сложности самой сущности.
кстати, что насчет ресурсов на работу кучи баз. Один только оракл кушает минимум 2 гига оперативной памяти

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

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

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

  1. От каких транзакций вы отказываетесь?
  2. Никаких проблем нет. Вас никто не заставляет ломать обратную совместимость в минорных патчах. При необходимости таких изменений используется стандартное решение через /api/v1/… /api/v2/… при том вас никто не заставляет поддерживать 100500 версий. Пользователи этих апи — это все тоже ваше приложение и ваши коллеги, которых их саппортят. Приняли решение ломать совместимость, опубликовали соответсвующий раздел в доках, оповестили все команды и поставили дедлайн до которого они должны апнуться.
  3. Да, безусловно так, но никто не заставляет вас гонять данные через весь земной шар. Здажержки в локальной сети не такие уж и большие, особенно по сравнению с сетевыми задержками между вашим приложением и конечным пользователем. К томуже, шлюз, с которым общается конечный пользователь вполне может работать с остальными микросервисами асинхронно, что сведет сетевые задержки на общение микросервисов практически к константе, не зависящей от количества этих самых микросервисов.
  4. Не поверите, но может. Не случиться ничего страшного, если по какойто причине упадет рассылка писем. Да пользователи не получат писем некоторое время, но как только рассылка поднимется все задачи с очереди будут выполнены. Останется досутпной публичная часть системы, если вдруг упадет авторизация. Более того, залогиненые юзеры смогут продолжать работу. Да, когда падает критически важный микросервис, то работа встанет. Но даже в таком случае. На прошлой рабте у нас был здоровенный монолит, деплой которого на прод сервера в двух датацентрах занимал около 3 часов времени. Фикс в 5 минут времени деплоится 3 часа. Микросервисы меньше, проще, легче разворачиваются.
  5. Наоборот, микросервисы лучше утилизируют ресурсы. Их можно разворачивать на машинах оптимизированых на ту или иную нагрузку. Файлохранилищам нужны быстрые и надежные диски. кеши требовательны к объему озу и так дальше. Если ваш логин сервис не справляется с количеством жалеющих залогинится, то вам нужен просто еще один логин сервис, а не все огромное приложение.
  6. Отдельные проекты с общим кодом — плохой вариант. Да, нужно дублирование кода. Но это не так страшно. DDD отличо ложиться на идею микросервисов. Сервис владелец имеет код позволяющий создавать/менять/удалять некие сущности. Сервисы которым нужны эти сущности получают упрощенный код, рид-онли модели, на которые мапятся ответы апи сервиса-владельца. Да, лишний код, но он пишется один раз, да и пишется громко сказано. ИДЕ спокойно нагенерит класс с конструктором и пачкой геттеров.
  7. Это тоже что версионирование. Помогает с этим бороться во первых слоеная архитектура. Вы можете как угодно менять бизнес логику приложения, оставляя неизменный внешний интерфейс пока это возможно. Как только это становится невозможно, смотрите пункт 2. В монолите при таких изменениях вам точно также придется править все места, где модуль используется.
  8. Вы уже третий раз говорите одно и тоже. И я третий раз вам скажу, что эта проблема хоть и существует, но не такая страшная как вы её описываете.
  9. Вообще не проблема, ибо у каждого микросервиса есть своя бд для своих нужд и апи других сервисов для данных, которыми сервис не владеет.

Ну и как итог. Микросервисы далеко не серебрянная пуля. Более того, для большинства приложений они не нужны. Любой нормальный монолит вцелом пишеться как набор независимых модулей (читай микросервисов), работающих в пределах единого приложения. Сразу начинать писать приложение как микросервис — это глупая затея. На начальном этапе вы не установите границе микросервисов достаточно точно и как результат получите плохую масштабируемость и сильную связанность. Микросервисы — это следующий этап развития. Когда монолит становится слишком большим. Становится слишком большой команда, которая его поддерживает. Когда в монолите явно выделились группы независимых модулей которые решают бщую проблему и становится ясно, что их можно вынести в отдельное приложение. Когда видно какие компоненты зависят от каких данных и так дальше. Вот тогда приходят микросервисы.

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

Не надо откатывать. Надо повторять попытки достучаться до финансового модуля в фоне. Это и есть та самая устойчивость к отказам — складскому учету не нужен постоянно работающий финансовый модуль.

Если ваша бизнесс логика предпологает возможность отката зименений, то всеголишь нужно выставить соотвествующий апи ендпоинт и дернуть его в случае пробелм с финансовым модулем.
Как вариант можно сущностям добавить статус. И пока статус не станет подтвержденным их видно, но ими нельзя воспользоваться. Соотвественно можно мониторить зависшие в невесомости вещи и принимать какието решения/меры по их исправлению.

итого какие-то костыли и велосипеды вместо стандартных транзакций. Про это я и говорил в самом начале

У вас ошибка в комментарии:


вместо медленных транзакций
Итого мы отказываемся от медленных транзакций чтобы использовать свои велосипеды. Верно?

Почему вы стандартные решения называете велосипедами?

Как вариант можно сущностям добавить статус. И пока статус не станет подтвержденным их видно, но ими нельзя воспользоваться. Соотвественно можно мониторить зависшие в невесомости вещи и принимать какието решения/меры по их исправлению.

это явно не стандартное решение.
Ендпоинты — тоже довольно редко применяются и поддерживаются далеко не везде

Это очень даже стандартное решение. Формально, длительный процесс переводится в форму конечного автомата, после чего его состояние сохраняется в БД и учитывается в выборках.

Это наглядный пример, как (микро-)сервисы делают код проще.
Произошла ошибка в финансовом модуле. Как откатить транзацию в модуле складского учета?
Вообще эти 2 могут быть в одном микросервисе, в разных «черных ящиках» (модулях). Но если все же они отдельно, вызов финансового модуля должен быть быстрый (0,1-1 сек), в итоге если фин. модуль возвращает ошибку, то откатываете незакрытую транзакцию в складском.

Если фин. модуль выполняет метод долго (1-10 мин), то у вас проблемы другого плана, т.к. такие долгие транзакции очень не желательны (особенно которые блокируют «пол базы»). И если нет возможности ускорить, например это внешний платежный сервис, который ждет когда пользователь кликнет кнопку, то вам нужно использовать 2-х фазный комит. И микросервисы в этом случае не осложняют ситуацию.

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

PS: Я за «монолит на старте»
Вообще эти 2 могут быть в одном микросервисе, в разных «черных ящиках» (модулях).

Не могут. Это будет уже не микросервис.


PS Я за макросервисы и монолит на старте.

как делать одну транзакцию поверх нескольких микросервисов?

Вариантов куча, от самых простых типа залогировали ошибку, саппорт пускай разбирается, до промышленных координаторов транзакций от ведущих брендов типа МС и Оракла. Тем более на практике всегда есть транзакции, которые вроде бы одно целое, типа получил деньги и отдал товар, но в особых случаях откатить не получится, если что-то пошло не так, например, деньги взяли в кассу, провели и свет отрубился, ни деньги не вернуть, ни товар не отгрузить.

Ну или самый простой вариант — это не разносить транзакционные сервисы по разным микросервисам.

Этот вариант имеет свои ограничения.
Погуглить
— 2 phase commit
— eventual consistency

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

Такое впечатление, что микросервисы, по-вашему, — это как dll, только доступные по сети.

Самое большое преимущество микросервисов я вижу в их взаимозаменяемости. Если есть хороший стандартный интерфейс, можно легко поменять одну имплементацию/версию на другую (в т.ч. реализованную на другом ЯП/платформе), не трогая всю остальную систему. Жертвовать же производительностью (общение сервисов через сеть) за счёт небольшой экономии ОЗУ (создание новых экземпляров только нескольких сервисов на другом сервере вместо нового экземпляра целого монолита) не вижу никакого смысла.
ну да, какой-то универсальный сервис. Например сервис адресов, которому не нужны ни транзакции, ни согласованность данных.
Но пытаться делить неразделимые вещи не стоит
Допустим у нас есть приложение в котором пользователи могут регистрироваться, авторизоваться и что-то публиковать. Пользователи могут дружить. И каждый пользователь может видеть только публикации друзей.
А также пользователь может заблокировать любого другого пользователя, даже друга, и тогда заблокированный пользователь не сможет увидеть публикации.
Как в микросервисах хранить заблокированных пользователей? Ведь они нужны в 2 микросервисах: публикации и друзья.

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

Есть микросервис авторизации, и есть микросервис правки данных. При правке нужно сохранять id пользователя, совершившего эту правку.
Как это сделать, если базы разные?

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

т.е. отказываемся от форенкеев (целостности базы)

База самого микросервиса вполне целостная. Целосность расшаренных данных зависит от от логики приложения. Только и всего. Допустим ваш сервис постинга может удалять/помечать удаленными записи автора, по которому приходит 404 с сервиса пользователей.
Почему вас не возмущает, что если я зареган через соц сети, а потом взял и удалился из соцсети, то на вашем сайте я по прежнему есть? Смотрите на микросервисы как на независимые приложения. У приложения есть "свои данные", целостность которых контролируется базой этого приложения. Есть внешние, которые от этого приложения не зависят (Юзер удалился). Максимум что, сервис юзеров может бросить ивент об удалении юзера, а сервис постов подписатсья на него и както прорегаировать. Или не реагировать вовсе. Все зависит от бизнес-логика приложения.


ЗЫ. существуют монолиты исползьющие несколько хранилищ одновременно. При этом это не всегда даже РСУБД. Это может быть документоориентированная бд, может быть кей-велью хранилище, графовая бд, даже банальные файлы или удаленные сервисы всяких амазонов и иже с ними. Как же монолит поможет обеспечить целосность данных в этом случае? О каких венешних ключах может идти речь?

База самого микросервиса вполне целостная.

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

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

Ну зачем-то же придумали форенкеи как метод обеспечения целостности

каждому инструменту свое применение. Внешние ключи отнюдь не панацея, к тому же довольно тяжелая штука при вставке/изменении/удалении записей.

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


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

Как это ушел, он вам об этом сказал? Если нет то откуда вы знаете что он ушел, может он после 5, 10 лет вернется.
Любые распределённые данные без единого транзакционного центра всегда вероятностны. Всегда есть вероятность, что данные на одном сервере уже изменились с того момента, как мы получили последний ответ. И, что самое ужасное, у нас нет способа сказать «Всем ЦЫЦ! Батька думает.»

З.Ы. Монопольное владение.
т.е. отказываемся от форенкеев (целостности базы)

Не драматизируйте. Всего лишь отказываемся от обеспечения целости данных в рамках всего приложения средствами СУБД. В рамках микросервисов целостность обеспечивается средствами СУБД, а целостность между ними обеспечивается другими средствами, если она вообще нужна.
Ещё пример. И в финансовом, и в складском модуле нужно ФИО клиента при выводе списка.
Что вы предлагаете делать: дублировать их в разных базах или дергать отдельный запрос на каждую запись в списке?

Дублировать.


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

а что делать, если эти ФИО поменяются? Как их синхронизировать?

Тут три варианта.


  1. Никак! ФИО в журнале операций должно быть таким же, что и документах (например, в накладной). А там данные измениться не могут.


  2. При получении свежего токена от пользователя данные о нем в базе обновляются. Таким образом, ФИО в журнале будет старым пока пользователь не обратится (прямо либо опосредовано) к сервису.


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

Обеспечьте целостность когда документы (накладные, квитанции и прочее) хранятся в документов монге, а юеры в mysql

Вы ходите по кругу, mongo и mysql — уже отдельные (не микро) сервисы. Логично, что между ними уже нет взаимодействия, и любые попытки синхронизации ради обеспечения целостности — велосипеды.
Потому любые ваши наезды «обеспечьте», вообще-то не по адресу, так как речь идёт именно о том, что (микро-)сервисная архитектура этого сделать не может, на это способен только монолит. То есть распределённая база не может давать гарантии, в ней всё всегда вероятностное. В рамках одного единственного mysql же (или postgresql, который давно уже чавкает жсонами) такую целостность обеспечить очень просто и достаточно дёшево.

Ясное дело, что люди переходят на связки манги и мускула не от хорошей жизни, но не нужно, как веганы, верещать во все стороны «Я давлюсь этим сельдереем уже два месяца и отлично себя чувствую, а вы такие злые из-за мяса.» Вы НЕ можете обеспечить 100% целостности и синхронности в микросервисах, и никогда не сможете. Факт. Но вы можете повысить производительность и понизить вероятность ошибок так, что погрешности с лихвой покроются прибылью. Тоже факт. И не нужно городить что-то ещё.
Вы НЕ можете обеспечить 100% целостности и синхронности в микросервисах, и никогда не сможете.

Вы отрицаете, что не только CA системы, но и просто C (в терминах CAP) существуют и эксплуатируются?
Нет, я её цитирую. Любая БД не может быть одновременно согласованной, доступной и распределённой на несколько транзакционых центров. Микросервисы — это именно выделение нескольких транзакционных центров. Значит, у вас не будет либо гарантии согласованности данных, либо гарантии доступности сервиса, и любая операция в такой системе будет вероятностная.

Вы сами написали, что вне единого транзакционного центра нужно рвать жопу сложными логами и прочими приблудами. Вы сами написали, что вне единого транзакционного центра мы можем гарантировать согласованность лишь атомарной операции. А теперь вы спрашиваете такие, простите за выражение, тупые вопросы? Повторюсь, я их не отрицаю. Я констатирую, что CA и C системы не могут быть распределёнными по определению.
Не могут быть распределенными (но не по определению, а по гипотезе, подтвержденной наблюдениями, но не доказанной теоретически) CAP системы, либо CA, либо CP, либо AP. И это относится в том числе к клиент-серверным и трехзвенным архитектурам — они тоже распределенные.
Подловил, по гипотезе.
Остальное верно, Они тоже вероятностные. Отсечение вероятностей возможно только монопольным владением, о чём монолиты и есть. Ибо если приложение монолит, оно точно знает, что кроме него самого никто не мог внести изменения в его хранилище, и что транзакции никто, кроме него вносить не может. А микросервисы? А что микросервисы? Сегодня он есть, а завтра их десять. Какие гарантии?
Микросервисы предоставляют на выбор либо CA, либо CP, либо AP (можно, конечно и меньше). Нужна согласованность обязательно — можно пожертвовать доступностью или устойчивостью. Причём это применяется и без микросервисов в обычном понимании. Есть транзакционный центр типа постгреса, для него пару синхронных реплик на случай отказа мастера. Пока обе реплики не подтвердят, что приняли изменения, мастер клиенту не сообщит о завершении транзакции.
Всё верно. Вот только это не противоречит тому, что я написал. А написал я, что с разбиением на микросервисы и, соответственно, на множество транзакционных центров мы теряем гарантии, как минимум доступности сервиса целиком, а то и целостности данных (монопольное владение данными в микросервисах, в общем, не поощряется, дублирование записей между репликами микросервиса, в общем, не работает, все системы разбиения на кластеры нужно прикручивать извне). Мы и так её не имели учитывая жестокий реальный мир, а теперь она дополнительно снижается, и весьма серьёзно. Написал я, что попытки дать гарантии повышает сложность взаимодействия систем (даже внутри постгреса разворачивать реплики не очень просто и дёшево, а скрестить манго и мускул — тот ещё фрукт получится), и большую часть кода придётся написать самому. Так в чём я был не прав?
В реальном жестоком мире гарантий соблюдения CAP не даёт никто. Более того, для повышения доступности вводят в монолитные системы распределенность в виде репликаций и прочих HA-штук. Это если не учитывать, что даже тот же Postgres по сути своей не является монолитом, а лишь условно монолитным ядром, взаимодействующим с, как минимум, ОС, которая взаимодействует с, как минимум, железом. И на уровне Postgres-ОС, и на уровне ОС-железо, тратится множество усилий для увеличения хотя бы целостности данных, чтобы клиент, получивший от Postgres подтверждение, что транзакция выполнена был уверен, что в сложной распределенной (с точки зрения процессов) системе его данные потеряются с минимальной вероятностью. Но это не гарантии, это лишь обещание «мы сделали всё, что смогли, но мы не боги».

На самом деле микросервисы мы используем очень давно, просто теперь есть тренд не только использовать, написанные (а то и воплощенные в железе) кем-то, но и писать их самим. Да, сложность разработки (в плане увеличения количества контролируемых разработчиком процессов и связей между ними) увеличивается, но это плата за другие преимущества, прежде всего за возможность дешевого горизонтального масштабирования в целях, прежде всего, увеличения доступности архитектурными средствами самого приложения, а не внешними «микросервисами» типа СУБД.
И где мой комментарий противоречит этому? Нигде. О чём спорим? О любви к спорам? Не имеет смысла, срач — это наше всё, и нет никого, кто любил бы нас сильнее, чем святой вентилятор и присвятая понажористая жижица.
Вы используете слишком категоричные утверждения, заявляя, что, с одной стороны, монолит дает гарантии CAP, а с другой, что микросервисная архитектура не может гарантировать даже C.

А на самом деле, классическая клиент-серверная или трехзвенная архитектура с РСУБД не может обеспечить CAP (даже сама СУБД не может, поскольку распределяет функции между своим ядром и ОС, имея вероятность как отрапортовать о законченной транзакции, которую по независящим от СУБД причинам клиент не увидит, так и закончить транзакцию, не уведомив об этом клиента), а микросервисная может обеспечить CA, CP или AP на выбор, так же как классика. Ничем они принципиально не отличаются, кроме того, что в случае микросервисной архитектуры на разработчика возлагается бОльшая ответственность за балансирование между метриками CAP, все из которых не могут достигать 100% ни в одной практически возможной архитектуре, только лишь вероятностные, пускай и с кучей девяток, даже в самых дорогих проектах типа космических, где применяется многократное резервирование всего и вся лишь с целью набрать побольше девяток, но стопроцентных гарантий нет, ведь сама аппаратная база носит вероятностный характер, а для защиты от сбоев используются методы теорвера и матстатистики, уменьшающие вероятность незамеченных сбоев и даже где-то исправляющие их, но не сводящие её к 0%. Например, какая-нибудь ECC-память способна исправить один и заметить ошибку в двух неправильных битах в слове, но если ошибка в трёх, то она даже обнаружить это может быть неспособна.

Весь срач из-за нежелания большинства разработчиков так называемых монолитов признать, что они давно используют сервис-ориентированные архитектуры, просто сами разрабатывают только один сервис из множества используемых их приложением, перекладывая ответственность за CAP-метрики всего приложения на плечи разработчиков этих сервисов таких как СУБД, веб-серверы, и ОС.
Ну да, всё так. С этим никто не спорит, чистых монолитов слишком мало, чтобы о них писать, мы это с вами выше обсудили. Только не об этом срач. Мы же с вами не сошлись на том, что мы зовём микросервисной архитектурой, и в чём её отличие от архитектуры сервисной и от модульной архитектуры. У нас по прежнему нет чёткого понимания терминов, на которых мы говорим.

Мы можем говорить о микросервисной архитектуре, как о продукте из независимых модулей-приложений с отдельными базами данных и взаимодействии только по HTTP. А о монолите, как о приложении, в котором все части написаны на одном языке и реализуются через внутренние вызовы, которое собрано в общий бинарик, но которое, в принципе, может использовать внешние сервисы через публичный API. И то, и то — радикальные формы архитектуры, имеющие в своём радикализме огромные неустранимые в рамках самих себя проблемы. Монолит — в масштабировании, а микросервисы — в накладных расходах и проблемах с синхронизацией.
А истина, как обычно, где-то посередине, там, где валяются DLL-ки, где куча пайпов и потоков, где разделяемая память трясёт мутексами и критическими секциями и где, прежде всего, продуманная архитектура внутреннего взаимодействия с разделением в тех местах, где оно может понадобиться. Короче, там, где нас нет.
Отличие от сервисной архитектуры только одно по сути — ответственность каждого отдельного сервиса. Грубо, если блоговый сервис отвечает и за собственно блоги (посты с комментариями) и за управление пользователями, то это сервис. Если доверяет управление отдельному сервису, отвечая только за блоги, то это микросервис.

Протокол взаимодействия сервисов между собой к архитектуре особо не относится. Мы вон активно AMQP используем. И даже разделяемая память и прочие мутексы может быть частью протокола, если условный монолит был однопроцессынм и мы решили его масштабировать горизонтально хотя бы в пределах одного процессора по процессу на ядро.
А вот тут очень зыбкая почва под ногами. Микросервис отвечает за блоги и только за ленту блогов? Отлично. А разделить его на микросервис работы с БД для простоты миграции, микросервис генерации страницы для гибкой настройки генерируемого контента и микросервис взаимодействия с внешним миром — остальными микросервисами — не хотите?

Вы скажете, это излишнее усложнение? А вот это вопрос дискуссионный. Как и предложенное вами разделение. Есть у меня, например, сервер онлайн-игры, и есть сайт. На нём чат, совмещённый с игровым, лента новостей, лента внутриигровых событий. Аутентификация через клиент. И как делить, что тут микросервис, что тут сервис? В драке на ножах, не иначе. Да и сам сервер, с одной стороны, делится на микросервисы, а с другой — не делится. Потому что есть сотни разделений, которые можно провести для правильных абстракций и ещё тысячи — для неправильных, но всё ещё очень симпатичных. И будет ли такое разделение сервисом или микросервисом — это прекрасная тема для дискуссии за пивком под воблу, но совершенно лишняя у клавиатуры с IDE-шкой на мониторе.

И по протоколу, лично вы, конечно, можете использовать любые, но вы, видимо, не читали самой статьи. А в ней красной линией проходит мысль, что вы делаете это внеправильно, а правильно — через веб-сокеты. Это мысль из статьи, и я с ней не согласен, но эта мысль встречается не впервые, её активно проталкивают.
Собственно это и имелось в виду. Микросервис блогов отвечает за записи постов и блогов в БД, отдавая их в каком-то слабо адаптированном для конечного пользователя формате типа JSON. А взаимодействие с внешним миром может осуществляться не только через http endpoints по схеме все-со-всеми, но и через, например, звезду, где в центре какая-нибудь очередь сообщений, или через шину. А html рендеринг (если он вообще на серверной стороне осуществляется, а не на клиенте) происходит на отдельном сервисе шаблонизации.

Да не надо делить сервисы на микро и «макро» у клавиатуры. Когда ответственность сервиса выродится в ответственность только за одну сущность или за один процесс, тогда можно констатировать, что он стал микросервисом. А можно не констатировать, можете продолжать называть его сервисом.

Это вы, видимо, невнимательно читали статью, в ней фразы типа «например HTTP», «вроде HTTP» — просто HTTP самый популярный способ для создания интерфейсов микросервисов, особенно на первых этапах разбиения монолита на сервисы, в том числе и микро. Он синхронный, он поддерживается из коробки, наверное, всеми мэйнстрим языками, он простой (если использовать его в качестве транспорта, а не пытаться реализовать всю его семантику). И во многих случаях он уже используется в системе для общения с клиентами.
И в чём тогда отличие микросервисов от любой другой модульной архитектуры, прежде всего, трижды упомянутых мной динамических библиотек? Спойлер: они не такие гибкие.
Зачем такое повальное поклонение «золотому бычку»? Спойлер: раскрутить тему и продать больше своих решений.

Всё, что написано в статье, всё целиком уже давно известно. А всё что вы написали, ВСЁ ЦЕЛИКОМ сводится к «наймите толкового системного архитектора». Вот только ни в статье, ни у вас не написано, как обеспечить привычные для монолита согласованность данных, да и организовать транзакции вообще. Готовых решений нет, а все варианты сводятся к «нажарь свою СУБД».

А я буду стоять на своём «нужно думать, что делаешь — и не поддаваться на веяния моды и чьи-то сладкие речи», И ни Аллах, ни шайтан не смогут сдвинуть этого упёртого осла с его места.
Грубо, сервис — модуль, компонент, вынесенный в отдельный исполняемый (а не линкуемый как библиотека) бинарник, который запускается в отдельном процессе ОС (на практике часто на отдельной машине исключительно с сетевым доступом к процессу клиентами). Главное преимущество перед библиотеками — возможность гибкого горизонтального масштабирования: может один процесс сервиса обслуживать тысячи основных процессов, а могут тысячи процессов сервиса обслуживать один основной процесс. С библиотеками невозможно реализовать второй кейс, и, как правило, не реализуют первый, либо статически линкуя библиотеку, либо загружая все динамически линкуемые библиотеки на старте процесса, используя динамическую линковку по сути лишь для уменьшения размера бинарника, а не по требованию, а после использования сразу выгружая.

Является ли сервис микросервисом определяется не техническими характеристиками, а архитектурными — количеством ответственностей в рамках общей архитектуры системы — у микросервисов оно стремится к одной.

Согласованность и транзакционность привычно обеспечивается не самим монолитом, а средствами СУБД в рамках трехзвенной архитектуры: клиент-сервер приложения-СУБД, то есть монолитом является сервер приложений с весьма ограниченным собственным состоянием, а целостность и транзакционную изоляцию он доверяет другому серверу/сервису/микросервису — СУБД. При решении архитектора разбить монолит на сервисы/микросервисы есть множество способов обеспечить согласованность и транзакционность между ними, первый из которых убедиться, что она действительно нужна во всех кейсах, а не суется по привычке, потому что разработчикам это практически ничего не стоит. Нужен индекс для поиска по идентификаторам клиента в таблице заказов, есть первичный ключ у таблицы клиентов, почему бы его не сделать внешним ключом к таблице заказов, даже если от аналитиков/заказчиков не было требования обеспечить ссылочную целостность. Вот есть явное требование что поле «идентификатор клиента» должно иметь возможность ссылаться на несуществующую в таблице клиентов запись, тогда не будут делать внешний ключ, а нету — будут. То же и с транзакционностью. Вот сейчас уничтожаю транзакционность в модуле приема платежей от платежной системы. разработчик модуля писал информацию о сообщении платежной системы о платеже в таблицу для этих сообщений, потом собственно в таблицу платежей финансового модуля, транзакционность явно не использовал, но она во фреймворке по умолчанию. В результате при нарушении целостности во второй таблице мы теряем запись о платеже вообще. Не, ошибка в логи пишется, но читать их начинают только когда клиент приходит жаловаться с чеком платежки на руках.
И что не позволяет библиотеку реализовать и как приложение-(микро-)сервис, и как подключаемый модуль? rundll32.exe не в десятке выпустили, так-то.

Это число всегда зависит от нашей точки зрения. Для одних чат для работы с клиентами будет микросервисом, а для других он будет сложным продуктом из скрипта на сайте, серверного приложения с балансёром нагрузки и планировщиком, клиентов для службы поддержки и административных инструментов. И, что самое противное, со своих колоколен все будут правы.
«Фрукт — фрукт, сиська — сиська, цветок — цветок. То же самое, мать твою!» © «Чёрные паруса»

Этот конкретный пример говорит лишь о том, что предыдущий разработчик думал чем угодно, но не головой. Или вы рассказываете не всю правду, а лишь то, что вам выгодно. Ещё ни один программист не сказал, что транзакции и внутренние зависимости — это плохо. Они могут быть неудобными, долгими, сложными, но все альтернативы — хуже. Конкретно в этом примере есть две проблемы с транзакциями: не хранится отдельно таблицы с запросами на проведение операции, и нет реакции на провалившиеся транзакции (или, шире, нет поля результата запроса на операцию). Или оно есть, но его никто не пользовал. Но это уже другая история.
Напишите службу someservice.exe, оборачивающую some.dll в какой-то интерфейс хоть HTTP, хоть велосипедный, и вы получите сервис.

Микросервис чата — фасад для сложного сервисного приложения. Для пользователей микросервиса чата — чат микросервис, для его разработчиков — сложная распределенная система.

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

Таблица хранится, при успешном платеже формируется две записи — запрос на платеж с успешным статусом и собственно платеж. При неуспешном есть только запись в логе (реакция на ошибку).
Отлично, возражений нет. Тогда повторяю вопрос: о чём срач? Мы тут просто пожурчать собрались или ради дела? Если ради дела, то в чём вы со мной не согласны, когда я пишу «ничто не ново в этом мире» и «homo sapiens должен быть человеком разумным»?
Действительно концепция микросервисов не нова как явление. Просто дали сервисам с единственной ответственностью название «микросервис», чтобы подчеркнуть единственную ответственность в отличии от обычных сервисов, которые часто монолитно берут на себя решение множества проблем.

Капитан сообщает: надо сохранять id пользователя.

Т.е. то что в монолите можно было сделать в базе одним SELECT и где все проиндексировано, теперь надо делать 2 SELECT'a.
А что если между запрашиванием списка френдов юзера и SELECT'ом постов, меня заблокировали, я получу публикации которые не должен был получить.
А что если между запрашиванием списка френдов юзера и SELECT'ом постов, меня заблокировали, я получу публикации которые не должен был получить.

Вы получите публикации которые вы могли бы получить если бы запросили их секундой раньше. Это не проблема.


Проблема будет, если запрашиванием списка френдов юзера и SELECT'ом постов другой пользователь сначала блокирует вас, а потом публикует что-нибудь. В таком случае вы можете получить публикацию, которой никогда бы не смогли получить при последовательном исполнении запросов.

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

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