Комментарии 45
Хотелось бы посмотреть на реальные примеры проектов которые построены по этой архитектуре. А то идея вроде бы интересная но требует довольно много людей для поддержки разных сайтов.
Странно что в статье нет ни слова про OSGI. Хотя именно выход осги контейнеров в ентерпрайз, как по мне, и дал возможность делать хорошие не-монолитные приложения ентерпрайз уровня: с разбиением функционала на отдельные бандлы, с очередями, транзакциями и всем тем что раньше было возможно только на j2ee серверах.
Я не соглашусь. Просто OSGI отлично подходит под определение микросервисов. Но если зависимости приложения не адаптированы для OSGI, то адаптация — дополнительные сложности и боль на проекте.

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

Почитайте посты как современный вариант решения Micro Services the easy way with Fabric8 , Apache Camel for Micro­service Architectures

У меня есть опыт разработки приложения, которое можно разворачивать как в OSGI контейнере, так и в обычной jvm без OSGI зависимостей благодаря использованию blueprint в OSGI (dependency injection framework) и немного своего кода для деплоймента в обычную jvm
Про fabric8 не слышал, гляну, спасибо. Просто последнее время большой хайп вокруг деплоймента не то, что в виде отдельных процессов, но и процессов в отдельном контейнере. Я имею в виду mesos, marathon, docker и так далее. Оно и понятно — чем больше изоляция, тем больше безопасности и управляемости, но и проблем с latency тоже больше, это понятно. Я так понимаю вы оптимизируете больше под latency, в то время как веб он обычно больше throughput ориентированный.
Про fabric8 мои знания теоретические, документация и общение с архитектором из Red Hat. Я работал с fuse fabric на одну версию раньше. Все никак не попробую деплоймент в kubernetes/CoreOS и мониторинг cAdvisor. За год появилось очень много нового и перспективного
OSGI поидее скорее о модульности сервиса. Может в частном рассмотрении это конечно что-то вроде…
Но «true» микросервисы это разделении монолитной аппликации на сервисы (процессы) не на модули.
Толковый комментарий

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


В java возможно развертывание множества микросервисов в рамках одного процесса используя OSGI: что решает проблему с переразвертыванием в процессе работы, а так же четко определенными интерфейсами самих сервисов и реестра в котором они регистрируются. Микросервис в отдельном процессе выгоден в том случае, если требования по отказоустойчивости, времени отклика(настройка сборщика мусора под конкретный сервис с заданным требованием к максимальным паузам GC). Распределенность всегда добавляет накладные расходы и определенные сложности. Все зависит от требования и задачи!

Тем не менее, использование сервисов подобным образом имеет свои недостатки. Удаленные вызовы работают медленнее, чем вызовы в рамках процесса, и поэтому API должен быть менее детализированным (coarser-grained), что часто приводит к неудобству в использовании.

Каждый раз когда вы имеете набор синхронных вызовов между сервисами, вы сталкиваетесь с эффектом мультипликации времени простоя (downtime). Время простоя вашей системы становится произведением времени простоя индивидуальных компонент системы. Вы сталкиваетесь с выбором: либо сделать ваши вызовы асинхронными, либо мириться с простоями.

В случае последовательных синхронных вызовов в распределенной системе большое значение имеют задержки (latency) а не только пропускная способность канала передачи данных(throughput). Асинхронность добавляет дополнительную сложность, но и ускоряет работу во многих случаях. В случае развертывания микросервисов в одном процессе можно выбирать между удаленными вызовами(REST, Distributed OSGI или другие) и локальными в рамках одного процесса

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

Ох…
Это жизнь. У меня раньше между сервисами бегало всё в JSON-RPC через TCP. А потом потребовалось дать доступ к сервисам для сторонних разработчиков, и всё, оппаньки — пришлось заворачивать всё в HTTP, добавлять OAuth, для событий EventSource (ну хоть его не сильно переусложнили). А куда деваться, если клиентом для сервисов может выступать в т.ч. и одностраничное веб-приложение на js? Плюс пришлось обходится без реестра сервисов (чтобы не усложнять для средних js-программистов и без того непростой внешний интерфейс ещё и дополнительным приключением «найди как подключится к нужному сервису и будь готов к тому, что он может пропасть или поменять адрес»), что не лучшим образом сказалось на динамичности и простоте администрирования всей системы.
Сделали бы midlware, которая с клиентами общается так как им хочется а с Вашей средой как Вам. И безопаснее и проще и имеет много других ++. У меня страшный SOAP завернулся nodejs в json-rpc2 за день.
Сделал бы. Может дальше что-то такое и нарисуется, но пока в этом нет смысла — 98% API всех сервисов, по задумке, должно быть доступно внешним клиентам. В таких условиях проще наоборот, для своих же сервисов организовать точно такой же стиль доступа (через OAuth), как для внешних клиентов.
О, наконец-то как-то назвали то, что я делаю с 2009-го. Это очень хорошо, такую архитектуру надо активно популяризовать. Возможность постоянно работать с проектом, который полностью «помещается в голове» — это реально game changer! Но вот первоначальная разработка архитектуры — интерфейсов и связей между основной массой базовых сервисов, решение проблем поддержания целостности данных без ущерба для производительности — это пока что очень нетривиальная задача, на которую уходит много времени при старте проекта.
Дык не надо всю архитектуру сразу и доконца. ;)
В этом то и «геймчэнджер» что ошибки прощаются легче, и можно начинать с известных и понятных сервисов… (Аджайл!)
И все можно достаточно незатратно поменять в процессе, огхраничив последствия изменений в переделах одного сервиса (в идеале конечни).
А вот продеалть тоже в «Энтерпрайзном» монолите через годик работы — писец :)
О всей сразу речь и не идёт, разумеется. Но пяток-десяток базовых сервисов, без которых все остальные работать вообще не смогут — нужны (реестр сервисов, генератор uid, диспетчер событий, аудит/логи, мониторинг, защита от DoS, ну и прочая аутентификация с авторизацией и минимально нужными им базами юзеров, клиентов, их прав, базовый профайл юзеров, OAuth, etc.). Плюс продумать протоколы, контроль прав доступа, кеширование этих прав, как делать eventual consistency хотя бы для этих сервисов, защиту от зацикливания запросов между сервисами…

Раньше у меня были проекты в которых сервисы были внутренними, доступа к ним снаружи не было. И всё было значительно проще. А сейчас надо делать публичную платформу, которую будут пытаться ломать, к которой скорее всего придётся прикручивать биллинг за вызовы API… и всё резко стало намного серьёзнее.
А сейчас надо делать публичную платформу, которую будут пытаться ломать, к которой скорее всего придётся прикручивать биллинг за вызовы API…

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

Кстати, требование полной асинхронности, в свою очередь, ведёт к тому, что писать эти микросервисы на языках без поддержки лёгких нитей (вроде Perl или Node.js) значительно сложнее, чем на языках где она есть (вроде Go).
Требования что эти микросервисы обязательно должны использовать лишь ассинхронную модель нет.
Хотя я согласен с вами, лучше сразу её закладывать. Тоже сталкивался с каким-то срахом у разработчиков перед таким подходом…
Но в принципе не обязательно и вовсе не везде…
Тут Кроме ассинхронности куча нестандартынх решений… Например людей приходится убеждать что
одна большая база данных это уже не торт как в 80/90 тых.
Коллеги, поделитесь мыслями о том — каким образом в SOA или в микросервисной решить проблему, когда ты не можешь декомпозировать сервис на меньшие части просто потому, что несмотря на отдельно различимые предметные области, описываемые в модели БД сервиса, эти модели имеют такой объем внешних ключей друг на друга… что даже при их разделении на отдельные сервисы, они будут абсолютно и полностью зависимыми)

И при этом получается, что под шиной может сидеть до 10-20 сервисов, данные в БД каждого из которых на 30-40% дублируются, просто из-за реляционных связей, через которые можно связывать другие 60-70% данных этих сервисов)

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

Но если включить телепатическую машинку и начать гадать по симптоматике, то обычно такая проблема возникает в двух ситуациях: либо Вы пытаетесь делить на части не в том месте — правильное место то, где между частями получится небольшое количество слабых связей, либо Вы пытаетесь решить проблему недостаточным количеством сервисов — попробуйте посмотреть что получится, если разделить всё на ещё более мелкие части.
А ещё имеет смысл присмотреться не к данным и их предметным областям, а под другим углом — к связям между данными. Нередко оказывается, что разные связи нужны совершенно разной функциональности, так что можно для каждой такой функциональности сделать отдельный сервис и изолировать нужные ему связи внутри его собственных данных.
Присоединяясь к powerman дополню, что делить ради деления смысла то может и нет. Если не видите явных причин иметь отдельные сервисы то может не надо вам это…
В общем пережде чем делить в рамках SOA вам надо задать себе вопрос какую business capability (бизнесс-возможность/способность) должен олицетворять сервис.
Она должна быть осмысленна иммено с этой стороны. Например, сервис который знает что-то про запчасти, про сотрудников, третий про ресурсы, четвертый бух-учет, и т.д.
И даже если у сервиса сорудников и сервиса бугучета будут общие обьекты это совершенно не помешает вам (см: BoundedContext: martinfowler.com/bliki/BoundedContext.html )

Причем в моем понимании сервисы в корпоративной SOA это немног не о том… Можно конечно так её рассматривать. Но всеже…
Например можно иметь один достаточно сложный сервис в соа который будет сам по себе аппликацией сосотоящей из микросервисов.
В моем понимании парадигма микросервисов это скорее девелопер-дривен. А СОА это бизнес-дривен.
У меня rule of thumb — всё, что может быть (адекватно, без создания сильных связей между сервисами) вынесено в отдельный сервис — должно быть вынесено! Исключительно из соображений, что чем меньше каждый микросервис — тем проще его поддерживать, и из чем большего количества отдельных микросервисов составляется общий проект — тем гибче его архитектура и тем легче её изменять под меняющиеся бизнес-требования. Вы этот подход назвали «developer-driven», или что-то другое?
Ну да вы с технической и пракатической на это смотрите. Если я правильно понимаю то что вы описывате вы полностью прониклись идеей ;)
Я в свой фирме тоже в эту сторну толкаю, но люди привыкшие к монолитам пока с недоверием смотрят на мой проект ;)
Есть частный проектик, где я имею все свободы — и там я тоже руководствуюсь юниксовской филисофией ( do one thing and do it well)

Просто пару лет я был консалтером и мы продовали «Эндерпрайз СОА». И вот в этом мире другие вещи в фокусе.
Там речь идет о орхестрации сервисов и их подвешиванием к примеру в сьиты BPM или приочие штуке длай мэнеджмента.
При этом вопросы о архитектуре самих сервесов или их легковесности не в фокусе тематики…
И сервисом может оказаться вдруг какая-нибудь страшная API управляющая какими-то сущностями в SAP/R3 или прочее легаси…
Это конечно не лучшие примеры, но тоже СОА…
Нда. Спасибо за ссылку. Я там много чего перечитал за эти часы, в общем всё достаточно адекватно.

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

Закончится всё бедой — вполне обычные ошибки и неудачные подходы к решению проблем, когда они коснутся асинхронности, eventual consistency, fault tolerance и прочих критичных для микросервисов вещей, выльются в гораздо более крупные неприятности, чем они привыкли для монолитных приложений. Вернёмся к этому комментарию лет через пять, убедимся.
Может быть… Но с другой стороны, так хайпует Docker со всей этой (легковесной) экосистемой вокруг него… Что очень обнадеживает
Я имею ввиду вот что. Предположим, у меня есть 2 достаточно громоздких модели данных в БД. Предприятия, автомобили и запчасти. Получается, что я не могу их разделить на 3 (микро)сервиса, ибо внешние ключи. Если я хочу разделить их на 2 — в обоих (микро)сервисах должны быть данные, которые позволят связать данные отсюда, с данными в других.

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

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

Получается, что без такого дублирования данных в отдельных сервисах не обойтись, т.к. только оно и связывает данные в них?
Вы не о том думаете. Микросервисы — это не про вынос отдельных таблиц из РСУБД в виде отдельных сервисов. Если у Вас реляционная природа данных — оставьте их в РСУБД. Думайте не о данных (БД), а о функциональности (сервис), которая поверх этих данных реализуется. И стройте архитектуру микросервисов так, что большинство новых фич можно было добавлять в виде отдельных сервисов, а не нескольких дополнительных полей и связей в общей базе.

Если, например, автомобили и их запчасти сильно связаны между собой и большинству фич нужно оперировать одновременно и тем и другим — сделайте отдельный сервис, реализующий все эти фичи, и хранящий автомобили и запчасти в собственной реляционной базе. Так делать можно, иногда нужно, но вообще-то этот сервис скорее всего будет не «микро» — если большинство изменений функциональности будет требовать добавлений и даже изменений API этого сервиса, значит Вы идёте не туда. (К сожалению, пока что у меня складывается впечатление, что enterprise будет делать «микро»сервисы именно таким образом, из чего ничего хорошего не выйдет — сделав из одного монолита 5-10 таких псевдо-микро-сервисов они по сути просто добавят в середину своего монолита массу ненужной сложности с асинхронностью, eventual consistency, etc. — и это будет очень-очень больно в конечном счёте.)

Ещё может помочь фантазия на тему: а что, если бы всех этих автомобилей и запчастей не было у Вас в базе, и не было достаточно простого способа их туда положить? Представьте себе, что в ТЗ на разработку Вашего приложения было бы сказано, что информацию по автомобилям и/или запчастям нужно получать через REST API какого-нить внешнего сервиса(ов). Как могло бы выглядеть API этого(их) сервиса(ов), предоставляющих информацию по автомобилям и запчастям, но ничего не знающих о конкретных нуждах и фичах Вашего приложения, и как бы Вы реализовывали нужные Вашему приложению фичи в этих условиях? Как выглядела бы реализация Ваших фич? А чтобы исключить рефлекторную попытку всё сделать как обычно — эти внешние сервисы не дают возможность выкачать всю их базу и в дальнейшем её обновлять — например, у них доступ к API платный и/или ограничения на количество вызовов API.
Кто и что является клиентами этой базы данных?
Какие запросы типичны?
Если вам кроме широковещательных запросов пригодятся к примеру API только по моделям, только по предприятиям или только по запчастям, то почему бы не разделить на 3 сервиса…
А по широковещатесльным дергать все 3?
Но это только попытка понять задачу…
Может вам всегда надо список деталий, с моделями и предприятими и быстро… а по отдельности никогда не интересно впринципе… тогда и делить может не надо.

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

Для меня это значит, что либо было выбрано неверное направление декомпозиции. Либо для самой задачи подход SOA или микро-сервисов не является корректным. Однако SOA практически везде, где я о нем читаю, преподносится как панацея)) Вот мне и интересно, предлагает ли SOA какие-то свои способы декомпозиции (ориентированные на функционал сервисов, а не на модели хранения данных)… или все это на совести и фантазии архитектора?)
Вы постоянно отвечаете не на комментарий, а на сам топик, из-за этого если бы я случайно не зашёл в топик то не узнал бы о Вашем ответе. Нужно нажимать на "ответить" под комментарием. Это древняя проблема юзабилити хабра.

Панацей не бывает.

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

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

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

P.S. На самом деле я много лет назад «придумал» микросервисную архитектуру когда пытался отобразить модульный подход используемый в Limbo (есть такой язык в OS Inferno, фактически он один из языков из которых вырос Go) на языки без лёгких нитей — Perl, Python. И я должен заметить, что оригинальный подход, который я «сэмулировал» в виде микросервисов — намного проще и эффективнее. К сожалению, одних лёгких нитей для него недостаточно, нужна ещё нативная поддержка 9P, которой в Go, насколько мне известно, нет. Другой пример этого же модульного подхода, для разнообразия используя внешние приложения — UNIX шелл и тысяча мелких, ничего не знающих друг о друге команд, работающих совместно через конвейеры. Так что цимес вовсе не в микросервисах, а в правильной декомпозиции и умении её сохранять в процессе развития проекта.
Очевидно нет универсального метода декомпозиции, есть несколько эвристик и опыт.
И как обычно в архитектурах куча Trade-offs :)
Отличный перевод, спасибо автору за это! Но я нашел немного опечаток) Вот некоторые

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


и еще тут

это компоненты, выполняемые в отдельном процессе и коммуницирующие между собой через веб-запросы или remote procedure call (RPSС).


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