Рис.1
Рис.1

Попробуем начать с цитаты:

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

...

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

Если интересно откуда эта цитата и что с ней не так прошу под кат.


Это цитата из книги которая написана более 25 (это не ошибка!) лет назад.Просто цитата не совсем коректная. Вот более полная версия:

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

Рис.1
Рис.1

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

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

Рис.2
Рис.2

В чем же заключается современная идея микросервисов? Может быть в том, что сложные приложения надо поделить на простые и по возможности распределить эти простые приложения на разные компьютеры (даже на разные серверы). Казалось бы тут сразу должен возникнуть следующий вопрос: «Зачем делать именно так, ведь работа распределенной системы связана с дополнительными накладными расходами и дополнительными задержками связанными с взаимодействием по сети или даже со взаимодействием между условными сервисами в разных процессах на одной машине?». Но такой вопрос просто не принято задавать в приличном нано-технологичном обществе, в котором все издержки представляются как нано-издержки, а микросервисы это слово прогресса и просто путь в лучшее будущее.  Вы же знаете, последний писк моды это взаимодействие между микросервисами через текстовый интерфейс на базе древнейшего HTTP, так называемый Rest API, а не какой нибудь SOAP например, или не дай бог CORBA. Вообще то изначально не было никакого Rest API был просто HTTP протокол предназначенный для общения браузера с сервером для навигации и управления контентом, который хранится на сервере, но прогресивная мысль не стоит на месте и продвинутые разработчики быстро смекнули, что можно писать целые куски распределенной программы, которые будут общаться с другими кусками этой распределенной программы через тот же HTTP протокол. А это круто! C таким опытом вас с руками оторвут любые эффективные менеджеры с деньгами. Конечно этот метод взаимодействия внутри одной программы (системы) несет в себе достаточно большую избыточность, создает дополнительные задержки, но кого это волнует когда придумано такое модное название для этого перформанса как RESTful веб-сервисы, когда любой программист может вам с гордостью и даже с некоторой надменностью сказать: «Я работаю через RESTful интерфейсы, разрабатываю микросервисы», попробуйте что-то возразить против такого метода работы.

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

Источник цитат

Это цитата из перевода книги «Inside COM». by: Rogerson, Dale, 1966-. Publication date: 1997. Конечно книга была посвещена Компонентной архитектуре, а ни как не Микросервисной, я просто заменил в цитатах все однокоренные слову «компонент» слова словами производными от слова «микросервис». Но вы можете заметить, что если рассматривать слово «компонент» как противоположность слову «монолит», то замена является совершенно корректной, так как в нашей современности «микросервис» все также выступает в качестве противоположности «монолиту», в этом отношении ничего не меняется. Задача противостоять Монолиту видимо очень не простая, поэтому разработчики используют тактику замены кандидата для противостояния.

Но что же предлагалось авторами концепции деления приложений на компоненты:

  • возможность замены компоненты на лету в работающем приложении (например пока функция за которую отвечает компонента отключена),

  • повторное использование компоненты в другом приложении - в приложении с другим набором функций,

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

  • но верхом совершенства древние программисты тогда считали возможность распространять-передавать пользователям части программ в виде бинарников!

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

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

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

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

Мне показалась очень интересной и поучительной следующая аналогия из этой книги:

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

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

Если Вы пишете программы для UNIX, Macintosh, Linux, VMS или какой-либо другой операционной системы, эта книга также будет Вам полезна. Концепции, заключенные в СОМ, работают не только в операционной системе Windows, СОМ — это не большой API. COM — это способ программирования, стоящий в одном ряду с такими способами, как структурное или объектно-ориентированное программирование. Вы можете использовать подход СОМ в любой операционной системе. Конечно, Windows предоставляет код, который облегчает программирование «в духе СОМ», но большую часть этого кода нетрудно реализовать на Вашей любимой платформе.

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

Комментарии (18)


  1. rinace
    03.10.2024 03:52

    Ну и банально, сорри за повторение - вся идея о микросервисах не имеет никакого смысла , если все эти "микросервисы" взаимодействуют с общей СУБД.

    Пока , я только такие решения встречал. Возможно , в природе есть и другие решения. Но пока архитекторы просто выделяют отдельную БД все кластере и называют это - "мы реализовали микросервисную архитектуру".


    1. flancer
      03.10.2024 03:52
      +6

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

      На мой взгляд требование отдельных БД сравнимо с требованием отдельного ЦОДа для каждого микросервиса. Чтобы не было единой точки отказа. Можно, но не обязательно.


      1. rinace
        03.10.2024 03:52
        +4

        Что на концептуальном уровне мешает микросервисам использовать общую СУБД? 

        Всего 3 слова : "конкуренция за ресурсы". Или другими словами один микросервис влияет на все остальные . Если это считается "микросервисной архитектурой", пусть. Для DBA разницы никакой .

        Для микрорешений для 1-10 пользователей и десятком TPS , это вполне работает и они это называют "микросервисы" и очень гордятся.

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

        Появился новый микросервис - появились новые таблицы в общей БД.

        :-)


        1. saboteur_kiev
          03.10.2024 03:52
          +5

          Всего 3 слова : "конкуренция за ресурсы".

          А если BD не является бутылочным горлышком?

          "взрослая работа" - это просто подмена понятий. Есть куча приложений, которые уперлись в производительность СУБД, есть куча приложений, которые не уперлись. Вторые - обязательно детские?


        1. flancer
          03.10.2024 03:52

           Для DBA разницы никакой .

          Согласен. Но DBA и не архитектор.

          :-)

          В Magento именно так и происходит, только на уровне плагинов. И в WordPress так же, насколько я в курсе. Думаю, что и во всех популярных CMS'ках с плагинами точно так же дела обстоят: добавляешь плагин - появляются новые таблицы в БД.

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

          Так бывает. И не только в микросервисах. Для этого кэши и придумали. Как будто гонять данные между базами микросервисов для их синхронизации (репликации) много лучше?


      1. powerman
        03.10.2024 03:52
        +12

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

        Нет никакой проблемы физически хранить таблицы разных компонентов/микросервисов в одном Postgres, но в разных схемах/databases, требующих для доступа к этим таблицам разную аутентификацию. При таком подходе не получится залезть напрямую в чужие данные просто потому, что нет чужого пароля для доступа к ним. А попытка добавить своему компоненту/микросервису в конфигурацию пароль от чужой БД будет крайне заметна на всех уровнях (от ревью этого PR до девопсов которым нужно будет обеспечить передачу "лишнего" пароля при выкате) и обычно будет кем-то успешно заблокирована, даже если разработчик попытается такое реализовать.

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


        1. rukhi7 Автор
          03.10.2024 03:52

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

          вы наверно имеете ввиду "сложно нарушить НЕЗАМЕТНО", то есть чтобы хотя бы некоторое время сохранялась видимость что все нормально работает. То есть границы должны быть явные в том смысле что они делают явным нарушение этих границ.

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


          1. powerman
            03.10.2024 03:52
            +4

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

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

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

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

            • Любое (без исключений) изменение API компонента/микросервиса требует аппрува от архитекта.

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

            Более того, я не рекомендую использовать компоненты вместо микросервисов на языках, на которых нет технической возможности надёжно изолировать код компонентов друг от другах. Например, в Go есть возможность изоляции компонентов в рамках одного бинарника с помощью internal/ пакетов, что даёт возможность использовать компоненты вместо полноценных микросервисов не ослабляя уровень изоляции (чтобы один компонент не смог напрямую, минуя публичное API, вызывать код другого компонента). Если же язык или сторонние утилиты (линтеры) не позволяют гарантировать изоляцию, то безопаснее использовать полноценные микросервисы, не смотря на накладные расходы на сетевое API и прочие сложности распределённых систем - это всё-равно лучше, чем превратить проект в очередной "комок грязи".


            1. rukhi7 Автор
              03.10.2024 03:52
              +1

              • Любое (без исключений) изменение API компонента/микросервиса требует аппрува от архитекта.

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

              А вот полагаться на мысленные эксперименты квалифицированного эксперта-архитекта - это как раз самый плохой способ

              вы не верите в эффективность такого анализа, как же вас понимать?

              если есть

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

              то архитекторы вроде как и не нужны.

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


              1. powerman
                03.10.2024 03:52
                +2

                Может я неправильно понял Ваш предыдущий коммент, но в моём понимании в нём шла речь о любом изменении системы. Требовать квалифицированного ревью каждого PR на предмет "не нарушили ли мы тут случайно архитектуру" - это тупиковый подход. В моём варианте ревью архитекта требуется крайне редко, только в случае изменения API/конфига, т.е. тех точек, в которых определяются связи между компонентами/микросервисами. Эти связи - как раз область ответственности архитекта, он их изначально спроектировал, и он же должен контролировать их изменение в процессе развития проекта. В идеале в этих точках может даже и кода толком не быть - API обычно описан в swagger.yml или .proto-файлах, конфигурация либо в коде (но это просто структура данных) либо в yaml-конфигах оркестратора. Таким образом архитект контролирует именно связи между компонентами, а не реализацию конкретного компонента.

                простой набор правил просто не получается простым

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


                1. rukhi7 Автор
                  03.10.2024 03:52

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

                  да, о разделении на уровни я просто не подумал, с учетом разделения все понятно.

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

                  Я видел API даже написанным в JSON-e, на первый взгляд решение не выглядело адекватным, но у меня не было задачи глубоко вникать почему сделано именно так и можно ли по другому. Судя по тому что я видел раньше, мне кажется что можно, но вполне допускаю что просто кажется.


                1. Raspy
                  03.10.2024 03:52

                  Вероятно вы не работали в крупном кровавом энтерпрайсе. Место где я сейчас работаю на позиции архитектора, состоит из примерно 2500 подсистем, каждая подсистема это может быть монолит, а может быть сотня микросервисов. И между ними есть взаимодействия. Всё это находится в сотне сетевых сегментах, десятке ЦОД. Как без архитектора что-то делать? Но, справедливости ради, архитектора вообще не лезут в код, основной уровень их работы это С2-С3 по С4 нотации. (есть ещё корпоративные архитектора, они смотрят на всю систему целиком) Мои обязанности это проектирование апи, сети, заказ железа, поддержка паттернов надёжности и куча других сопутствующих задач. И да, никакие интеграции между системами не стартуют до согласования архитектуры решения с аппрувами от всех архитекторов интегрируемых подсистем.

                  И да, содержать архитекторов это действительно дорого, поэтому мелкие и средние фирмы отдают это на откуп лидам/ТМ-ам.


        1. flancer
          03.10.2024 03:52
          +2

          Дело не в точке отказа, а в изоляции.

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


          1. powerman
            03.10.2024 03:52
            +3

            Это правда, но не вся. Микросервисный подход обладает рядом недостатков и рядом преимуществ. Просто в одной ситуации (определяемой компанией/проектом/командой) одни преимущества будут важны, а другие нет, а в другой ситуации будет иначе. Иногда важно именно иметь возможность раздельного деплоя части функционала проекта - ради производительности и/или надёжности. Иногда важно иметь возможность писать разные части функционала на разных языках программирования. Но чаще всего, действительно, основная польза от микросервисного подхода это надёжная изоляция частей проекта друг от друга.

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


            1. rukhi7 Автор
              03.10.2024 03:52

              эффект от процессов (ревью, тесты, вышеупомянутая изоляция которую сложно нарушать, etc.) становится намного сильнее эффекта от квалификации.

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


  1. jmnemonik
    03.10.2024 03:52

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


  1. qrKot
    03.10.2024 03:52

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

    Очаровательно, но совершеннейшим образом оторвано от реальности.

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

    Без учета этих факторов даже и рассуждать о микросервисной архитектуре смысла нет.

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

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

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

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


    1. rukhi7 Автор
      03.10.2024 03:52

      Итого, как выглядит ваш изумительный монолит:

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