Pull to refresh

Comments 237

UFO just landed and posted this here
Вы прочитали 1 книгу и делаете выводы. Есть очевидные места где надо делить. Просто не надо впадать в крайности.
UFO just landed and posted this here
Ну вот например, пользователь загружает видео файл. Его нужно сконвертировать в другой формат, другое разрешение. Тут очевидно, что эту задачу нужно выделить в отдельный сервис.
Или, аналогично. Пользователь загружает 3D модель, для неё нужно срендерить превьюшки. Ну не будете же вы это делать в томже приложении?
Очевидно что это нужно сделать сразу. Иначе у вас не будет возможности дорасти, потому что у вас вашего приложения не будет пользователей.
Потому что завтра нужно будет отрендерить миллион превьюшек. Хорошо 50 тысяч. Тысячу.

И что? Если это не главная задача то наверное нагрузка на рендер будет меньше чем на все остальное. Особенно когда посетителей не более тысячи в час.

Откуда вы знаете какую модель загрузит пользователь и сколько она будет рендериться? Если у вас виртуальный сервер 2 vCPU, 4 GB RAM и 3 пользователя начнут одновременно загружать сложные модели, то ваш сервер встанет на какое-то время (под превьюшками я имею в виду полноценные картинки нормального размера, а не 100x100).
Вместо этого логично отсадить рендер на отдельный сервер и рендеринг ставить в очередь. И даже если он встанет раком, это никак не повлеяет на работу всего сайта.

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

Зачем добавляшь еще один веб-сервер, если один и так справляется? А если не будет спраляться веб-сервер, зачем добавлять еще 1 рендерер?
Это немного отклонение от темы, но рендеринг 3D моделей обычно происходит на GPU, а сервер с GPU на порядок дороже сервера без него. Получается, если вдруг веб-сервер будет неспраляться с кол-вом запросов, вы добавите еще 1 сервер с GPU просто потому что это логичнее?
Вот это хороший ответ на «почему нет?» выше.
Почему это очевидно? Это прекрасно может работать в рамках монолита.
Пользователь загрузил 20-и минутный видео файл в качестве 1024p. Его нужно предобразовать в видео меньшего разрешения: 720p, 480p и 360p. Какой алгоритм будет в монолитном приложении?
Пользователь загрузил 20-и минутный видео файл в качестве 1024p. Его нужно предобразовать в видео меньшего разрешения: 720p, 480p и 360p. Какой алгоритм будет в монолитном приложении?


Для определенности предположим, что вы делаете клон YouTube, но с посещаемостью на порядки меньше. Вам интересно как бы это выглядело на монолите?

Как бы сделал я:

0) Балансировщик на входе — fabio/Traefik/nginx.

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

Это что для монолита, что для микросервисов нужно.

1) БД для метаданных видеофайлов, профилей пользователей, сессий, комментариев.

Возможно, одна СУБД, если проект невысокой нагрузки.

Или несколько СУБД различной специализации, например, более часто запрашиваемые сущности такие как сессии — в Tarantol/Redis, комментарии в Mongo (тут пригодится ее умение масштабироваться сравнительно легко, ну а то, что платой за это является у Монги консистентность не строгая, а типа «когда-нибудь потом» — это не важно для комментариев).

Необходимость реляционной СУБД для такой простой задачи под вопросом. Ну, разве что, для строгой консистентности профилей пользователей, если, например, у вас платный доступ. Допустим, возьмем PostgreSQL.

Все экземпляры всех видов СУБД — разумеется реплицируются.
Выделение Tarantool/Mongo/PostgreSQL позволит сделать удобную репликацию master-master для Tarantool/Mongo (Тарантул точно умеет, Монго, надеюсь, не помню точно). Это снимет нагрузку с PostgreSQL, так как он заметно хуже работает на большом количестве экземпляров (а тем более по сети) и позволит обойтись для PostgreSQL более мягким master-slave.

Что для микросервисов, что для монолита — эти СУБД будут.

2) Бэкенд. Вполне себе монолит. Большой и единый.

3) Фронтенд.

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

4) Модуль конвертации. Маленькая узкоспециализированная утилита. Даже какой нибудь ffmpeg годится.

С небольшой специально написанной обвязкой, например, подписанной на очередь и запускающий ffmpeg.

Или вообще без обвязки специальной — тот же Nomad из Hashicorp вполне годится, имхо. Его же можно для deploy новых версий бекенда использовать. Его же можно использовать для запуска ffmpeg

Что для монолита, что для микросервисов — все тот же ffmpeg и все та же обвязка.

5) Сервер очередей. Для более гибкого управления множеством инстансов.

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

Это нужно и для монолита и для микросервисной архитектуры.

6) cloud storage работающее по протоколу S3 или OpenStack Swift

Это нужно и для монолита и для микросервисной архитектуры.

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

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

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

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

Опционально добавляем:

8) Если бюджет позволяет более серьезно относится к диагностике — централизация сбора логов и метрик. Логи нужны всем. Метрики микросервисам важнее.

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

Для многопоточных бэкендов Erlang или Go (golang) нет необходимости выделять этот компонент сразу. Для NodeJS с ее однопоточностью — принципиально выделить сразу, даже при небольшой нагрузке на upload новых файлов.

Итого имеем балансировщик, СУБД и MQ-сервер и cloud storage и кэш — обязательные как для монолитной так и для микросервисной архитектуры.

Варианты с монолитом:
1) Монолит бэкенда + конвертер.
2) Монолит бэкенда + конвертер + модуль upload

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

Конечно модуля upload и конвертер — легковесны и обладают частью признаков микросервисности, но все решение — однако все решение в целом все же не является микросервисной архитектурой, имхо. Максимум — просто сервисной. Без «микро-».

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

Впрочем, учитывая особо выделяющийся по объемности функционал компонента бэкенда-монолита — все же, полагаю, что это монолитная архитектура. С использованием отдельных помощников бэкенду — MQ, cache, конвертер.

Я один не считаю такое приложение монолитом? Для меня это SOA.

Тут товарищ в соседней ветке предлагает делать правильный монолит — 1 приложение и много потоков.
Фанатики микросервисов называют такое приложение монолитом, потому что монолитом является все то, что не построено на микросервисах.
Тут товарищ в соседней ветке предлагает делать правильный монолит — 1 приложение и много потоков.


Не обязательно.

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

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

И причина, по которой вы запускаете дополнительные инстансы — не важна.

Неважно что это будет необходимость утилизировать все ядра процессора, если выбранный инструмент этого не умеет (если использует только 1 ядро, а на сервере их 16 — в этом случае вы запустите 16 инстансов на одном сервере). Или неважно, что это будет необходимость обеспечить обработку достаточного числа потоков (если один инстанс обрабатывает 1 000, а вам нужно 100 000, то вы просто запустите 100 инстансов)

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

Это важно и для монолита и для микросервисной архитектуры.

Давайте рассмотрим чистый монолит (сам конвертирующий видео файлы, сам же обрабатывающий запросы от пользователей) на примере ситуации, описанной ppl2scripts в habr.com/post/427215/#comment_19272331
Потому что завтра нужно будет отрендерить миллион превьюшек. Хорошо 50 тысяч. Тысячу.


Ситуация с монолитом не отличается от ситуации с микросервисами.

Определимся с вашей политикой использования вычислительных ресурсов. Что для монолита, что для микросервисов это будет одно и то же:
  1. Или по мере освобождения вычислительных ресурсов, выделенных только под длительные операции. Таким образом, под трудоемкие операции выполняются только на определенном выделенном пуле вычислительных ресурсов.
  2. Или по мере освобождения вычислительных ресурсов от других операций. В этом случае, фактически размер доступного пула динамически меняется в зависимости от нагруженности по прочим операциям
  3. Или автомасштабированием — добавлением вычислительных мощностей, выполнением операции, освобождением вычислительных мощностей.
  4. Или комбинацией этим методов.


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

  1. В схеме бэкендом+конвертер мы просто запустим конвертер 50 000 раз.
  2. Для бэкендов ничего не изменится.
  3. В схеме с единым бэкендом — мы начинаем конвертацию, тем самым количество бэкендов, доступных для обычных запросов пользователей, сокращается. При обработке очередного запроса от пользователя обнаруживается, что обрабатывать запрос некому, так как свободных бэкендов нет. Просто запустим новый бэкенд. Очевидно, что при сохранении нагрузки придется запустить под быстрые запросы 50 000 дополнительных бэкендов, взамен тех, что длительное время будут заняты конвертацией. Если ваши бэкенды долго инициализируются это имеет смысл сделать заранее, одновременно с запуском конвертации. Или предусмотреть пул «горячих» свободных бэкендов
  4. Рассмотрим ситуацию, когда конвертировать вообще ничего не надо. Но обычные быстрые запросы не успеваем обрабатывать. Просто запустим новый бэкенд. Ничем не отличается от предыдущего пункта в плане автомасштабирования. Только то было «автомасштабирование по причине того, что бэкенды заняты конвертацией». А это «автомасштабирование, так как бэкенды не успевают обработать обычные быстрые запросы». Но не отличается ровно ничем — ответ на недостаток ресурсов для обработки это запуск нового бэкенда


Но почему это произошло?

Если у меня год подряд было 1 000 в день, то вероятность того, что завтра будет 50 000 в день — крайне незначительна. А вероятность того, что будет миллион = 0.

Если такое случится, видимо, теперь мы мега-популярны и мега-посещаемы?

Так что следующий этап:

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

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

Платить за это заранее готов далеко не каждый.
А вдруг не будет не то что миллиона, а и 50 000 не будет никогда?
Сделать сразу «как у Фейсбука и Гугл» — это ж разница совсем не в 20% по стоимости работ. И по срокам тоже дольше.

А скорее всего для начала сгодится компромиссный вариант, описанный тут habr.com/post/427215/#comment_19276749

Монолиты гораздо эффективнее по производительности, чем микросервисы на огромном числе задач. При меньшей стоимости и большей скорости разработки.

Вот пример примитивнейшей ситуации:
habr.com/post/282299
«Кэш внутри приложения» vs «Кэш рядом, в соседнем отдельном процессе».
А ведь в микросервисах, все еще хуже. Там и сетевые задержки. И переходов между процессами/модулями/сервисами куда как больше. И дополнительных сериализаций/десериализаций полным-полно. И пр.

Надо смотреть по конкретной задаче.

Ну вот пример очень даже посещаемого проекта:
habr.com/company/oleg-bunin/blog/418235
Как было раньше (со старта Авито до 2015 – 2016 годов): мы жили в условиях монолита, с монолитными базами и монолитными приложениями. В определенный момент эти условия стали мешать нам расти. С одной стороны, мы уперлись в производительность сервера с главной базой, но это не основная причина, так как вопрос производительности можно решить, например с помощью шардирования.


Как они пишут производительность можно было решить и с монолитом. А ведь это один из самых посещаемых сайтов в РФ, входит в первую десятку rg.ru/2017/09/28/nazvany-samye-populiarnye-sajty-v-rossii.html

Если вы не Гугль, то, вполне возможно, гораздо оптимальнее для вас будет не микросервисы, а всего лишь 2-3-4 крупных сервиса. Главное, чтобы они были способны работать на множестве запущенных инстансов для горизонтального масштабирования.

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

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

Надо смотреть по конкретной задаче.
Я один не считаю такое приложение монолитом? Для меня это SOA

Зачем замыкаться в формальных определениях. Ведь чистых монолитов и не бывает.

Кроме самого монолитного приложения — всегда есть СУБД, часто есть кэши, и в отказоустойчивых системах с несколькими инстансами как правило есть MQ.

Приведенный пример точно не микросервисы, а скорее ближе именно к монолиту.
Откуда по вашему взялись «очевидные места»?

Из опыта
Да люди как люди. Кто-то начитался умных книжек и статей, кто-то просто хочет быть в тренде, кому-то банально скучно и хочется попробовать что-то новое. Что еще печальнее, часто им совершенно пофиг на судьбу проекта, зато потом в резюме можно написать «знаю стек netflix».
Также можно сказать про ООП, ФП и другие подходы. А может просто кто-то не хочет говнокодить?

Не хотеть говнокодить и не говнокодить — две большие разницы.

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

Также можно сказать про ООП, ФП и другие подходы

Конечно можно
А может просто кто-то не хочет говнокодить?

Как говнокод связан с микросервисами? Микросервисы — это про архитектуру. А как она реализована — это уже другой вопрос. Говнокод с равной вероятностью может быть как в монолите, так и в микросервисах.
Если впихивать невпихуемое в 1 монолитное приложение, то код приложения превратится в говнокод. Архитектура помогает этого избежать.
А если бить на куски то, что должно работать вместе, то помимо говнокода, будет еще и ад с поддержкой этого чуда. Это я к тому, что как и вы, могу приводить крайние примеры. А нужно просто включать голову.

ООП и ФП это попытки справится со сложностью декомпозицией на меньшие куски.
Если микросервисы это единственный метод для декомпозиции, то получится как на


Molonithic vs Microservices

image

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

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

Мне кажется, это просто мода… Типа мы такие современные, сейчас внедрим микросервисы с аджайлом и всё сразу взлетит…

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

Если же коммуникация между «сервисами» должна быть исключительно быстрой, лучше сделать монолит… У меня был опыт, когда в хорошем продукте всё равно пришлось несколько сервисов слить в монолит, потому как так работало лучше…
смешно такое читать, достаточно посмотреть какой код пишут программисты без должного присмотра и сразу станет ясно почему микросервисы пихают вовсюда, с микросервисами не получаться макароны, вернее их создать сложнее, а в монолите легко, даже думать не надо, почему-то все забывают что главная проблема это именно программисты, мы не любим работать много и хорошо, а если ещё и менеджеры такие которым уяк-уяк и в продакшен то код в какашку быстро превращается, а микросервисы это физическое разделение кода и откуда попало не вызовешь любой кусок кода, многие ещё на ФП переходят там в некоторых языках вообще жёсткие ограничения, что сделать плохо сложнее чем сделать хорошо, но нужно понимать как оно должно быть иначе вообще ничего не напишется
Отличный пример монолитного предложения, которое можно рефакторить в микропредложения
да! если написано хорошо то делается это всё легко и быстро
UFO just landed and posted this here
Никогда не говори никогда… ну и в целом не надо слишком сильно обобщать… Если разработчик привык фигачить микросервисы, то может быть вполне нормальной идеей писать сразу на микросервисах. Просто некоторые вещи сразу удобно выделять в микросервисы (например — КЛАДР классификатор, который по отдельности никому нафиг не нужен ни в одном проекте, но в целом компании нужно, чтобы все адреса задавались в едином формате), сервис отправки сообщений (sms, email, telegram) тоже никогда не влазит ни в один из сервисов компании, но оповещения клиентам может слать биллинг, система мониторинга сети или отдел маркетинга и все они хотят слать сообщения без заморочек и по тому каналу, который пользователь указал как приоритетный для связи… да тонны их. Ну а если непонятно «куда приткнуть эту фичу» или «она временная» или вообще «мы тут быстро на коленке накидаем, потом решим что с ним делать», то пусть будет один «микро» сервис, в котором, например, бизнес-логика и всё вот это вот непонятное… Как назвать получившуюся архитектуру с 1-2 кучами ака монолитами и обвязкой из нескольких микросервисов я не знаю, но обычно получается что-то подобное.
Это вы описываете не микросервисную архитектуру, а классическую сервисно-ориентированную (SOA). В которой критерием выделения сервиса является возможность его переиспользования или особые требования к автономности либо масштасштабируемости.

Микросервисная архитектура строится по-другому, там монолиту просто нет места.
Как уже было упомянуто в статье, переход на микросервисную архитектуру влечет за собой накладные расходы на создание и поддержание инфраструктуры мониторинга. Причем, знаю по собственному опыту, что это намного сложнее, чем мониторинг в монолите. Поэтому, у вас так не получится) Чтобы сначала был монолит, а потом вдруг решили, что давайте какой-то функционал вынесем в отдельный микросервис. Как результат, вам придется поднимать ещё и все сопутствующие инструменты. А это по расходам может встать даже дороже этого временного сервиса и уж наверняка дороже, чем запилить этот функционал прямо в монолите. Другой вопрос конечно, если у вас уже микросервисная архитектура и вынести какой-то мелкий функционал в отдельный сервис почти ничего не стоит.
Не нужна никакая «система мониторинга» на той стадии, о которой идет речь в статье — там первые шаги бэби-приложения. А когда это будет уже серьезное приложение, где устойчивость будет ставиться в более приоритетное положение — там уже все эти доводы против микросервисов отпадут и вообще это будет другая история.
По факту сейчас многие так называемые монолиты являются представителями сервисных архитектур. Очень часто в этих монолитах есть выделенные сервисы типа СУБД или веб-сервера для статики и маршрутизации. Чем какой-то, nginx решающий одну задачу раздачи статики для веб клиентов не просто сервис, а микросервис?

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

У Сысоева спросите требует он написания кода или нет.
В мире nodejs есть одна реальная техническая предпосылка к тому, чтобы пораньше распилить приложение как минимум на две части: однопоточность. Если смешать в одном процессе (небольшом кластере) разнородную по потреблению процессора нагрузку, то можно добавить совершенно лишних задержек простым для вычисления задачам за счет более сложных, который будут блокировать event loop. Очевидный пример вынос серверного рендеринга в отдельный воркер/процесс/микросервис.

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

Это не микросервисы. Но это же уже и не монолит, верно? В статье рассматриваются 2 крайности — монолит или микросервисы. Но есть же еще среднее между ними.
По моему мнению, это все еще монолит. Это конечно же, спор о терминах, но давайте просто определимся с терминами.

Вот у меня есть монолитное API-приложение с in-memory database (это просто пример, ок :-)).

Я заменяю in-memory database на чужую внешнюю бд, которая имеет свой протокол обмена данных и может хоститься на отдельном сервере. Приложение перестало быть монолитом?
Я добавляю к приложению чужой внешний кэш, который имеет свой протокол обмена данных и может хоститься на отдельном сервере. Приложение перестало быть монолитом?
Я добавляю к приложению чужой фулл-текст (эластик, к примеру), который имеет свой протокол обмена данных и может хоститься на отдельном сервере. Приложение перестало быть монолитом?
Я добавляю к приложению балансировку нагрузки на одинаковые инстансы, которые не имеют возможности обмениваться данными, но могут хоститься на отдельном сервере. Приложение перестало быть монолитом?
Я добавляю к приложению сервис авторизации, который выношу на отдельный сервер и который может обмениваться с основным приложением. Приложение перестало быть монолитом?
Файлы вы храните в S3. Видео перекодируете в AWS ElasticTranscoder. RTMP транслируете через Red5. 3D модели рендерите SolidWorks. Email-ы рассылаете через SES. Картинки конвертируете ещё чем-то. И т.д.
Да, на мой взгляд, это уже будет сложно назвать монолитным приложением.

А что, если у меня всего этого нет, потому что не нужно? Ладно, не суть


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


Я так не играю. Извините, но имхо, то, что вы описываете далеко от общепринятого понимания микро/нано-сервисов.

Ответы на ваши вопросы, нет, не делает.
Конечно же, использование сторонней БД не делает приложение не монолитным. Но если значительная часть логики приложения отдана на откуп сторонним сервисам, то, я считаю, его уже нельзя назвать монолитным.
Как бы вам сказать ответы: «Да, монолит» и «Нет, не монолит» одновременно смотря с какой стороны смотреть.

Ответ «Да, монолит» со стороны пользователей вашего API-приложения — для них ваше API-приложение условно «чёрный ящик» и внешне он самостоятелен и независим.

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

Посмотрите на следующую цепочку: Монолит > SOA и Микросервисы > Библиотеки и Модули > Классы и функции.

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

Рассмотрим ваше API-приложение:

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

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

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

Так или иначе вы уже обращаетесь к другим сервисам даже если они физически на одной машине. И вот теперь ваше приложение относится к SOA (не обязательно микросервисная архитектура, но сервисная точно), и не является монолитом т.к. уже не выполняет полностью от и до весь заявленный функционал: хранение/поиск/авторизация уже выполняются внешними сервисами/приложениями. А ваше приложение представляется фасадом с набором собственной связывающей бизнес логики.

К слову вариант с вынесением авторизации в отдельный сервис из монолита будет происходить быстрее и проще, если «монолит» будет не совсем монолитом, а скорее модульным приложением. Всё-таки довольно легко независимый и унифицированный модуль вынести в отдельный сервис. Чем пытаться распутать жёстко связанный спегетти код особенно, если приложение уже стало огромным.

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

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

Просто всё зависит от того как близко рассматривать всё решение. Невооруженным глазом одно, под микроскопом другое, под микроскопом рассматривая примитивную единицу третье.
Отличная статья. Хотя основная тема все таки про микросервисы, я для себя взял извлек и другой смысл. Сам очень много раздумываю, как сразу писать хороший код. Обычно над проектами работаю сам, и в какой то момент замечаю, что код находится не в лучшем состоянии. Спешки на проектах никогда нет, у меня достаточно времени, чтобы думать о том что писать. То есть, ожидалось, что код не будет похож на спагетти, но он почему-то похож. А похож, потому-что, как здесь и говорится, нельзя (трудно) предвидить развитие проекта. Вот начинаешь писать класс, создал несколько методов. Потом в один метод надо добавить еще один аргумент, потом еще одно условие, потом создать дочерний метод. В результате, видиш — это все тянет на отдельный класс. Но как это предвидеть изначально. А есть методы, которые вообще не меняются. Может, это с опытом таких вещей становится меньше, а может так и должно быть.

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

Замечательная статья.
Для меня удивительно, что в статье не упомянут важный момент: микросервисы вносят дополнительную сетевую задержку. Для мелких проектов этот недостаток реально трудно перекрыть.
Еще хуже, что при неправильной декомпозиции (а на старте она будет скорее неправильной, чем правильной) приложение будет напоминать пинг-понг: множественные пересылки данных между микросервисами в рамках исполнения одного api-запроса.

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

Вы верно вспоминаете о том, что бд/кэш/elastic тоже вводят дополнительные сетевые заддержки.


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


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


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

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

Я уверен что любое приложение можно на начальном этапе разделить как минимум на 2 части:
— с состоянием
— без состояния

На часть без состояния обычно приходится основная нагрузка. И эту же часть легко масштабировать. Для этого, например, в AWS/Azure существуют готовые решения: auto scaling groups / scale sets. Это позволяет держать 1 меленький сервер, а в пиковые нагрузки запускать дополнительные.
Простите, но я действительно не понимаю, почему вы так думаете.

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

Если вы испытываете проблемы с поступающей нагрузкой, то у вас есть возможность поднять кучу инстансов и сделать балансировщик нагрузки. Многие приличные бд имеют возможность создавать read replica. Вы также можете вынести отдельные тяжелые операции в фон на отдельный сервер с помощью очередей, если это возможно (если что, это вовсе не микросервисы).

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

Но это же уже будет не монолит?

если что, это вовсе не микросервисы

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

еще раз, я не говорил про микросервисы, я имел в виду минисервисы.
Разница только в объеме кода или есть еще какая-то разница?
Нет, это не правда. Размещение по серверам и монолитность никак не связаны. Можно сделать несколько копий монолита (воркеров) на слабых серверах за балансировщиком, а можно все микросервисы посадить рядом на один сервер.
Сделать несколько копий монолита возможно только для очень простого монолита. Я даже таких приложений и не встречал.
Как-то глупо делать монолит(если он один) который будет складывать входящие запросы в базу, потом их оттуда забирает в правельном порядке. Но если их сатановится два, то это необходимо.
Что в таком случаи делать?
Либо делать оверхед одиночному монолиту, чтобы не переписывать когда их будет два? Или всё же переписывать когда надо будет?

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

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

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

И по сути БД или MQ это микросервис.
Оверхед тут в том, что приходится использовать лишнее хранилище, хотя если это было одно приложение то можно было бы эти данные хранить и сортировать в памяти, без использования очередей.
С очередью в памяти очень трудно добиться либо гарантий persistance, либо гарантий exactly-once. Все еще оверхед?

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

Вообще мне этот комментарий доставляет. Такое впечатление, будто вы думаете, что микросервис — это модуль, общающийся по сети.
Я имел в виду что я не участвовал в разработке веб-приложения, которое можно было бы реализовать монолитным (UPDATE: правильнее сказать, целесообразно, потому что если сильно захотеть, можно в посмос улетель). Мне приходит в голову только онлайн-магазин, сайт на wordpress и что-то в этом роде. Более-менее сложное веб-приложение требует разделения на несколько независимых приложений.
Еще меня удивляет реакция людей, которые минусуют. Такое ощущение, что здесь собрались люди, которые сложнее сайта на WordPress ничего не делали и такие комментарии:
Сделать несколько копий монолита возможно только для очень простого монолита. Я даже таких приложений и не встречал.

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

Но вы мне скажите один момент. Микросервисы в общем-то недавняя тема (если смотреть по взрыву популярности). Как до этого момента люди делали сложные приложения?
Делали немонолитные приложения — сервисы. Просто они были не микро.

И продолжают так делать. Может вы скажете что Facebook, Google, VK — это монолитные приложения?

Пожалуйста, забудьте учебник демагогии. Это реально раздражает.


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


Хорошо, мы уже пришли к сервисам. Вы уверены, что все сложные приложения делались на основе сервисов?

Я уверен что они не монолитны.

Хорошо, давайте зайдем с другой стороны. Как разрабатываются сложные приложения вне веба? Тоже сервисы/микросервисы?

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

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

Это некорректное сравнение. Скорее каждый из ваших примеров можно сравнить с узкоспециализированным сервисом. Рассатривать ядро линукса без самого линукса странно. А линукс — это уже не монолитное приложение.

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


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

Мне кажется тут просто разные абстракции что такое монолит. Можно запустить одно большое приложение в докере или даже кубернетисе и сделать 1000 его реплик и это все равно будет считаться монолитом, так как изначально сервис один.

И от сложности кода тут ничего не зависит. Разве что у вас такие сложные запросы к БД когда две копии одного приложения будут драться за блокировку таблиц например.
>Потому что монолитное приложение можно разместить только на 1 сервере.

Почему? Если с размахом подойти к делу, то можно сколько угодно серверов занять. На первых трех — кластер бд, мастер и два слейва на чтение. Еще на шестерых запустить по одному экземпляру монолита. Ну и последний отдать под nginx — балансировать нагрузку. Вот и десяток серверов заняли. И это еще не упомянули ни кеширование (+ 1 сервер под редис?), ни разбивку таблиц на части…

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

А если этого нельзя, то приложение сделано рукожопами?
Строго говоря, у разработчиков монолита могли быть весомые причины не добавлять возможность запуска на произвольном количестве серверов. Однако в таком случае и о микросервисах говорить бессмысленно.
Так что в рамках выбора монолит/микросервисы мы имеем, что такое монолитное приложение спроектировано рукожопами.
Черт бы побрал этот планшет. Писал большой хороший коммент с примерами, но браузер скрашился.

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

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

Единственное, с чем могут быть реальные сложности — пользовательские файлы. Хранить их в бд (постгресе или монге) — нерационально. S3 может быть слишком дорого. И вот лежат они на диске, рядом с монолитом, и никак второй сервер сюда не присобачишь. Но даже тут есть варианты, начиная от запуска облачной файловой системы — от клона S3 до какого-нибудь seaweedfs, написанного на go.
Пример, приложение по таймеру делает какие-то действия с базой, например очищает старые записи. Я запустил 10 инстансов и получил 10 очисток, вместо 1.

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

Но не проще ли сделать отдельное приложение для этого?

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

Я где-то сказал про микросервисы? Я просто привожу пример где проще разделить 1 приложение на несколько.
Ну мы находимся в топике про микросервисы и обсуждаем недостатки монолита по сравнению с микросервисами.
Хочу отметить, что при разделении приложения таким образом мы вовсе не обязаны разделять кодовую базу. Особенно если хотим шарить общую бизнес-логику. В таком случае код куда ближе к монолитам.
Вот именно «недостатки монолита по сравнению с микросервисами», а получается наоборт, что у него монолита одни плюсы. Но это неправда
Основное преимущество микросервисов, как мне кажется, распределенние отвественности и упрощение менеджмента при разработке действительно больших приложений.

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

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

Зря ведёте дискуссию.
Ваш оппонент плавает в темах, что монолита, что микросервисов.


Причём ужасно плавает.

Мне вот интересно, такие умные комментаторы дейстиветельно делали что-то серьёзное или только в теории всё знают?

Понятное дело, что блог, онлайн магазин, форум, нет смысла делить на части. Если сложнее этого вы ничего не делали, то спор действительно бесполезен.
Встряну, пожалуй. Вы показываете серьезный недостаток в теории и при этом аппелируете к практике, чудно. Проблема в том, что знание теории видно из беседы, а практика скорее всего лежит под NDA.

К примеру, я учавствовал в разработке серьезных проектов. Монолит нисколько не мешал. Но откуда вам знать, что я не соврал?

Зы: вы же не думаете, что люди защищающие монолит защищают отсутствие модульности?
Я думаю что они защищают чувство собственного достоинства.

Да, я не эксперт в микросервисах, я никогда с ними не работал и по-этому стараюсь их не упомянать. Но что такое монолит я представляю.
Вот это лол. Вы неявно обвиняете чувака в недостатке практики. Но при этом:
1) вы не представляете как масштабировать монолит;
2) сами не имеете практики участия в проектах с архитектурой похожей на микросервисную.

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

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

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

И да, это был обычный монолит на десятках инстансов со временем эволюционировавший в SOA.

P.S. Даже онлайн-магазин может состоять более чем из одной частей — склад, бухгалтерия, логистика, crm…
Да как бы — ну и будет у вас 10 очисток, и что? Одна из них реально почистит бд, остальные девять просто отработают вхолостую (и довольно быстро, к слову — старых записей-то в бд не останется уже после первой итерации). Да, выглядит не очень красиво, но для большинства ситуаций — рабочий вариант, если уж прям совсем не хочется заморачиваться.

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

>Но не проще ли сделать отдельное приложение для этого?

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

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

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

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

Никакой разницы в этом смысле между микросервисом и монолитом.
А почему бы для задачи очистки старых записей не сделать job-у на базе?
Всегда есть больше 1го решения, и у всех свои плюсы/минусы
Я запустил 10 инстансов и получил 10 очисток, вместо 1.

Потому что ваша система не умеет работать в нескольких инстансах.
Это не имеет отношения ни к микросервисам ни к монолитам.

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

Но не проще ли сделать отдельное приложение для этого?


Ну я бы решил сие с помощью MQ-сервера.
Это, имхо, довольно универсальный ответ на то, чтобы несколько инсансов приложения корректно совместно работали.
Еще 1 пример, для nodejs. Чат на WebSocket'ах. Запустите его на 2 серверах :-)
У того же редиса есть pub/sub, в нем и хранить состояние. Тогда экземпляров nodejs можно хоть десяток наплодить.
В любом туториале по написанию чатов на вебсокетах объясняется как сделать несколько воркеров, общающихся друг с другом через мастер-процесс. Добавить еще один уровень в эту иерархию. тривиально.
В этом случае мастер и воркеры разные приложения. А спор в том, возможно ли это сделать 1 монолитным приложеним копии которго запущена на 2 серверах
Так чем же принципиально отличается взаимодействие двух приложений от взаимодействия двух серверов? В обоих случаях используется обмен сообщениями.
Ничем особо не отличается от синхронизации процессов после fork()
Ещё пример. Вам нужно сконвертировать видео загруженное пользователем. Вы будете его налету конвертировать монолитным приложением?

Нормальный подход — сделать для этого отдельный сервис.

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

Update: да, тоже можно через общую фс. Пойду спать)

А в чем ключевые различия этой задачи при монолите и при микросервисной архитектуре?

Простите, я ничерта не понял из вашей картинки

Сервисов можно наплодить хоть сколько, при этом иметь 1 сервер для закачки файлов.
А что мешает настроить балансировщик так, чтобы он определенные запросы отправлял строго на один конкретный инстанс?
Во многом получится тоже самое, но без модульности.

Но ваши примеры становятся все лучше и лучше
А что мешает на второй картинке вперед еще один балансер поставить?
Он там и подразумевается, только вот если балансировщик будет случайно выбирать сервер, то закачка будет начинаться каждый раз с 0 с вероятностью 1 / кол-во_серверов.
брр… как сложно. Тут проблема изначально с архитектурой наверное. каждый инстанс сервиса будет качать себе некий файл, несмотря на то, что его сосед уже это делал ранее?

Все инстансы (реплики) могут ведь иметь общее файловое хранилище и работать с одними и теми же файлами.
На картинках я привел пример использования расширения для nginx (resumable_upload) которое работает с файловой системой. Т.е. в этом случае для него нужен сетевой диск. Сетевой диск — это отдельный геморрой. Сколько раз приходилось использовать, столькоже раз потом отказывться.
Есть такая штука как sticky session. И закачка в рамках одной сессии не будет иметь проблем
монолитное приложение можно разместить только на 1 сервере

— не правда, кластеризация и балансировка запросов возможны и на монолите
Вы про это:
Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms


Между Калифорнией и Нидерландами 150ms. А точто такое же внутри одного датацентра?
Это если сервисы общаются peer-to-peer. Но люди хотят отказоустойчивости, горизонтальной масштабируемости и т.д. И тут приходят они, брокеры сообщений, и добавляют задержки.
Выше, товарищь приводил аргумент с сетевыми задержками как один из ключевых недостатков микросервисов перед монолитом. Другой товарищь приводит в подтвержение этого аргумента сетевую задержку между Калифорнией и Нидерландами. Ну очевидно что она будет большая. А какова эта задержка будет между серверами внутри одного датацентра? Пренебрежимо мала
А я говорю, что в современном мире мерить задержку, как передачу пакетов, неправильно.
Я видел приложение, которое гоняло между микросервисами файлы объемом 1-100 мегабайт в рамках одного API-запроса десяток раз. Даже на локальной машине это жутко тупило. Но это эпик случай.

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

Это вовсе не пренебрежимо малая задержка.
Round trip within same datacenter = 0.5ms
А если учитывать tcp handshake, кучу промежуточных роутеров, фаерволов, несколько уровней балансировщиков, можно получить скорость, которую совсем не ожидаешь, особенно если микросервис однопоточный, не имеет очередь. Тут же всплывают вещи о которых надо думать, потери пакетов в сети, лимиты на процесс (которых можно не достичь при локальных сервисах) и прочее-прочее. И в итоге может оказаться, что сравнивая производительность проекта построенного на микросервисной архетикруте и монолита, разница получается не в пользу микросервисов, при большей суммарной производительности серверов где работают микросервисы.
tcp handshake: не обязательно создавать TCP подлючение на каждый запрос.
кучу промежуточных роутеров, фаерволов: например в AWS/Azure есть опция (Accelerated Networking) которая отрубает фаервол.
А я и не спорю, если вы заметили
Я привел сравнительную таблицу только для одной цели, оценить задержки разных подсистем. Разбивая монолит на микросервисы вы добавляете значительную сетевую работу, которая медленнее всего, даже если это 10G. Приведение форматов обмена между микросервисами тоже необходим, а протокол общения добавляет кол-во возможных исключений. Что делать при отсутствии сети, потере пакетов, недоступности какого-либо сервиса, ошибок ответа, перегрузке вм-ки где работает сервис. И это только сетевая часть. А если немного поофтопить, и коснуться деплоя, то возникают вопросы версионности, внедрение фич касающийся сразу нескольких сервисов, обратной совместимости (при rollback и смене версий), сложности CI/CD, балансировке, сервис-дискавери. Повторюсь, я не спорю, просто разбивая на микросевисы, вы выносите изнутри наружу всю сложность связности. Когда то это оправданно, но чаще нет.
В статьях про микросервисы, забывают очень много важных моментов.

Например что если данные лежат в двух отдельных БД — невозможно гарантировать их консистентность. Ну типа такую операцию нельзя выполнить транзакционно:
personsSvc.fire(id = 123);
workplaceSvc.free(id = 123);

Или что не получится по-человечески сделать распределенный join на данных из двух сервисов, типа
select *
from svc1.persons p
join svc2.tasks t
where p.name like 'ivan%' and t.name like 'do %'

Такого плана мелочи ведь меркнут перед всеми неоспоримыми плюсами микросервисов.
На самом деле не так, просто либо Вы имеет большой опыт работы с монолитом, либо не внимательно читаете те самые статьи… Как было сказанно в этой — выбор в пользу микросервисной архитектуры зависит от самого проекта. Есть ещё одна важная вещь — разделение на микросервисы, и то что описали Вы — как раз пример неправильного деления микросервисов.
Ну как не так-то?

Распределенные транзакции невозможны даже теоретически по CAP, а условный 2-phase commit — дает какую-никакую соломку, но средней руки разработчик никогда его по-человечески не сделает, а средней руки архитектор и аналитик — никогда этого «маленького нюанса» не учтут. В результате постоянная история когда что-то там «не прососалось», и руками что-то там в БД лазают и правят.

Распределённый join теоретически возможен — таки никакой разницы с БД вроде как нет — алгоритм будет такой же: hash join или inner loop там. Но когда это делается внутри БД — с локальным диском, кешем, и умными опытными разработчиками БД сделанное — это одно. А когда поверх REST-сервисов джунами — это совсем уже другое. Там же приходится городить кеши или сервисы-аггрегаторы какие — и хана перформансу и консистентности.

Ну и при этом всём, я регулярно вижу всяких архитекторов, которые реально топят за «давайте выделим Person Service и будем туда ходить из всех аппов в стиле GET svc/people/123». А иногда этим идиотам даже дают реально делать так систему, потому что модно. Весь этот проект, есстесственно, жостко факапится. И по жопе за это этим идиотам даже не выдать. Да, можно уволить их с позором. Но они же потом пойдут и устроятся «с опытом построения микросервисных архитектур» в другое место. Потому что модно. И даже может и не поймут что проект факапнулся от их глупости.

Поэтому я аггресивно против популяризации микросервисов. Еще раз — не против самого паттерна, а против его пополяризации. Людей, которые могут обоснованно принять решение юзать микросервисы — очень мало, там должен быть опыт архитекторства и разработки лет в 10 хотя бы. Эти люди сами как-нибудь решат. А для остальных всех — гораздо лучше будет если по-умолчанию в голове установка «микросервисы — плохое решение в 99% случаев».
Распределенные транзакции невозможны даже теоретически по CAP,

Нет, CAP-теорема вообще о другом. Она сообщает в общем-то самоочевидную мысль, что в условиях неработоспособности сети невозможно одновременно поддерживать целостность данных и доступность сервиса. Распределённые транзакции никуда не делись, и по-прежнему возможны, в том числе и теоретически.
Ну хорошо, если не по CAP так по Two General's Problem
Обычно CAP и Two Generals из одной области, находятся одновременно человеком, когда проблема до него доходит, и весьма возможно что одна из них выводиться из второй.
Вообще jacobz написал хорошо.

Транзакционное поведение в микросервисах делается через общую шину и ключи идемпотентности. Если облом на одном из сервисов, другие участники получают сигнал "сделай обратную операцию". Более того, действия могут быть очень разветвленными, на много экранов, если бы это было внутри хранимой процедуры. Ну а джойны с like%, это само по себе узкое место производительности и маркер костыля. А ведь можно вместо джойна кинуть запрос на десяток сервисов(например поисковый) и асинхронно склеить. Яндекс вон склеивает целую пирамиду из результатов метапоисков.

А если облом в общей шине?
То же самое, что и «если ядерный взрыв случится». Шина попадет в рай, а микросервисы — просто сдохнут: ))
И в чем тогда разница? Просто переложили проблему с больной головы на здоровую и сделали вид что она решена, тогда как на самом деле она осталась нерешенной.
Это была шутка юмора. Хотя в ней и не только юмор — вы спрашиваете про проблемы в шине — но это равнозначно, что спросить: А если сервер откажет? И что ты будешь делать со своим монолитом, Илон Маск? Это же ерунда — эти отказы не следствие выбора архитектурного решения. Из-за чего шина может отказать? Из-за проблем кода самой шины? — Ну так это плохая шина, и в монолите будет проблема, если его «внутренняя шина» кривая. Или проблема связана со связью? — Ну так и монолит без сети скорее всего бесполезен как вещь в себе в современных-то реалиях, да и микросервисы городить для не сетевого приложения смысл какой?

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

Что такое транзакция, простыми словами? Это объединение нескольких запросов в базу — либо выполнятся все, либо не одна. Если во время исполнения транзации в приложении возникает ошибка — транзакция откатывается, изменений в базе нет.

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

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

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

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


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


В простонародье есть "золотое правило микросервиса" — любой микросервис можно выкинуть и переписать с нуля за 2 недели не ухудшив.

Опять: проблема синхронизации данных — это не проблема микросервисов как таковых, а проблема любых распределенных систем, каковыми могут быть и монолиты — как несколько инстансов на разных узлах.
Да, я так и писал — «в распределенном приложении».

>каковыми могут быть и монолиты — как несколько инстансов на разных узлах

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

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

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

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

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

И про like% я и не говорил. Я говорил что обычный джоин нельзя сделать на JSON/REST-сервисах без слёз. Ну типа есть такие API:
users.svc/get?age=23&city_id=2,3,1
locations.svc/get?i=1,2,3&country='RU'
Как вытащить всех пользователей с age=23 из городов с country='RU'? Вынуть все города России, и передать их ID в users? Или вынуть всех пользователей с age=23, вынуть их city_id и передать в locations?
Как вытащить всех пользователей с age=23 из городов с country='RU'?

Никак. Это пример архитектуры курильщика. Еще и на мобиле часто это все пытаются через REST дергать, чтобы собрать интерфейс, по 20 запросов на экран. Сквозные данные (единый набор id, общие структуры) не должны летать между сервисами.


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


… где-то видел схему с «делай обратную операцию» работающую реально?

Гарантий 100% никто дать не может и бывают необратимые действия. Это надо индивидуально рассматривать. В редакторах undo реально работает и сложность там не запредельная.


Если сделать микросервисы из одной функции примитивными, вся транзакционность сильно упрощается, практически до уровня промисов js в точке склейки логики. Ключ идемпотентности больше применяется, чтобы дважды одно и то же не сделать, но и откатить при случае можно. Типа сложный трансфер прав на объект, который сопровождается дополнительным пересчетом, но это прям экзотика.
Нотификация может быть финальным шагом в логике, а может быть сразу в пачке действий, часть из которых обламывается. Не отправлять сразу, ставить в очередь с задержкой отправки, по сигналу отмены удалять. Работает вполне. По ключу потом и логи удобно вытаскивать.

Например что если данные лежат в двух отдельных БД — невозможно гарантировать их консистентность.
Почитайте, удивитесь: habr.com/company/oleg-bunin/blog/418235
Эта статья как раз отличная иллюстрация моего поинта. Чтобы обеспечить хоть какую-то целостность данных и транзакционность в распределенной системе — там ужас что пришлось городить. При этом этот их алгоритм все равно не гарантирует ни целостность, ни транзакционность — он лишь обеспечивает какой-то приемлимый уровень.

А еще в статье явно написано что они уперлись в производительность монолита. Т.е. до этого они монолите построили крупнейший в россии интернет-магазин.
А еще в статье явно написано что они уперлись в производительность монолита. Т.е. до этого они монолите построили крупнейший в россии интернет-магазин.


Там не так написано.

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


Они уперлись в производительность монолита.
Но видели пути решения.

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

И многие из этих статей делают вывод что надо сразу пилить микросервисы. Это неправильный вывод. Правильный вывод — сначала надо сделать попроще, а вот если взлетит — можно уже подумать как переделать, и на это уже будут деньги, и будет опыт и понимание как правильно делать.
Еще бы добавил, что микросервисы плодят дополнительные потоки (на ввод/вывод данных), оверхед на конвертацию данных (объекты в JSON/SOAP и прочую сериализацию) и усложняют инфраструктуру (часто требуя дополнительного сетевого оборудования и ПО типа nginx, для проксирования, балансировки).
усложняют инфраструктуру (часто требуя дополнительного сетевого оборудования и ПО типа nginx, для проксирования, балансировки).


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

К сожалению в Microsoft Visual Studio кнопки «приготовить пакет для инсталляции на Microsoft Windows Server 2016» не оказалось, а без кнопки выполнять поиск по соответствию пакетов библиотек платформе разрабочик отказалась, на основании того, что это потребует от неё работать сверхурочные.

Поскольку разработчик имеет неплохие отношения с отделом, начальник решил, что это не главное, работника не уволили, сервис запустили на платформе Microsoft Internet Information Service, и никаких нареканий по этому поводу не было.

Средства на освоение Microservice были освоены и выплачены, работа была не сделана, а недостаток компетенции инженера свалили на отсутствие кнопки в Microsoft Visual Studio.

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

Да, огромное количество продавцов в бывшем СССР, с подачи многих бухгалтеров, пользовались недостатками этой системы оплаты товаров народного хозяйства, и их ловили на кражах от копеечных до государственных ( и тогда за это рассреливали ). Говорят во времена Андропова сели все в один день. И сразу стали честно считать. Более того, даже во времена, когда Гребенщиков распевал с подиумов

«А я сра-ал на Вашего Ленина
И на весь Ваш савейський саю-у-усь»

я спокойно подсчитывал в уме стоимость трех килограммов сельди ( которой говорят нигде не было ) по 2 рубля и 13 копеек за кило, высчитывал среднее арифметическое в расчете на одну рыбу, просчитывал отимальную стоимость покупки, в плане калорий, веса, затрат бюджета с точньстью до 4-го знака после запятой, поправлял на реальную стоимость у прилавка, платил точно до копейки, при чем продавщица не смела пикнуть, запросив 11 рублей 50 копеек за 3,5 кило, и уходил от прилавка, когда следующий покупатель выкладывал уже 13 рублей за ту же покупку, на ответ «а почему он дал меньше», продавщица вежливо отвечала «неа, он дал столько же» а на попытку упорного покупателя, изрядно отдававшего спиртным, настоять на своем вежливо отвечала «а давай подсчитаем, е*лан поганый», чем вызвала взрыв доверия всей очереди криками одобрения и немедленную оплату покупателя, счастливо расстающегося с 3-е кратной суммой, поскольку в пересчете на потерянное время от удовольствия от алкоголя с вожделенной закуской, препирательства были неуместны.

Если Вы думаете, что в США продавщицы чем — то отличаются от продавщиц СССР, Вы очень глубоко ошибаетесь. В России просто не привыкли прятаться. К моему глубокому ужасу недавно в одном из крупнейших магазинов страны я наблюдал сцену, которую очень надеялся никогда в жизни не увидеть. Пьяный муж, на чистом русском мате, охаживал свою супругу, обслуживающую покупателей, чтобы она не слишком улыбалась, или её дома ждет полный ***.

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

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

К чему такие вот всемирные обобщения… казалось бы все очевидно. Все было бы очень хорошо, если бы этому самому, которому нужны компьютеры, сервисы, микросервисы и прочая, в общем — то не нужная дребедень, они нужны были чуть меньше. Именно нашему, Русскому… Мы не можем себе позволить не делать. Звезда у нас такая :)
Я могу передать всю вашу мысль в трех предложениях:
Микросервисы — есть следствие развития технологий. И это один из многих этапов этого развития, такой же, как само появление компьютеров. Если вы не понимаете зачем нужно развитие, посмотрите на то, как выглядел мир до этого развития.

Вы это хотели сказать? Тогда вы не правы.
Любая технология применима в одних ситуациях и неприменима в других. Вообще любая.
Какой то несвязанные поток предложений, вы не умеете формулировать мысли?
И причём тут рыба?
Причём тут IIS? Микросервис можно и на нём запустить, что именно девушка сделала не так? Докер тут вообще не причём, это всего лишь виртуальная машина.
Докер это все-таки технология контейнеризации, и сам по себе виртуальной машиной не является.
По пунктам:
1. Docker «это всего лишь виртуальная машина» — нет.
2. «при чем она» — ответ чуть ниже.
3. «Микросервис можно и» — нет, нельзя. Сервис, не изолированный от ОС является просто «сервисом». Другое дело, что определение не ограничивает средства изоляции контейнерами. Но то, что изоляция необходима определено совершенно четко.
4. рыба это пример, компьютеры не нужны, если принять концепцию автора «надо как дешевле, главное чтобы работало» Без компьютеров дешевле, и прекрасно работает.
>>Сервис, не изолированный от ОС является просто «сервисом».
Кто такую чушь сказал?
Та штука, поднятая на IIS, точно такой же микросервис. И это всего лишь вопрос удобства развёртывания и безопасности, в докере он, или нет, или в какой-то виртуальной машине, или на выделенном кластере.
Одно из двух, или все ПО microservice, включая то, что на тех самых «выделенных кластерах», или Вы не правы и хамите.

То есть Вы не правы и хамите.
Микросервис или «просто» сервис определяется не изоляцией, а функциями сервиса. Микросервис выполняет только один типа задач. Никто не запрещает вам на один физический сервер без всяких средств контейнеризации или виртуализации задеплоить 5000 микросервисов. С другой стороны, если вы запуститет виртуалки, в них докер и там разместите просто сервисы или монолиты, приложени ене станет вдруг микросервисным.

Квинтессенция статьи: "если вы не понимаете каким боком к вашему приложению приплести микросервисы — спите спокойно, они вам не нужны".

сервис на базе микросервис архитектуры Docker
— с каких это пор Docker стал микросервисной архитектурой?
микросервисы и архитектура Docker — вообще никак не связанные между собой вещи. Даже по Вашей же ссылке написано:
This guide is an introduction to developing microservices-based applications and managing them using containers.
Микросервисы иногда напрашиваются на старте — когда есть куски работы, слабо связанные по времени исполнения (имеется ввиду процессорное время) и результаты работы этих кусков допускают возможность краша. Сейчас работаю над проектом, в котором есть основной сервис со своей базой данных, и есть добытчик данных, которые основной сервис периодически запрашивает у добытчика. Оба сервиса, конечно, синхронизированы по времени обновления данных, но если у добытчика отказ, то основной процесс от этого не страдает — он работает на уже собранных данных — тут изначально напрашивалось разделение на сервисы, что и было реализовано в архитектуре. И здесь проявляются преимущества микросервисов — добытчики данных могут менять алгоритмы сбора данных как угодно без необходимости править весь проект — требуется лишь поддерживать стандарт интерфейса передачи данных между сервисами, можно балансировку и резервирование легко сделать для добычи данных — надо лишь на основном сервисе добавить адреса добытчиков. Сервисы в данном случае занимаются каждый своей работой.

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

Статья же — однобокая, но она так и задумана, наверное. Ведь действительно лучше сделать работающее приложение, которое еще сто раз поменяется, чем стараться изначально все эти сто предстоящих изменений предусмотреть — и, конечно, все равно ошибиться, ибо всего не учтешь. Но то, что изначально хорошо можно вынести в отдельный сервис — почему бы и не вынести, если есть время и ясное понимание и обоснование преимуществ такого решения.
UFO just landed and posted this here
Микросервисы — это не идея, это архитектурное решение на основе этой идеи в условиях распределенных систем. Не надо тут астронавта изображать.
UFO just landed and posted this here
Ну в целом да, любая nix система это набор отдельных программ, которые могут быть удалены-заменены без вреда для основной системы. Есть ядро (kernel), а остальное — внешние независимые друг от друга (в идеале конечно) программки.
Unix Way — это написать на Си отдельные программы и запускать их, пересылая текст через пайпы.
Микросервисы — общаться с другими серверами по сети, подключаемся по HTTP, пересылаем JSON, можем легко отмасштабировать горизонтально.

Идеи схожи, детали сильно различны, поэтому требуется отдельный термин (а есть еще S в SOLID, на ту же тему). Так-то ничего нового в мире, да и в литературе всего четыре сюжета.
UFO just landed and posted this here
идеи философии un*x: разделить сложную задачу на простые задачи

Нет, нету такого в философии юникс. Она про то, как писать одну программу так, чтобы её могли потом использовать как угодно. Подход к проектированию снизу-вверх.
А вот микросервисы уже про разбиение, подход сверху-вниз.
UFO just landed and posted this here
Можно ли киянку называть кувалдой?
UFO just landed and posted this here
Вы немного путаете частное с общим. Микросерисы, написаные на JS тоже умеются общаться через сокеты/pipe по желанию и посылать данные не в json. Просто по HTTP+JSON так проще и поэтому многие так делают.
Статья, ссылка на которую вы дали — это ужасно. Автор не понимает, что он несет.

XML вместо сырого текста — это упрощение работы, а следовательно экономия времени и прочих ресурсов. Оптимизация расхода ресурсов — краеугольный камень любой экономики. Авторы вывода только потому получились такие складные, что он выкинул из расчетов экономику вообще. При этом он лицемерно писал на компьютере текст, хотя мог разослать всем нам по голубю.
Гм-гм, Джоэл вовсе не топит за использование сырого текста вместо XML. Перечитайте статью.
Там на столько абстрактный текст, что можно что угодно в нем прочитать. По моему сам автор решил собой продемонстрировать, что такое абстракция.
Я там вижу две темы:
— Хейт неоправданной абстракции, т.е. когда абстракция начинает приносить больше проблем, чем решать.
— Хейт маркетинга, который врет о том, что новые штуки кардинально изменят жизнь, тогда как на самом деле они проводят только локальное улучшение.

А что видите вы?
Могу сказать, что монолиты тоже следуют этой же философии UN*X.
В каждом своде правил/советов по хорошему коду есть пункт типа «каждый фрагмент кода должен выполнять одну задачу», разумеется, делать это правильно.
UFO just landed and posted this here
Хм, даже не знаю как корректно ответить на ваш вопрос.
Грамотно написанные монолиты следуют этой философии. Т.к. вообще в программирование есть принцип разделения ответсвенности в коде.
UFO just landed and posted this here
Вопросы все сложнее и сложнее. Не очень понимаю вопрос. И точно не смогу ответить без четкого определения монолитной и микросервисной архитектуры.
Не получится.
Монолит отличается от микросервисов в первую очередь тем, что в монолите нельзя отключить определенный кусок когда тебе вздумается. Только целиком.
А микросервисами можно манипулировать — включил-выключил-поменял без остановки других частей.
И тут на сцене появляется Эрланг, позволяющий срезать подковы заменять куски хода прямо на ходу.
Не имел удовольствия прикоснуться к Эрлангу.
Если все как вы говорите, то если в куске, который заменили, во время замены проблема возникнет типа «Global apocalypse panic» — она за собой только этот кусочек потянет или всю конструкцию?
А к ПХП прикасались? ))
Прикасался. И как раз в нем можно одной буковкой запятой повалить вообще все. Это явление я бы и назвал «монолит», когда либо все либо ничего (ну в пределах адекватности трактовки слова «все», а то можно в нем копаться философски ради копания).
Я на другое намекал: как раз можно менять модули отдельно без остановки всего. Естественно, если не трогать такие модули как роутинг или фронт-контроллер.
Резать конечно хорошо, но вот включать/выключать, подключать «к куску кода» блок физической памяти, и выполнять прочие административные функции с ресурсами «куска кода» ни ЭрЛанг ни один другой язык не позволят. А уж тем более, не затрагивая при этом «остальные куски кода». Стандарт микросервиса может и написан языком «все можно, все верно, все разрешено», но там в сиропчике сладкого «делай что хочешь» залиты такие гвозди, что индийские йоги чихнуть боятся.
Монолит отличается от микросервисов в первую очередь тем, что в монолите нельзя отключить определенный кусок когда тебе вздумается. Только целиком.


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

Серьезные системы обновляют хитрым образом. Например, blue-green deployment или gaceful restart.

Эти же технологии применяются что для монолитов, что для микросервисов.

Без использования blue-green deployment/graceful restart и пр. вы и с микросервисами не можете поменять произвольную часть системы без остановки обслуживания клиентов.

Некоторые части системы — да.

Некоторые — ключевые, нет. Отключение их равносильно отключению сервиса целиком.

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


Система только выглядит рабочей.

Формально — да. Если 90% микросервисов у вас работают — то система рабочая как бы на 90%?

Фактически нет. Не рабочая. Пример ниже.

Пример: Интернет магазин.

Если вы отключите подсистему, отвечающую за формирование списка товаров и навигацию по нему (каталог товаров, витрина) — ваш интернет магазин не функционирует.

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

Ваш сайт мертв пока, вы не восстановите каталог товара.

Да, возможно, в этот момент кто-то уже в корзине и просто оформляет покупку. Однако:
а) Одного покупателя дает только 1000 или даже 10 000 посетителей.
б) Покупателем он становится после длительного прохода по каталогу товаров, выбора товаров.

Так что вы обслуживаете 1 покупателя в корзине/личном кабинете и даете отлуп 10 000 или 100 000 потенциальным, что нужен каталог.

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

habr.com/post/427215/#comment_19283943

Вот мне довелось обновляться — и я ВЫНУЖДЕН в монолите обновлять или всё или ничего.

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

Никто не говорит, что микросервисы — лучшее решение во всех случаях, или что оно «бесплатное», но и появилось оно не на ровном месте, от скуки.
Вот мне довелось обновляться — и я ВЫНУЖДЕН в монолите обновлять или всё или ничего.


Стоп-стоп-стоп. Речь совсем о разных вещах.

Во первых:

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

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

Вы же говорите о самом процессе модернизации системы, то есть об разработке или, по ненашему, development. Первая часть термина DevOps.

Во вторых:

Ваш пример — про сильносвязанную систему, изначально разработанную без учета принципов «Чистой архитектуры».

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

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

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

Так что виноваты не монолиты. А люди.

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

Но пришли безопасники и сказали — что для multi-tenancy так нельзя. И будьте добры запилить теперь в каждом микросервисе функционал для аутентификации и авторизации и шифрования для каждого tenant независимо. И вы встряли опять таки с тем же объемом работы, что и был в вашем примере. И для микросервисов он будет даже побольше, чем для монолитов.

P.S.:
Имхо, хороший монолит можно распилить на части и превратить в микросервисы относительно легко. Ибо все входящие в него сервисы изолированы, взаимодействие между ними идет на уровне известных интерфейсов.

Собственно, человечество еще в прошлом веке придумало для этого инструменты, используемые для написания больших программ — всевозможные «private vs public» в помощь принципа SOLID/«чистой архитектуры». Как раз, чтобы не было соблазна лезть в другой модуль напрямую. Как раз чтобы на выходе не получить мешанину сильносвязанного кода. Это нужно не только для микросервисов. С таким кодом и в монолите сложно работать. Например, проблема тестирования части функционала.

P.P.S.:
Довольно подробно pro/contra микросервисов рассказано тут
habr.com/company/flant/blog/424531
Ребята как раз специализируются на обслуживание всевозможных систем, в том числе и микросервисных.

Далеко не всегда:
Оправдываются ли ожидания с микросервисами?
image


Красным — неоправдывающиеся ожидания.
В том числе и усложнение (а не упрощение) разработки.

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

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

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


Есть и еще развернутые статьи:

m.habr.com/post/261689
Мартин Фаулер (умеет аргументировать). Компромиссы микросервисов

m.habr.com/post/311208
Микросервисы: пожалуйста, не нужно

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

Когда я размышляю о реализации той или иной задачи, я в первую очередь думаю… о задаче: ) Не о микросервисах или монолите, ни даже о фреймворке или библиотеках, алгоритмах — а о задаче. Я может быть несколько консервативен — но, признаюсь — я даже рисую схемы бизнес-процессов: ) стараясь в первую очередь представить картину предметной области в логическом смысле.

Получив такую картину, я начинаю понимать — что и как лучше реализовать, где можно и нужно отделить, а где — нет. Отделяю я те компоненты в микросервис, где могу делегировать ответственность в независимый компонент. Это как, например, распределение задач на выполнение разным людям — они будут трудиться совместно, но у них есть свои довольно четкие зоны ответственности. Кроме того, важно, чтобы разделение не вызывало необходимости чрезмерно плотной коммуникаций — когда людям приходится постоянно у друг друга что-то выспрашивать, чтобы выполнять свою работу. Микросервисы так же не должны разделять объекты в работе — то есть нет такого, что один объект изменяется из двух разных точек, все изменения проходят только как сообщения-данные между сервисами. Сервисы принимают данные и данные же возвращают, а не модифицируют «чужие» объекты. В общем я, даже не обладая большим опытом в микросервисах — уже, пожалуй, мог бы написать объемную статью — как именно я выбираю кандидатов на микросервисы.

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

И пока, всё что я прочел про «недостатки» микросервисов, является по моему мнению — недостатком в понимании: что именно и как следует разделять. Многое из того, что я прочел — я изначально не стал бы выделять в сервисы и для меня дальнейшие рассуждения о превратностях микросервисов уже более чем странные. Примерно как если бы кто-то написал:… и вот мы решили отправить рыбу лазить по деревьям…
Я здесь не пишу в духе «микросервисная архитектура — это лучшая практика» и, соответственно, статьи с антогонистическим посылом для меня мимо цели.


Ну что вы. Зачем с антагонистическим…
Скажем у Фаулера — и плюс и минусы отлично расписаны.
Во второй статье по моей ссылке — в те же самое что мы здесь пытаемся в комментариях обсудить. Но сформулировано стройно и развернуто. Чувствуется, у человека есть опыт.

Ну я чуть ниже написал, что согласен с многими выводами Фаулера. Я возражаю против посыла «Микросервисы — зло», возможно недопоняв, что под микросервисной архитектурой понимается стремление полностью всё приложение представить как набор микросервисов (отсюда и десятки микросервисов в приложениях), в то время как я сам делаю приложения не монолитной архитектуры и не микросервисной — а гибридной: )

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


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

Ну устроены мы так — напишешь скромно — читать будут меньше.
Замечу также, что Фаулер говорит практически то же, что думаю и я о микросервисах: )

Меня лично берет оторопь, когда пишут: «у нас 50 микросервисов» или «у нас более 100 микросервисов»… Э-э-э, что? Это действительно было необходимо? Чего вы добивались этим дроблением? Почему бы тогда уж каждую функцию-процедуру не завернуть в «микросервис»? Неудивительно, что проблема из «Большого комка грязи» превращается в проблему «Большого клубка связей».
habr.com/post/427215/#comment_19283943

Вот мне довелось обновляться — и я ВЫНУЖДЕН в монолите обновлять или всё или ничего.


А вот тут — ровно та же проблема что и у вас. Проблема с кодированием и общими библиотеками — привела людей из микросервисов к монолиту назад.

m.habr.com/post/416819
Прощайте, микросервисы: от ста проблемных детей до одной суперзвезды
Я для себя решил, что МС стоит использовать (как архитектурный подход), если необходимо создать по-ностоящему распределенное приложение, которое будет работать в облаке, так сказать cloud native. Во всех других случаях нужно 100 раз подумать.
Микросервисы — это как agile. В коде оно никак не проявляется. Повторю, микросервисы — это не алгоритмическое явление, а административное.

Чтобы понять о чём идёт речь, подумайте о разнице между обычной многосерверной архитектрой и микросервисной? Эта разница в том, кто пишет спецификации.

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

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

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

Даже хуже. Если у вас спецификации микросервисов будут писать те, кто пишет микросервисы, то вы получите комплет проблем микросервисов (сложность отладки и обслуживания), комплект проблем от неконсистентных API, комплект проблем из-за необходимости сопровождать все эти API в каждом приложении (а уж внесение изменений и поддержка нескольких версий сделает вашу жизнь восхитительно-загруженной).
У нас компания тоже идёт по пути микросервисов. Это было решено еще до моего прихода в неё, и я никогда не слышал каких-то более-менее вменяемых доводов в пользу этого решения. А сейчас в компании уже и тех людей нет, что приняли такое решение. Что еще забавнее, об этом было столько разговоров, но никто ничего не делал. Но т.к. решение политически было уже давно принято, то вариант разворота на 180 градусов даже не обсуждался.

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

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

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

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

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

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

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

Но мы бы не продолжали «ехать» в данном направлении, если бы сервисы несли только проблемы. Кратко перечень выгод:

— команда начала писать тесты (в старом легаси коде это было почти невозможно из-за повсеместного использования статических функций, синглтонов и нарушение паттернов — например, когда в модели неожиданно для тебя делается бизнес-логика)
— команда несколько обновилась: те люди, которые были причастны к написанию некачественного старого кода и не смогли приспособиться к новым подходам, были вынуждены покинуть команду
— ребята (даже самый зеленый юниор) достаточно быстро учатся (если уж не в сфере девопс, так в сфере качественной организации кода и покрытия его тестами), предлагают свои идеи, которые день ото дня всё более близки к реальным потребностям нашего продукта
— нет необходимости прикручивать сбоку костыли в старом легаси, когда можно написать что-то новое, идеологически более правильное, читаемое, тестируемое, масштабируемое
— мы начали активно использовать кубернетес в своей архитектуре, что нам позволяет гибко доставлять сервисы на продакшн и масштабировать только необходимое, а не весь монолит сразу
— нет привязки к одному языку, плюс легче производится апгрейд версии языка (раньше был только php версии 5.3, сейчас есть php 7.2, go и немного nodejs).

В общем, не всё однозначно, и не для каждой фирмы это имеет смысл, но если уж фирма на это решилась, то выгода обязательно будет. Но очень не сразу (особенно, если ресурсы ограничены).
А мне до сих пор не ясно как вообще работать через api со сколько-нибудь сложными данными. Банально в rest api не заложен join, что выливается в постоянное getAllIds(), request($ids) и назначение результатов. Или вот нужно выбрать всех клиентов у которых есть заказы… это вообще жесть: приходится добавлять динамическое поле и делать выборку по нему. А как иначе?
Так же в rest api гоняется очень много лишних данных из-за чего запросы по 200-300 мс — норма, хотя никакая это не норма.
Чтобы хоть как-то упорядочить весь этот ворох запросов даже придумали Swagger который реально выручает.

Но на горизонте уже виден новый многообещающий подход — graphql.
Верно — graphql. Избавляет от боли модификации api, кача избыточных данных, разрастания набора эндпоинтов. Запихнул его в свой проект с микросервисами — теперь у меня свой проект с graphql и микросервисами: )))

А кроме шуток, и говоря о заметке уровнем выше про опыт с микросервисами — я полагаю, что надо еще и осторожнее быть со связями между сервисами, то есть в идеале один сервис связан не более чем с двумя другими сервисами, обеспечивая иерархическое дерево, иначе геморрой при изменениях начинает расти экспоненциально как функция от количества связей на сервис. С одной стороны такое ограничение вроде как и противоречит концепции широкого переиспользования, с другой — это продиктовано соображениями локализации и сдерживания сложности. Если в такой ограниченной микросервисной архитектуре возникает необходимость изменений какого-либо сервиса, то это хотя бы не порождает слишком много изменений, а те, что неизбежны — по-крайней мере распространяются в известном направлении — вдоль своей ветви. Но это так — интуитивные соображения безопасности, реального опыта эксплуатации пока мало.
С одной стороны как будто-бы правда избавляет. И я с таким мнением сталкивался и у нас на параллельном проекте уже третий раз с ним срывают сроки. Увы — серебряной пули не существует, хотя регулярно всречаются люди, которые в них продолжают верить. GraphQL хороший инструмент, но с довольно специфической областью применения.

Та ситуация, с которой он позволяет бороться очень актуальна для кого-нибудь типа facebook, когда у тебя десятки тысяч независимых разработчиков и все хотят разные срезы данных. При этом в жертву приносится значительный кусок функционала от протокола HTTP (состояния, ошибки, уникальные идентификаторы ресурсов, кэширование, докачка), очень сильно ограничивается инструментарий (вся куча кода написанная для http routing) и появляется необходимость поддерживать еще один слой абстракций. Причем если худшем случае задача — только передача данных, то разработка превращается в написание очередного протокола общения с базой данных (где кстати уже есть тоже не шоколадный, но более распространенный ODATA), а если нет — то корявенький RPC.

Если задача — махровый энтерпрайз, и количество независимых разработчиков под твое приложение — ноль, то graphql это скорее помеха, опять же не сам по себе, а в связи с тем, что для него нужно тащить библиотеки — которые под кучу языков — сырые.
О серебристости GraphQL речи не идет, но есть два фактора, которые позволяют его эффективно применить в ряде задач. Во-первых — это его явные преимущества, которые я перечислил выше, а если говорить коротко — то это его высокая гибкость по сравнению с тем же REST.

Второе же заключается в том, что используя graphql необходимо и мыслить в концепции graphql, попытки же сделать «как в REST, только GraphQL» к хорошему явно не приведут, что, в общем-то, справедливо для любой технологии.
> мыслить в концепции graphql,

если речь о том, что к любому такому инструменту нужно адаптировать свой мыслительный процесс — 100% соглашусь с вами, а вот если то, что надо бизнесс задачи переформулировать так, чтобы они под graphql подходили — это вряд ли соглашусь. Для гвоздей — молоток, для шурупов — отвертка, а микроскоп вообще не для строителя.
Да, конечно, речь идет о понимании концепции, а часто у специалиста есть опыт работы с какой-то технологией — и он переносит его целиком на другую, из чего получается натягивание совы на глобус, а по итогу этот специалист говорит: да фигня эта «сова» ваша. Что же касается адаптации задачи к технологии… я сталкивался не раз с тем, что одна и та же задача вполне себе решается несколькими способами, вполне хорошо решается. У каждого решения — свои плюсы и минусы, и тут требуется решить — какой набор плюсов/минусов удобнее. Ну и, конечно, возможно это только если способен эти разные решения создать, чего никогда не будет, если есть предубеждения против чего-то — а по факту это неумение работать с той или иной технологией.
Соглашусь. Верно и обратное. Когда есть только молоток, то все задачи превращаются в гвозди.
в идеале один сервис связан не более чем с двумя другими сервисами, обеспечивая иерархическое дерево

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


иначе геморрой при изменениях начинает расти экспоненциально как функция от количества связей на сервис.

я предпочитаю один геморрой на сервис (количество связей в нулевой степени), а не, например, 4 при связи с двумя сервисами :)

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

Разумеется, это не про те «микросервисы», которые на самом деле уже и не «микро», а полноценные приложения, к которым обращается масса других приложений за какими-то данными.

Вообще же, надо просто понять — откуда есть пошли эти микросервисы. Они ведь появились не только лишь потому, что кому-то вздумалось «поиграть в микросервисы». Микросервисы — это логичный ответ на конкретные задачи. Я выше тут писал про свой пример — у меня есть в проекте задача обслуживания клиента, и есть задача периодического мониторинга неких данных, которые я предоставляю клиенту. Можно обе задачи решать в рамках одного монолитного приложения, но так же хорошо эти две задачи могут работать и по отдельности. У меня нет сильной связанности между двумя этими задачами: то есть сбор (обновление) данных конечно нужен, но если он не увенчался успехом в очередной итерации — клиенту допустимо предоставить на его запрос предыдущие данные. Другая особенность состоит в том, что сбор данных может меняться довольно часто из-за того, что сам источник этих данных изменяется и под него надо подстраиваться — в условиях монолита это будет означать необходимость править весь проект, прерывать обслуживание клиентов при апдейте проекта. А в условиях микросервиса — я могу править сервис более удобнее. Я могу вынести микросервис сбора данных куда угодно — это, кстати, тоже одна из задач проекта, так как наш доблестный РКН любит поиграть в модераторов. Я могу наплодить кучу одинаковых микросервисов, тем самым зарезервировав их, я могу относительно легко добавлять микросервисы с другим типом собираемых данных — конечно же тут придется и принимающую часть изменять для того, чтобы она умела эти данные принять, но вся инфраструктура уже построена — нужны лишь кастомны методы приема и обработки конкретного типа данных.

Я не являюсь ни теоретически подкованным в микросервисах, ни обладателем обширного практического опыта их применения, ни даже их почитателем — я использую то, что разумно в поставленной задаче.
Вот, кстати, еще один прекрасный практический пример — в чем смысл микросервисности. Сейчас у меня на одном из проектов есть задача обновить приложение — оно отстало от текущих версий на три апдейта фреймворка. Приложение — монолитное, но есть в нём, например, такой модуль работы с соцсетями пользователя — неосновная задача приложения. И вот с ним мне пришлось повозиться, так как он и сам так же устарел относительного текущих версий фреймворка, и базируется на компонентах, которые тоже устарели. Будь это отдельный микросервис — а это вполне реализуемо в рамках проекта, я, возможно, даже и не стал бы его обновлять — работает и работает, задача его — далека от основного процесса проекта и без особой разницы как он там реализован. Но — нет, мало того, что мне по-любому пришлось его обновлять и переписывать местами, чтобы он соответствовал и работал в составе обновляемого фреймворка, так еще и созданные им зависимости проникли в код монолита (включены в модели), так что не обошлось одной лишь правкой в отдельном модуле, и пришлось обновлять все пакеты, от которых этот модуль зависит.
Вы правы, и столкнувшись с данной проблемой, я чуть более года назад написал вот такое для php (в случае использования symfony + doctrine): github.com/artprima/query-filter-bundle. Для внутренних потребностей у нас работает весьма неплохо (хотя, конечно, кто-то сейчас скажет, зачем использовать symfony и доктрину для микросервисов, но это мы оставим за скобками). Для использования для внешнего апи нужно, наверное, провести аудит на предмет уязвимостей (на первый взгляд я вижу только возможность делать тяжелые запросы, которые не попадают в индексы).
P.S. Документация к коду не полна, как всегда :( Например, там не задокументированы алиасы для полей (что позволит скрыть t.tableName за чем-то вроде pinkPony).
P.P.S. GraphQL, кстати, тоже не спасёт от тяжелых неиндексированных запросов. Вообще, произвольный доступ к данным и практически произвольная фильтрация — это достаточно сложная задача не только со стороны API, но и со стороны безопасности и эффективности.
> Банально в rest api не заложен join

Что значит «не заложен»? Принципі rest не запрещают вам вытягивать сколь угодно сложные схемы.
Не запрещает. На автомобиле наверное тоже можно взлететь если разогнаться до скорости света.
Многие из тех же аргументов можно использовать просто против модульного построения приложения. И мне доводилось их слышать как раз в таком контексте.

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

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

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

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

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

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


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


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

ООП тут особо непричём, скорее нужно изучать DDD

Самое интересное, что я в последнее время тоже начал так начинать писать… После 20 лет работы программистом. Сначала заморачивался над будущей структурой, каким-то продумыванием заведомых узких мест для оптимизаций и прочим бредом, что отнимало много времени и в итоге всё-равно не было похоже на запланированное, т.к. в ходе разработки многое меняется. Сейчас открываю редактор и начинаю писать сразу, по мере надобности начинается рефакторинг и оптимизации… Но всё чаще и чаще этого вовсе не требуется. С опытом, наверное, приходит.
Только вот сегодня утром размышлял над тем, как происходит от поганого кода к красивому и лаконичному.
Цитата
Как вы думаете, Тобиас сидел в нерешительности, кропотливо продумывая идеальную архитектуру на микросервисах, прежде чем написать первую строчку кода?

Чёрт, нет. Я не присутствовал при разработке первой версии Shopify, которая изначально была просто интернет-магазином для сноубординга, но если Тобиас похож на меня (типичный разработчик), то процесс выглядел примерно так:

1. Изучить новую технологию в процессе написания исходного продукта.
2. Написать довольно нестандартный (поганый), но полностью рабочий код.
3. Посмотреть, как всё работает вместе и возбудиться.
4. Провести рефакторинг типа «выжигание огнём» и улучшить код, когда возникает проблема.
5. Повторять этот цикл при добавлении новых функций и запуске в рабочей среде.
Автор прав. Спасибо за перевод.
Sign up to leave a comment.

Articles

Change theme settings