Комментарии 269
К сожалению, у меня нет опыта работы с микросервисамиОпыт бы не помешал, особенно суппорта, статья получилась бы несколько другой.
>У микросервисов доступность выше: даже если один из них сбоит, это не приводит к сбою всего приложения.
Да-а-а? Представим себе что это микросервис авторизации. Что, скажете нет, это не микросервис? Или его неработоспособность не отразится на работе всего приложения? Ха три раза.
Тщательнее надо формулировать, тщательнее.
это не обязательно приводит к сбою всего приложения
fixed
Т.е., не большая доступность, а простота обеспечения этой доступности, путем применения таких-то решений.
А что мешает развернуть несколько копий монолита?
Имелось в виду, что в монолите не все является той самой точкой отказа, которую вообще стоит дублировать. Вынести эти части, сделать их автономными, и задублировать (заодно повысить производительность) — это вполне себе годная стратегия.
Не очень понял вас.
- Допустим в микросервисах есть точка отказа. Мы дублируем микросервис с этой точкой — профит.
- Допустим в монолите есть точка отказа. Мы дублируем монолит — профит.
В чем разница?
Теперь понятно.
Однако хочу заметить что это не повышение производительности (скорее наоборот из за накладных расходов на сетевое взаимодействие), а снижение потребления памяти.
Скорее это просто снижение накладных расходов на деплоймент (хотя если посчитать в сумме — то возможно окажется, что на развертывание сотни микросервисов уйдет намного больше ресурсов, чем на один монолит). Просто эти ресурсы — их можно будет проще горизонтально масштабировать.
Ну и да, сетевое взаимодействие вместо вызовов внутри процесса — это всегда минус микросервисам, без вопросов.
Ну и да, сетевое взаимодействие вместо вызовов внутри процесса — это всегда минус микросервисам, без вопросов.
Не сетевое, а межпроцессное. Микросервисы и сервисы вообще не обязаны общаться по сети, вполне могут использовать файловые сокеты, разделяемую память и т. п., хотя это накладывает ограничения на инфраструктуру.
Так что насчет «всегда» — да, я выразился слишком сильно, но как правило взаимодействие все-таки требует дополнительных накладных расходов.
В одном процессе, в разных, или на разных серверах.
Это забота шины взаимодействия.
Монолит жрет 16Gb памяти. Микросервис, который точка отказа — 128Mb.
Это что ж Вы такое делаете? Обычно 500 Mb под инстанс монолита более, чем хватает.
Хоть числа и только как пример, но их соотношение вызывает вопросы… На микросервис конечно меньше памяти приходится, но во-первых не в 100 с лишним раз, а раз в 5-10, да и сумма памяти, потребляемой всеми микросервисами скорее всего будет в пару раз больше, чем нужно монолиту.
То, что написано в ТЗ, а что?
>Обычно 500 Mb под инстанс монолита более, чем хватает.
Вот прямо так, без понимания того, какие задачи решаются? Хм.
У Вас, видимо, есть несколько примеров веб-приложений, которые могут по делу откушать 16 Gb оперативки?
В статье только аббревиатура HTTP встречается 6 раз, не считая множества других признаков… Так что уместнее вопрос, с чего Вы взяли, что тут обсуждается что-то кроме веб-приложений?
И мы тут, между прочим, 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 слишком высокомерна по отношению к своим пользователям, примерно как Вы — к собеседникам )
И продолжаете это дальше — вы ничего не знаете про приведенную мной в пример систему, но при этом считаете, что она не может потреблять столько памяти. Продолжайте дальше — только без меня.
Нет, если потребляемое ОЗУ растёт линейно от кол-ва пользователей, то это нормально только для какого-нибудь кеша или in-memory БД, но там есть свои приёмы, чтобы ограничить потребляемую память сверху.
А для основного приложения — это совсем ненормально… Какой-нибудь reddit-эффект и у вас серваки вылетят с out of memory?
Под одновременными реквестами Вы имеете в виду в секунду или в минуту? Вообще, когда говорят про пользователей, обычно подразумевается, что в предыдущие N минут были какие-то запросы от 16 тыс. уников. Где N — время, исходя из которого границы визита определяются, для GA и Метрики — это 30 минут iirc. Напрямую rps из этого вывести сложно, не зная специфики приложения.
А начнут серваки вылетать, ставить запросы в очередь или ещё как разумно реагировать зависит от архитектуры.
Линейный рост потребляемого ОЗУ это норма, а часто идеал, которого не могут достигнуть.
Т.е. у Вас по графику потребления ОЗУ на сервере можно сразу видеть, где были пиковые нагрузки? Ни 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
Которое ваше приложение будет использовать как микросервисы :)
Вы загоняете себя в ловушку терминологий.
Если динамическая библиотека или консольная тулза является микросервисом, то все стоны из монитора — пустая трата времени и сил. Все и так стараются делать модульные приложения там, где это даёт прирост, и ни один здравомыслящий человек не будет агитировать радикально против модульных систем.
В противном случае понятие «микросервисы» как самостоятельный термин обретает смысл. Но этот смысл — радикальная форма модульности, которая применима к узкому числу задач разработки высоконагруженных систем. За их пределами польза от радикалов очень сомнительна.
И, кстати, выводит практически все программы из категории «монолит», ибо очень сложно найти приложение уровня пользователя, которое вообще не использует библиотеки операционной системы, на которой оно запущено.
Конечно, тут же можно возразить, что это уже не монолитная архитектура, но, во-первых, вы уже написали «Использование ffmpeg или системных библиотек как подключаемых не выводит приложение из монолитов.», а во-вторых, динамические библиотеки с минимальными усилиями можно* превратить в статические (больше всего возни с глобальными объектами, которые не шарятся между модулями), а те собрать в единое неделимое приложение.
*Есть исключения.
Подытожу, я не говорю, что микросервисная архитектура — это плохо, она позволяет легко и быстро производить горизонтальное масштабирование. Но она НЕ серебряная пуля, и НЕ даёт преимуществ над правильно организованным модульным приложением в тех случаях, когда горизонтальное масштабирование не требуется. Напротив, оно вводит как ряд ограничений, вроде используемых протоколов взаимодействия и полного разнесения данных, так и ряд накладных расходов, в виде медленных внутренних сокетов (по сравнению с общей памятью и стеком).
Если мы говорим, что «монолит» — синоним «модульного», у меня для вас плохие вести.
Которое ваше приложение будет использовать как микросервисы :)
Какая-то ложная дихотомия получается… Этак, если в проекте используется cron, то он уже микросервисным резко становится? xD
"Резко" микросервисным не становится. Смотря что крон запускает. Если какую-то часть приложения, то приложение уже не монолит.
Да-а-а? Представим себе что это микросервис авторизации.
Будет работать публичная часть приложения. У вас это только форма аутентификации? Но ведь будет работать!
Само не поднимется, но система может перезагрузить упавшее приложение.
Начнем с того, что в зависимости от предметной области могут быть связи между микросервисами. И пока ключевой сервис не поднимется, то остальные сервисы будут ждать и ничего не делать. Независимо от монолит или мокросервисы, восстановление и отказоустойчивость это отдельная тема.
Так же в зависимости от предметной области, некоторые сервисы легко масштабировать, а другие почти невозможно.
За что минус не пойму, аргументируйте чтоли
Не ставил минус, но, видимо за это:
Скажем в случае PHP, так и будет. А в случае компилируемых приложений, один раз упав приложение уже само не поднимется и станет недоступно по всех ендпойнтах.
Автоподъем сервисов реализуется нынче в любом продакшене. Хоть с микросервисами, хоть с крупносервисами.
Да, так тоже делают. Скажем, если в том же C# не использовать небезопасного кода, то довольно хорошо отрабатывает монитор в отдельном appdomain.
А можно эту задачу поручить и системе. Так, винда умеет перезапускать службы автоматически. В линуксе есть специальные обертки, которые занимаются перезапуском.
Средствами самого приложения?
Иногда. Чаще внешними средствами.
Такое впечатление, что вы в глаза не видели микросервисы, если считаете, что оно там как-то само поднимается.
Отнюдь не сами микросервисы себя восстанавливают. Микросервисы роутятся на резервные в случае аварии и поднимаются внешними средствами по отношению к микросервисам.
С крупносервисами — также. Но иногда в них реализован и автоподъем. Для микросервисов такого не делается, так как микросервис — это управляемый извне маленький винтик большого механизма.
Если интересно — см. Kubernetes — это сейчас один из самых развитых инструментов для управления микросервисами.
В случае микросервисов (независимо от технологий), если падает микросервис, то остальное приложение будет функционировать (естественно зависит от степени критичности упавшего микросервиса)
Не все так просто.
1. Все до единого микросервисы поднимаются довольно долго. В сумме это заметно дольше, чем один монолит.
2. Монолит никто не мешает делать как минимум дублем — оригинал и реплика. Даже 2 реплики — сейчас сие стандарт для серьезных систем.
Современные языки программирования и инструменты тестирования облегчили вам задачу в последние годы более чем.
Когда монолит отказывается выполнять какую отдельную функцию и это вызывает возврат сообщения об ошибке — сие совершенно нормально и совершенно аналогично микросервисной архитектуре.
Вы не там ищете преимущества микросервисов.
Их преимущества в возможности горизонтального масштабирования, которая недоступна монолиту.
И за эти преимущества приходится платить менее оперативным перезапуском именно системы микросервисов и задержками в их связанностях. У монолитов все проще и быстрее.
угу, проще и быстрей. Есть опыт деплоя монолита на продакшен ~ 3 часов.
Компилировали новую, предварительно опустив старую версию???
del
Микросервисы позволяют по мере необходимости обновлять приложение по частям. При единой архитектуре нам приходится заново развёртывать приложение целиком, что влечёт за собой куда больше рисков.
А разве развертывание по частям не несет риски нарушения Согласованности (Consistency)?
А почему никто не пишет, что при разделении монолита тотально падает время отклика системы? Вызов, который ранее случался через стек за несколько тактов теперь передается аж по сети, да еще с сериализацией в текст (http же).
Также возможность горизонтально масштабировать случается в ущерб возможности вертикально.
Согласен. Замолчали о важном факте.
Я считаю это необходимо добавить в минусы микросервисов.
Это означает только то что монолит был написан коряво. Если архитектура и бизнес-процесс позволяют из хранилища получать данные параллельно, то и монолит и микросервис могут их получать параллельно.
Если десять запросов можно сделать асинхронно — они и в монолите могут быть сделаны асинхронно — это не преимущество микросервисов.
А вот представить себе сто отдельных оракловых серверов вместо ста баз на одном физическом сервере мне как раз будет сложно — потому что это создаст лишние немалые расходы на их поддержку.
Вот именно! Почему-то многие проводит дихотомию "микросервисы — монолит", забывая об остальных вариантах архитектуры. И выдают за достоинства микросервисов любые недостатки монолита.
По факту, микросервисная архитектура часто позволяет ускорить отдельные компоненты (этому мы дали больше ресурсов, для этого обновили окружение, этот выкинули и переписали на ассемблере), а оверхед на взаимодействие между микросервисами пренебрежимо мал по сравнению с общим временем работы и скоростью отдачи результата клиенту.
Насчёт сериализации в текст — вот вообще не понял. Если у вас были бинарные данные, они точно так же и останутся бинарными. Если нет, то там тот же незначительный оверхед.
Вспоминаю, что было лет 10 назад — и понимаю, что EJB beans тоже были в значительной степени микросервисами. И те, и другие, не деплоятся сами по себе куда-то, а работают в контейнере — но это дает свои преимущества, скажем в плане мониторинга.
То есть, самой подобной архитектуре — ей сто лет в обед. Можно еще corba вспомнить, например. Скока это лет назад?
А дальше все зависит от того, где вы проведете границы между сервисами — может получиться хорошо, а может и не очень. Принципы — практически теже самые, что применяются «в малом» — сервис должен быть сильно связан внутри, и слабо снаружи. Так это верно для любого модуля, и это все знают.
Вот именно.
Отсюда возникает логичный вопрос: откуда такая шумиха?
Появились средства контейнеризации, облака — и достали из закромов старый прием и назвали по-новому.
А по мне очевидно — о деньгах.
Ребекка Парсонс считает очень важным, что мы больше не используем даже внутрипроцессное взаимодействие между сервисами, вместо этого для связи мы прибегаем к HTTP, который и близко не бывает столь же надёжен.Спрашивается, ради чего необходимо отказываться от технологии, которая позволяет сэкономить время и ресурсы? Очевидно, деньги. И дело не столько в экономии самих тактов, сколько в создании новых квазипродуктов и захвате рынка у классических инструментов. Что мешает создать генератор API под все платформы и языки над MPI, к примеру? Почему нет? Видимо, потому, что рост рынка будет незначительным, а все деньги уйдут разработчикам MPI.
Можно еще corba вспомнить, например. Скока это лет назад?
Трепыхается еще родненькая.
О преимуществах микросервисов стоит судить не с точки зрения "модули, которые общаються по хттп вместо in-process call, зачем?", а с точки зрения облачного развертывания. Это скорее набор микро-приложений (а не модулей), которые друг с другом взаимодействуют мало и редко.
Представьте банковские сервисы: сервис курсов валют запрашивают миллион раз в день, сервис свифт-переводов — тысячу раз. В облаке дешевле отмасштабировать только нагруженный сервис — деплой и контейнер дешевые (бесплатные), плюс автомасштабирование от облачного вендора будет дешевле.
Т.е. содержание облака с двумя микросервисами, которые получают 1000000 и 1000 запросов за день будет дешевле содержания облака с двумя монолитами, которые получают 500000 и 500 запросов за день?
Вы утверждаете, что он, при низкой нагрузке, будет жрать больше ресурсов, чем система микросервисов.
"Размазывая" работу монолита по микросервисам вы не уменьшаете общую нагрузку.
Монолит не будет есть больше ресурсов только потому что он монолит.
Монолит потребляет столько же ресурсов, как и микросервисы при одинаковой нагрузке. Просто некоторые части из которых он сложен буду простаивать.
Так что никакого оверхеда нет.
А что именно в простаивающем приложении может потреблять ресурсы?
Мне приходит на ум только "лишние" модули/библиотеки загруженные в память. Но это ничтожно мало.
Плюс (тут я не уверен, чисто как идея) — не будет ли проблем при запуске на одной машине нагрузки разных типов — множества быстрых запросов или маленького количества медленных, либо грузящих диск, или процессор.
Если монолит — полный stateless и содержит в себе только обработчики запросов — то разницы нету.
Если монолит содержит в себе какое-то состояние — явное или неявное (кеши, сессии в памяти, восстановленные CQRS агрегаты ), или поведение — задачи по расписанию и т.п. — то разница есть, и значительная.
А вот тут я с вами соглашусь.
Тем не менее, вы сами даете решения для монолита: stateless, липкие сессии, отдельный инстанс для задач по расписанию, распределенный кэш.
Хотя в этом случае задачи по расписанию можно выделить в отдельный микросервис, ибо ферма монолитов, будучи неправильно настроена, может конфликтовать пытаясь конкурентно выполнять эти задачи.
Получается, что микросервисы, в некоторых случаях, все же лучше чем монолит с состоянием.
Не если сравнивать с монолитом без состояния, увы, опять не вижу преимуществ.
Независимая эволюция подсистем
Микросервис может развиваться и ломать обратную совместимость, не обременяя себя поддержкой старых версий, так как всегда можно оставить старую версию микросервиса работающей необходимое время.
Монолитное приложение делится на сборки (пакеты, динамические библиотеки).
Давно существуют технологии их параллельной (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
На других операционках да — ставится ВМ с Linux и на ней работает Docker. Про Windows не скажу — много лет уж не пользуюсь, но на макоси Docker безбожно тормозит и есть много геморроя с настройкой сети.
Создайте базовую клиентскую библиотеку HTTP REST, оптимизированную для REST-вызовов, на основе которой можно строить конкретный микросервисный клиент, им будут пользоваться другие микросервисы. Этот оптимизированный клиент должен быть портирован на все языки, применяемые в вашей экосистеме.
HTTP REST сомнительное решение для API микросервисов, бизнес-логика которых не состоит большей частью из CRUD операций над сущностями, а состоит из масштабных изменений (включая создание и удаление) состояний сущностей в ответ на какие-то события в другом ограниченном контексте или явные команды пользователей с небольшой полезной нагрузкой.
Какие-то варианты RPC и(или) MQ в случаях когда большинство сценариев использования выглядит примерно как (в скобках полезная нагрузка):
— зарегистрировать нового клиента (куча персональных данных)
— создать (список товаров и их количества) и предоставить ему договор со статусом «черновик»
— при подписании (просто событие) изменить статус договора на «подписан» и сформировать и предоставить счёт на оплату
— при оплате (сумма) и её достаточности изменить статус договора на «доставка» и сформировать бухгалтерские проводки и ордер службе доставки
— … куча событий службы доставки в другом контексте
— при получении подтверждения о доставке (просто событие) изменить статус договора и ордера на «исполнен», перенести договор их оперативного хранилища в архив, поставить «лайк» менеджеру для системы мотивации
И это только идеальный сценарий и без получения оперативной и глобальной аналитики
По сути у нас лишь две операции явно создающие какие-то сущности/ресурсы и куча неявных побочных созданий, изменений и т. п. других сущностей, о которых часто даже информировать инициатора запроса не нужно, просто сообщить ему «ваш запрос принят к обработке», а информировать надо кого-то другого.
А там в статье ровно это и написано — если у вас есть новый проект, не делайте его сразу на микросервисах. Но постарайтесь сделать его архитектуру такой, чтобы при необходимости, вы могли выдернуть из него компоненты и преобразовать их в микросервисы. "правильная архитектура" она же из нечего не появляется сама по себе. За ней должна какая-то идея стоять. Вот микросервисы и есть одна из таких идей. Примуществом этой идеи является то, что она достаточно внятно сформулирована.
Как и с любым инструментом, микросервисы нужно уметь правильно готовить. Не в смысле взял докер, разделил базы, выставил api в виде rest, etc. А в смысле, правильно оцениваешь риски и выгоды, и распределяешь их в оптимальном сочетании.
При «умелом подходе» на микросервисах запросто можно сваять известную коричневую органическую массу.
Точно так же как и при использовании монолита.
Верно и обратное, с головой можно качественно ваять и на микросервисах, и на монолите.
Главное преимущество микросервисов перед монолитами — собственно говоря почему про микросервисы говорят из каждой кофеварки — микросервисы лучше чувствуют себя в cloud.
Если брать полный стейтлесс монолит, то он будет идентичен микросервисам в плане цены масштабирования только при условии, что хранилище данных масштабируется независимо.
Однако нагруженные микросервисы можно вынести на отдельные базы, если они допускают определенную несогласованность данных. Монолит так масштабировать обычно нельзя, т.к. некоторые части должны все-таки работать с согласованным хранилищем.
некоторые части должны все-таки работать с согласованным хранилищем.Зависит от бизнес процессов.
Все остальное прекрасно реализуется на монолите.
Просто у кого-то в голове возникает образ некого скомпилированного исполняемого файла, который при всем желании невозможно масштабировать количеством запущенных копий и балансировщиком перед ними.
А если представить RAILS-приложение(и подобные), которое вроде как монолит, то там прекрасно всё масштабируется. Тут единственный существенный минус — это выкатка новых версий подсистем монолита.
Зато, например, какая хорошая утилизация железа. Есть 10 серверов, раскатываем монолит на все сервера и гоним через балансировщик запросы. А в случае с микросервисами придется решать задачку — какой сервис на какую/какие машины раскинуть. В итоге часть железа простаивает, ибо заложили под пики нагрузки. Это можно победить, но ценою усложнения системы.
Отчёты обычно формируются на основе сложных запросов к БД. Поэтому на порядок лучший профит получится, если формировать отчёт запросами к реплике БД, а не от того, что основная БД будет также загружена запросами из другого процесса.
Так формирование отчёта по уже выбранным данным не требует гигабайтов оперативки, если это не отчёт на несколько тысяч листов. SQL для того и существует, чтобы из БД только нужные для отчёта цифры достать. Или Вы имеете в виду, что можно косячно формировать отчёт, но вынести это в микросервис и уже будет не так заметно, что отчёт формируется чёрти как?
Забыли про ещё один момент: цена добавления и последующего удаления временной функциональности из монолита.
Когда есть монолит и есть запрос «доделать существующее, но хитро» то есть большой соблазн это сделать именно в рамках монолита, хотя и известно, что это нужно временно (спустя год эта функциональность уже будет не нужна). Что же, добавляем функциональность, дорабатываем её, развиваем, а через некоторое время её нужно будет удалять и «выкорчевать» вросший в монолит код уже будет непросто. А если не выкорчёвывать, то будет мёртвый код, который будет постоянно мешать обновлять фреймворки и языки программирования и т.д. и т.п.
А если сделать под этот запрос отдельное приложение, то удалить его будет очень просто :-)
- Вызывать;
- Обрабатывать;
- Сохранять результат.
- Вызываться;
- Обрабатываться;
- Сохраняться.
- Вызова;
- Обработки;
- Сохранения.
Если вы считаете, что я в чём-то ошибаюсь — скажите, в чём?
- Вызывать можно банальным редиректом или отдельным upstream'ом в Nginx.
- Обрабатываться оно будет в отдельном приложении-микросервисе
- Сохраняться будет в отдельную БД.
Сразу бонусом получаем лёгкость переноса этой функциональности (вместе с базой, которая в обычной архитектуре веб-приложений является «бутылочным горлышком») на отдельный сервер в случае резкого прилёта нагрузки на неё из-за которой начинает тормозить всё приложение.
Да, в монолите это всё тоже можно делать, но сложность монолита начинает расти, и разбираться в его коде тоже становится сложнее.
2) Обработка не в смысле выполнение временной функциональности, а в смысле реакции остальной системы на возможные сценарии работы временной функциональности. Она в любом случае должна будет покрывать все стандартные ситуации работы Это я не про вылеты-перезапуски, а про вполне буднечные запросы-оповещения «я покушал» и «я покакал».
3) Данные подготавливаются не для повышения энтропии, а для вполне себе утилитарных нужд. Это значит, что они либо будут переводить систему в другое состояние (например, эмуляция оборудования), либо отображаться пользователю этой самой фичи (нужно будет создать запросы и, возможно, UIшки для отображения данных). То есть потребители данных должны получить унифицированный интерфейс, который возникнет не из воздуха, а будет внедрён в существующие модули соответствующей функциональности. А потом — удалён. И если вы думаете, что в микросервисах проще создавать эти самые связи внутри модулей, чем у монолита, опять же, вы либо не особо понимаете разницу, либо программировали монолиты в те времена, когда были говнокодером.
Иными словами, мантра «отдельное приложение» лично мне ничего не говорит. Да, есть лёгкость горизонтального масштабирования, а унифицированный API с удобным встраиванием есть? А отладка как, не хромает? Удобно ради какой-нибудь банальной мелочи целый микросервис городить и гонять тонны данных вместо внедрения пусть и неуместного в каком-нибудь контексте кода?
Да, сложность монолита растёт, но она растёт не быстрее, чем сложность взаимосвязей микросервисов.
У вас какой-то переусложнённый пример в голове, как мне кажется.
Пример из жизни, который доставил мне боль и думая про который я писал комментарии: тупо веб-сайт.
Дано: веб-сайт с функциональностью создания опросов для пользователей (не основная функциональность, но есть).
Задача: сделать более хитрые опросы да ещё в разрезе подчинённых организаций (что-то типа, устроило ли вас обслуживание). Аутентификация-авторизация не нужна, UI отдельный, нужна выгрузка результатов в Excel. Взаимосвязи с остальным сайтом 0 (ноль).
Как сделали: добавили новые типы опросов (куча условной логики везде), новые шаблоны, справочник долбаных организаций в админке и ещё одна библиотека для работы с Excel (чем не устроила предыдущая, история не сохранила). А потом ещё некоторые из организаций начали активно себе накручивать голоса (вот тут приехала нагрузка, часть из которой была вызвана логикой отложенной обработки голосов, не нужной именно этой функциональности).
Как надо было сделать: скопировать всю базовую функциональность в отдельное приложение с отдельной базой, доработать её там, навернуть любых библиотек и наворотов по желанию, развернуть на отдельном домене и сервере и после того, как оно поработало и заказчик получил свои результаты — удалить нафиг сразу вместе с той виртуалкой, на которой оно было развёрнуто.
А приведённая вами в пример задача в её текущей формулировке звучит скорее «нам дали протухшую задачу, мы наспех дерьмово спроектировали модули и не сделали бекапов, поэтому не проехали на Оке и пришлось вызывать говномесные тачки». Ваше решение «сделать всё то же самое, но на бекапе». Иными словами, у вас в любом случае были бы и новые шаблоны, и справочник долбаных организаций в админке, и ещё одна библиотека для работы с Excel, и куча условной логики везде. Ничего бы не изменилось. Ваша основная проблема в том, что никто не подумал изначально сделать опросы максимально изолированным модулем, чтобы его изменение не требовало такой боли. Проблема не в том, что opinion_poll.php был куском Monolith, а в том, что он не был ограничен opinion_poll.php и opinion_poll.html
Кстати, роуты в Rails проверяются по порядку, так что если у Вас реально проблема с тысячами неиспользуемых роутов, то вынесите десяток реально используемых на самый верх routes.rb и остальные роуты будут отнимать ресурсы на проверку раз в году, или когда там до них дело дойдёт )
Естественно сопоставление роутов идёт с учётом метода. Это не значит, что из-за этого проверять придётся все. Но в память загрузятся все — это да… несколько десятков килобайт займут )))
А я понял, Вы про роуты, которые для всех методов подходят. В таком случае в Rails будут просто игнориться все последующие дубликаты этого роута с указанием конкретного HTTP-метода. Хотя допускаю, что где-то роутинг может искать best match до победного конца, но имхо это странный вариант… first match будет всегда работать быстрее.
Пример: небольшая компания делает внутренний проект, пользователей несколько десятков по стране. Делает один человек. Естественно получается монолит в каком-то смысле. Потом добавляется второй проект, как-то связанный с первым — второй монолит. Потом ещё несколько. Все они взаимодействуют. Потом оказывается, что внутри первого есть малосвязанные компоненты, как-то друг с другом общающиеся все по разному — кто через базу, кто через CGI скрипт со странными форматами передачи данных, кто-то поставляет на соседний сервер обновления через rsync — зоопарк. Так как проект растянулся на десятилетия, есть архаичные версии систем, языков, технологий и библиотек. Проект работает сам собой годами, без серьёзного вмешательства. И тут надо что-то поменять. Небольшое. Например добавить 1000 пользователей. И оказывается что поменяв в одном месте — поменяется и в другом, а даже наличие описания не помогает потому что архитектура требует одного сервера в узком месте. Перенести на новую ОС не удаётся — там давно не поддерживаются старые библиотеки. Базы данных, которые обслуживают части монолита, не поддерживаются уже 10 лет но там где запущены — работают как часы и все забыли что они есть. Вот реальная проблема реальных систем не топовых компаний. На этапе разработки термина "микросервисы" не было. Теперь понятно, что надо было стандартизировать общение между компонентами и разделять на куски в расчёте на поддержку некоторых кусков 20 лет без изменений, а других править каждый день.
Сейчас огромный плюс разделения на микросервисы — возможность разделения задачи на разные языки и технологии и поддержка маленьких компонентов случайными людьми — по мере необходимости нанимаем специалиста по эрлангу или перлу или яве на текущую задачу на пару месяцев и всё хорошо. Сервис маленький, описание простое, протестировать можно. 20 лет назад были модны программисты-универсалы, сейчас больше одного-двух языков/технологий знают единицы. А выбор языка диктуется самыми разными причинами — например описание API на swagger довольно жёстко задаёт выбор одной из 20-ти технологий из которых половина Java.
А облака… это всё хорошо, но как-то облачно. Масса организаций в облако не отдаст ничего.
В общем, микросервисы — красивый термин, и статья как раз хорошо описывает что это такое на самом деле, без приукрашиваний.
Мне кажется оптимальным начать с монолита, а походу смотреть и находить линии «разреза». Так не только я считаю, и другие видят в этом нормальную стратегию.
бизнес-задачЭто очень расплывчатое понятие, а модуль авторизации, модуль суммирования массива или другая арифметика, модуль поиска числа в массиве — бизнес задачи или нет? А если сервис (node.js) просто пересылает данные из nginx в mysql и обратно — бизнес логика/микросервис?
Я считаю проще, если я делаю какой-то (сетевой) вызов в другой самостоятельный процесс, то этот процесс — (микро)-сервис. Просто mysql/redis — это уже обыденность и не хочется признавать это микросервисами, т.к. микросервисы — это вроде как повышенная сложность. К тому же некоторые хранят часть логики в самой БД.
Не совсем в тему микросервисов, но хочу заметить, что слово "бизнес" применительно к архитектуре приложения не имеет (в общем случае) отношения к коммерции, а обозначает ту "пользу", которую приносит конкретное приложение.
Поэтому сервис авторизации для конкретного приложения — это бизнес-функциональность, но в то же время используемая библиотека для OAuth2 — это уже не бизнес-часть, т.к. она универсальна и не привязана к предметной области.
Поэтому суммирование массива — не бизнес-функциональность, если у нас, конечно, не приложение по суммированию массивов (Excel).
1) От транзакций. Главный минус
2) Получаем проблемы с версионной совместимостью этих микросервисов между собой
3) Вместо работы внутри процессора и системной шины мы гоняем данные по медленной сети и всему сетевому стеку. Сильное замедление работы. Получаем сильную зависимость от качества сети
4) Повышение надежности — миф. Приложение не может работать без какого-то компонента. Это будет некорректная работа.
5) Все эти микросервисы в сумме потребляют больше памяти и ресурсов, чем монолит
6) Вынужденное дублирование кода. Либо приходится делать какие-то отдельные проекты с общим кодом
7) Невозможность рефакторинга. Мы получаем кучу внешних интерфейсов, которые нельзя трогать. Либо придется править одновременно все микросервисы
8) Сложность при обновлении, если изменился внешний интерфес. Приходится обновлять одновременно несколько микросервисов. Если будет рассинхронизация — клиенты получат ошибки.
9) Сложность правки базы. Сложно понять, использует ли эту таблицу какой-то другой микросервис. Приходится пересматривать код всех микросервисов. И опять возникает проблема одновременного обновления.
Что получаем взамен? Мнимую красоту кода. И больше ничего. Очередная серебряная пуля
Про базу (п. 9) вы загнули. У каждого микросервиса должна быть своя база, или хотя бы своя схема в общей базе.
т.е. отказываемся от форенкеев и дублируем данные?
Если данные надо дублировать — значит, граница ответственности микросервиса обозначена неправильно.
Например модуль складского учета и финансовый модуль. Произошла ошибка в финансовом модуле. Как откатить транзацию в модуле складского учета?
Не надо откатывать. Надо повторять попытки достучаться до финансового модуля в фоне. Это и есть та самая устойчивость к отказам — складскому учету не нужен постоянно работающий финансовый модуль.
У вас ошибка в комментарии:
вместо медленных транзакций
Почему вы стандартные решения называете велосипедами?
Как вариант можно сущностям добавить статус. И пока статус не станет подтвержденным их видно, но ими нельзя воспользоваться. Соотвественно можно мониторить зависшие в невесомости вещи и принимать какието решения/меры по их исправлению.
это явно не стандартное решение.
Ендпоинты — тоже довольно редко применяются и поддерживаются далеко не везде
Произошла ошибка в финансовом модуле. Как откатить транзацию в модуле складского учета?Вообще эти 2 могут быть в одном микросервисе, в разных «черных ящиках» (модулях). Но если все же они отдельно, вызов финансового модуля должен быть быстрый (0,1-1 сек), в итоге если фин. модуль возвращает ошибку, то откатываете незакрытую транзакцию в складском.
Если фин. модуль выполняет метод долго (1-10 мин), то у вас проблемы другого плана, т.к. такие долгие транзакции очень не желательны (особенно которые блокируют «пол базы»). И если нет возможности ускорить, например это внешний платежный сервис, который ждет когда пользователь кликнет кнопку, то вам нужно использовать 2-х фазный комит. И микросервисы в этом случае не осложняют ситуацию.
Но вообще, зачастую можно встретить когда микросервис осложняет транзакцию, это подразумевает использование одной БД, а значит имеет смысл держать эти части в одном микросервисе.
PS: Я за «монолит на старте»
как делать одну транзакцию поверх нескольких микросервисов?
Вариантов куча, от самых простых типа залогировали ошибку, саппорт пускай разбирается, до промышленных координаторов транзакций от ведущих брендов типа МС и Оракла. Тем более на практике всегда есть транзакции, которые вроде бы одно целое, типа получил деньги и отдал товар, но в особых случаях откатить не получится, если что-то пошло не так, например, деньги взяли в кассу, провели и свет отрубился, ни деньги не вернуть, ни товар не отгрузить.
— 2 phase commit
— eventual consistency
У каждого свои плюсы, минусы. Упомянутые принципы ортогональны к микросервисам или монолитам. Просто подходы к обеспечению целостности наряду с традиционным ACID.
Такое впечатление, что микросервисы, по-вашему, — это как dll, только доступные по сети.
А также пользователь может заблокировать любого другого пользователя, даже друга, и тогда заблокированный пользователь не сможет увидеть публикации.
Как в микросервисах хранить заблокированных пользователей? Ведь они нужны в 2 микросервисах: публикации и друзья.
Как это сделать, если базы разные?
База самого микросервиса вполне целостная.
только в пределах одного микросервиса.
Что делать, если id пользователей рассинхронизируются между базами?
Внешние ключи придуманы чтобы не оказалось, например, позиции на складе, которая принадлежит не пойми кому.
А ситуация, когда позиция на складе принадлежит клиенту, который больше не клиент — возможна и в жизни ("оставил и ушел"). А значит, должна иметь отражение в базе.
З.Ы. Монопольное владение.
т.е. отказываемся от форенкеев (целостности базы)
Не драматизируйте. Всего лишь отказываемся от обеспечения целости данных в рамках всего приложения средствами СУБД. В рамках микросервисов целостность обеспечивается средствами СУБД, а целостность между ними обеспечивается другими средствами, если она вообще нужна.
Что вы предлагаете делать: дублировать их в разных базах или дергать отдельный запрос на каждую запись в списке?
Дублировать.
Не смысла бороться за размер хранимых данных кроме как в самой большой таблице. В складском модуле самой большой таблицей будет журнал операций. Каждый клиент будет связан как минимум с двумя записями журнала, а скорее всего их будет еще больше.
Тут три варианта.
Никак! ФИО в журнале операций должно быть таким же, что и документах (например, в накладной). А там данные измениться не могут.
При получении свежего токена от пользователя данные о нем в базе обновляются. Таким образом, ФИО в журнале будет старым пока пользователь не обратится (прямо либо опосредовано) к сервису.
- Изменения данных пользователей публикуются другим сервисом, а складской модуль на них подписан.
Потому любые ваши наезды «обеспечьте», вообще-то не по адресу, так как речь идёт именно о том, что (микро-)сервисная архитектура этого сделать не может, на это способен только монолит. То есть распределённая база не может давать гарантии, в ней всё всегда вероятностное. В рамках одного единственного mysql же (или postgresql, который давно уже чавкает жсонами) такую целостность обеспечить очень просто и достаточно дёшево.
Ясное дело, что люди переходят на связки манги и мускула не от хорошей жизни, но не нужно, как веганы, верещать во все стороны «Я давлюсь этим сельдереем уже два месяца и отлично себя чувствую, а вы такие злые из-за мяса.» Вы НЕ можете обеспечить 100% целостности и синхронности в микросервисах, и никогда не сможете. Факт. Но вы можете повысить производительность и понизить вероятность ошибок так, что погрешности с лихвой покроются прибылью. Тоже факт. И не нужно городить что-то ещё.
Вы НЕ можете обеспечить 100% целостности и синхронности в микросервисах, и никогда не сможете.
Вы отрицаете, что не только CA системы, но и просто C (в терминах CAP) существуют и эксплуатируются?
Вы сами написали, что вне единого транзакционного центра нужно рвать жопу сложными логами и прочими приблудами. Вы сами написали, что вне единого транзакционного центра мы можем гарантировать согласованность лишь атомарной операции. А теперь вы спрашиваете такие, простите за выражение, тупые вопросы? Повторюсь, я их не отрицаю. Я констатирую, что CA и C системы не могут быть распределёнными по определению.
Остальное верно, Они тоже вероятностные. Отсечение вероятностей возможно только монопольным владением, о чём монолиты и есть. Ибо если приложение монолит, оно точно знает, что кроме него самого никто не мог внести изменения в его хранилище, и что транзакции никто, кроме него вносить не может. А микросервисы? А что микросервисы? Сегодня он есть, а завтра их десять. Какие гарантии?
На самом деле микросервисы мы используем очень давно, просто теперь есть тренд не только использовать, написанные (а то и воплощенные в железе) кем-то, но и писать их самим. Да, сложность разработки (в плане увеличения количества контролируемых разработчиком процессов и связей между ними) увеличивается, но это плата за другие преимущества, прежде всего за возможность дешевого горизонтального масштабирования в целях, прежде всего, увеличения доступности архитектурными средствами самого приложения, а не внешними «микросервисами» типа СУБД.
А на самом деле, классическая клиент-серверная или трехзвенная архитектура с РСУБД не может обеспечить CAP (даже сама СУБД не может, поскольку распределяет функции между своим ядром и ОС, имея вероятность как отрапортовать о законченной транзакции, которую по независящим от СУБД причинам клиент не увидит, так и закончить транзакцию, не уведомив об этом клиента), а микросервисная может обеспечить CA, CP или AP на выбор, так же как классика. Ничем они принципиально не отличаются, кроме того, что в случае микросервисной архитектуры на разработчика возлагается бОльшая ответственность за балансирование между метриками CAP, все из которых не могут достигать 100% ни в одной практически возможной архитектуре, только лишь вероятностные, пускай и с кучей девяток, даже в самых дорогих проектах типа космических, где применяется многократное резервирование всего и вся лишь с целью набрать побольше девяток, но стопроцентных гарантий нет, ведь сама аппаратная база носит вероятностный характер, а для защиты от сбоев используются методы теорвера и матстатистики, уменьшающие вероятность незамеченных сбоев и даже где-то исправляющие их, но не сводящие её к 0%. Например, какая-нибудь ECC-память способна исправить один и заметить ошибку в двух неправильных битах в слове, но если ошибка в трёх, то она даже обнаружить это может быть неспособна.
Весь срач из-за нежелания большинства разработчиков так называемых монолитов признать, что они давно используют сервис-ориентированные архитектуры, просто сами разрабатывают только один сервис из множества используемых их приложением, перекладывая ответственность за CAP-метрики всего приложения на плечи разработчиков этих сервисов таких как СУБД, веб-серверы, и ОС.
Мы можем говорить о микросервисной архитектуре, как о продукте из независимых модулей-приложений с отдельными базами данных и взаимодействии только по HTTP. А о монолите, как о приложении, в котором все части написаны на одном языке и реализуются через внутренние вызовы, которое собрано в общий бинарик, но которое, в принципе, может использовать внешние сервисы через публичный API. И то, и то — радикальные формы архитектуры, имеющие в своём радикализме огромные неустранимые в рамках самих себя проблемы. Монолит — в масштабировании, а микросервисы — в накладных расходах и проблемах с синхронизацией.
А истина, как обычно, где-то посередине, там, где валяются DLL-ки, где куча пайпов и потоков, где разделяемая память трясёт мутексами и критическими секциями и где, прежде всего, продуманная архитектура внутреннего взаимодействия с разделением в тех местах, где оно может понадобиться. Короче, там, где нас нет.
Протокол взаимодействия сервисов между собой к архитектуре особо не относится. Мы вон активно AMQP используем. И даже разделяемая память и прочие мутексы может быть частью протокола, если условный монолит был однопроцессынм и мы решили его масштабировать горизонтально хотя бы в пределах одного процессора по процессу на ядро.
Вы скажете, это излишнее усложнение? А вот это вопрос дискуссионный. Как и предложенное вами разделение. Есть у меня, например, сервер онлайн-игры, и есть сайт. На нём чат, совмещённый с игровым, лента новостей, лента внутриигровых событий. Аутентификация через клиент. И как делить, что тут микросервис, что тут сервис? В драке на ножах, не иначе. Да и сам сервер, с одной стороны, делится на микросервисы, а с другой — не делится. Потому что есть сотни разделений, которые можно провести для правильных абстракций и ещё тысячи — для неправильных, но всё ещё очень симпатичных. И будет ли такое разделение сервисом или микросервисом — это прекрасная тема для дискуссии за пивком под воблу, но совершенно лишняя у клавиатуры с IDE-шкой на мониторе.
И по протоколу, лично вы, конечно, можете использовать любые, но вы, видимо, не читали самой статьи. А в ней красной линией проходит мысль, что вы делаете это внеправильно, а правильно — через веб-сокеты. Это мысль из статьи, и я с ней не согласен, но эта мысль встречается не впервые, её активно проталкивают.
Да не надо делить сервисы на микро и «макро» у клавиатуры. Когда ответственность сервиса выродится в ответственность только за одну сущность или за один процесс, тогда можно констатировать, что он стал микросервисом. А можно не констатировать, можете продолжать называть его сервисом.
Это вы, видимо, невнимательно читали статью, в ней фразы типа «например HTTP», «вроде HTTP» — просто HTTP самый популярный способ для создания интерфейсов микросервисов, особенно на первых этапах разбиения монолита на сервисы, в том числе и микро. Он синхронный, он поддерживается из коробки, наверное, всеми мэйнстрим языками, он простой (если использовать его в качестве транспорта, а не пытаться реализовать всю его семантику). И во многих случаях он уже используется в системе для общения с клиентами.
Зачем такое повальное поклонение «золотому бычку»? Спойлер: раскрутить тему и продать больше своих решений.
Всё, что написано в статье, всё целиком уже давно известно. А всё что вы написали, ВСЁ ЦЕЛИКОМ сводится к «наймите толкового системного архитектора». Вот только ни в статье, ни у вас не написано, как обеспечить привычные для монолита согласованность данных, да и организовать транзакции вообще. Готовых решений нет, а все варианты сводятся к «нажарь свою СУБД».
А я буду стоять на своём «нужно думать, что делаешь — и не поддаваться на веяния моды и чьи-то сладкие речи», И ни Аллах, ни шайтан не смогут сдвинуть этого упёртого осла с его места.
Является ли сервис микросервисом определяется не техническими характеристиками, а архитектурными — количеством ответственностей в рамках общей архитектуры системы — у микросервисов оно стремится к одной.
Согласованность и транзакционность привычно обеспечивается не самим монолитом, а средствами СУБД в рамках трехзвенной архитектуры: клиент-сервер приложения-СУБД, то есть монолитом является сервер приложений с весьма ограниченным собственным состоянием, а целостность и транзакционную изоляцию он доверяет другому серверу/сервису/микросервису — СУБД. При решении архитектора разбить монолит на сервисы/микросервисы есть множество способов обеспечить согласованность и транзакционность между ними, первый из которых убедиться, что она действительно нужна во всех кейсах, а не суется по привычке, потому что разработчикам это практически ничего не стоит. Нужен индекс для поиска по идентификаторам клиента в таблице заказов, есть первичный ключ у таблицы клиентов, почему бы его не сделать внешним ключом к таблице заказов, даже если от аналитиков/заказчиков не было требования обеспечить ссылочную целостность. Вот есть явное требование что поле «идентификатор клиента» должно иметь возможность ссылаться на несуществующую в таблице клиентов запись, тогда не будут делать внешний ключ, а нету — будут. То же и с транзакционностью. Вот сейчас уничтожаю транзакционность в модуле приема платежей от платежной системы. разработчик модуля писал информацию о сообщении платежной системы о платеже в таблицу для этих сообщений, потом собственно в таблицу платежей финансового модуля, транзакционность явно не использовал, но она во фреймворке по умолчанию. В результате при нарушении целостности во второй таблице мы теряем запись о платеже вообще. Не, ошибка в логи пишется, но читать их начинают только когда клиент приходит жаловаться с чеком платежки на руках.
Это число всегда зависит от нашей точки зрения. Для одних чат для работы с клиентами будет микросервисом, а для других он будет сложным продуктом из скрипта на сайте, серверного приложения с балансёром нагрузки и планировщиком, клиентов для службы поддержки и административных инструментов. И, что самое противное, со своих колоколен все будут правы.
«Фрукт — фрукт, сиська — сиська, цветок — цветок. То же самое, мать твою!» © «Чёрные паруса»
Этот конкретный пример говорит лишь о том, что предыдущий разработчик думал чем угодно, но не головой. Или вы рассказываете не всю правду, а лишь то, что вам выгодно. Ещё ни один программист не сказал, что транзакции и внутренние зависимости — это плохо. Они могут быть неудобными, долгими, сложными, но все альтернативы — хуже. Конкретно в этом примере есть две проблемы с транзакциями: не хранится отдельно таблицы с запросами на проведение операции, и нет реакции на провалившиеся транзакции (или, шире, нет поля результата запроса на операцию). Или оно есть, но его никто не пользовал. Но это уже другая история.
Микросервис чата — фасад для сложного сервисного приложения. Для пользователей микросервиса чата — чат микросервис, для его разработчиков — сложная распределенная система.
Я говорю, что лишние транзакции и лишние ограничения на согласованность — плохо. Транзакция должна быть ограничена минимально необходимыми рамками, согласованность должна помогать не выстрелить себе в ногу, но не должна мешать всему остальному.
Таблица хранится, при успешном платеже формируется две записи — запрос на платеж с успешным статусом и собственно платеж. При неуспешном есть только запись в логе (реакция на ошибку).
Капитан сообщает: надо сохранять id пользователя.
А что если между запрашиванием списка френдов юзера и SELECT'ом постов, меня заблокировали, я получу публикации которые не должен был получить.
А что если между запрашиванием списка френдов юзера и SELECT'ом постов, меня заблокировали, я получу публикации которые не должен был получить.
Вы получите публикации которые вы могли бы получить если бы запросили их секундой раньше. Это не проблема.
Проблема будет, если запрашиванием списка френдов юзера и SELECT'ом постов другой пользователь сначала блокирует вас, а потом публикует что-нибудь. В таком случае вы можете получить публикацию, которой никогда бы не смогли получить при последовательном исполнении запросов.
Потом эти же селекты раскидать на независимые сервисы, которые работают параллельно, отвечают асинхронно и склеить все в ноде.
кроме гетерогенности преимуществ почти что и нет
а гетерогенность да - мало радости поддерживать 10 летний код, который нельзя обновить из-за глобальных стопперов (deprecated команды которые не позволяют например поднять PHP с 7 на 8).
Код говно, про изоляцию разных модулей никто не думал, про нормализацию данных тоже, даже внешних ключей нет. Это приводит к тому что рефакторить бесполезно, надо переписывать кусками, каждый кусок с нуля (от старого приложения полезна только устоявшаяся и проверенная бизнес логика).
К тому же код сейчас можно писать лучше, многократно компактней и понятней
Спасибо автору за то, что столько всего прочитал и переработал)
Архитектура микросервисов