Преамбула


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

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

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

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

Введение: Как конвенции и фреймворки улучшают запутанный код


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

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

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

Начинает появляться опасность запутанного кода – файл X обращается файлу Y, Y зависит частично от файла Z, файл Z импортирует несколько функций из файлов А и Б. Приходит младший разработчик, изменяет один файл и ломается всё приложение, а вы должны исправить ошибку, прежде чем боссу позвонит первый разгневанный клиент.

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

Хотите добавить ресурс? Измените файл маршрутов!
Хотите добавить дополнительную логику, которая запускается после сохранения записи? Подпишитесь на событие!
Хотите добавить дополнительные условия для запросов в базу данных? Создайте класс поведения таблицы!
И так далее.

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

Посмотрим на структуру пустого приложения на Ruby on Rails:

./app/assets
./app/assets/config
./app/assets/images
./app/assets/javascripts
./app/assets/javascripts/channels
./app/assets/stylesheets
./app/channels/application_cable
./app/controllers
./app/controllers/concerns
./app/helpers
./app/jobs
./app/mailers
./app/models
./app/models/concerns
./app/views/layouts
./bin
./config
./config/environments
./config/initializers
./config/locales
./db
./lib
./lib/assets
./lib/tasks
./log
./public
./test
./test/controllers
./test/fixtures
./test/fixtures/files
./test/helpers
./test/integration
./test/mailers
./test/models
./tmp
./vendor
./vendor/assets
./vendor/assets/javascripts
./vendor/assets/stylesheets

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

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

Монолиты и микросервисы: Влияние на спагетти-код


Вот что делают микросервисы со спагетти:

image

Ой, не та картинка. Вот так примерно выглядит спагетти-код в случае монолитного приложения:

image

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

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


image

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

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

В среде микросервисов плохой код изолирован.

Микросервисы: Успокой своего внутреннего перфекциониста


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

Теперь вы можете позволить себе «халяву» – можно сделать несколько ошибок, несколько неоптимальных реализаций, а ваше приложение всё еще достаточно легко читать и править, потому что ваш LoC (Lines of code) упал с нескольких тысяч до жалких десятков или сотен!
Процесс разработки ускорится, потому что вы меньше обеспокоены строгими правилами и мириадой зависимостей!

Вывод


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

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


  1. lubezniy
    27.12.2016 08:18

    Интересно, как работают микросервисные проекты в условиях high load? Сколько дополнительных вычислительных ресурсов уходит на связи между ними?


    1. dusterio
      27.12.2016 09:34

      Микросервисы особенно эффективны в условиях high load — поэтому на них и перешли сайты с высокой нагрузкой вроде Netflix и Amazon. Расход на RESTful или очереди ничтожен, зато масштабировать конкретный сервис (который создает нагрузку) намного эффективнее, чем масштабировать весь монолит (включая ненужные части)

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


  1. amaksr
    27.12.2016 09:20
    +2

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


    1. dusterio
      27.12.2016 09:36

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


      1. yvm
        28.12.2016 12:16

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


        1. Toshiro
          28.12.2016 12:35

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


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


          1. dusterio
            28.12.2016 14:17

            У каждого микросервиса должно быть отдельное хранилище, это как раз одно из преимуществ архитектуры (можно под конкретные данные выбрать конкретный вид sql/nosql базы)


            1. Toshiro
              28.12.2016 14:26
              +1

              Должно быть != Единственно верный способ.

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

              Я к тому, что слишком много пошло статей, постулирующих что-то как панацею. А не как один инструмент из многих.

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


              1. dusterio
                28.12.2016 15:53

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

                Весь startup-мир глумится над PHP, jQuery и MySQL, а один из самых успешных проектов десятилетия Slack сделан на них :)

                PS. Сложно себе представляю реализацию большого проекта на jQuery, но факт есть факт


              1. yvm
                29.12.2016 16:53

                Таки единственно верный способ.


                1. Toshiro
                  29.12.2016 19:25

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


            1. VolCh
              28.12.2016 15:43

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

              У нас сейчас несколько микросервисов используют одну общую базу (но записи из неё маппятся по разному и по набору полей, и по иерархии объектов), несколько свою собственную, а у одного — три базы. Это не считая чего-то типа ДВХ, которые собирает данные из всех имеющихся баз в одну для аналитики.


              1. dusterio
                28.12.2016 15:56

                А если один микросервис решил мигрировать схему БД немного? Если вам из-за этого придется что-то менять в остальных – это, вроде как, нарушает всю идею и лишает плюсов


                1. Toshiro
                  28.12.2016 16:11

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

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

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


                  1. dusterio
                    28.12.2016 16:18

                    1) Если речь идет о новой реализации существующего функционала, то конечно!
                    2) Возможность постепенного перехода является одним из плюсов этой идеи :)
                    3) Судя по комментариям, очень многие несогласны, что сама идея микросервисов хорошая. Не рано ли им предлагать переход? :) Создается впечатление, что людям пока надо слышать доводы в пользу. Даже если взять глобальную сцену IT, крупных проектов, которые приняли парадигму – намного менее половины (если судить по публичным источникам)


                    1. Toshiro
                      28.12.2016 17:12
                      +2

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

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

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

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

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

                      Нужны статьи не «Как я полюбил микросервисы, потому что {{ reason }}», а >>> «Разрываем сансару рефакторинга, выделяя в микросервис модуль, который вы итак переписываете на 50%-80% каждую неделю» или «Как разделить ваш центр управления колонизацией марса на микросервисы, и начать спать».


                      1. dusterio
                        29.12.2016 03:43

                        Целиком с Вами согласен, и учту замечания при написании второй части!

                        Привести практические примеры, в принципе, не проблема. Просто не подумал! :)


                1. VolCh
                  28.12.2016 18:38
                  +1

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


                  1. Toshiro
                    29.12.2016 11:11

                    В третьих, никто не отменял уровни абстракции: метабаза в несколько слоев, если потребуется, и вьюхи. Все зависит от конкретных обстоятельств.


  1. Suvitruf
    27.12.2016 11:44
    +10

    Почти каждая статья про микросервисы заканчивается:

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

    Вот только почему-то авторы в расчёт не берут время/ресурсы потраченные на создание всех этих маршрутов, связей между сервисами. Что это будет? Просто http запросы? Синхрониться через базу? А может брокер типо RabbitMQ?
    А как они искать друг друга будут? Какая-то сервис дискавери тулза? Как по мне, правильно построить архитектуру на микросервисах не так-то просто. И если у вас были проблемы с монолитом (почему всегда сравнивают с ним?!), то просто используя микросервисы вы от спагетти кода не уйдёте, так как проблема в головах.


    1. dusterio
      27.12.2016 11:53
      -1

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

      Даже если код одинаково плохим остается — когда он порезан на куски, с ним легче справляться и его проще рефакторить

      А временные затраты на общение сервисов не такое большое — все библиотеки и провайдеры предоставляют SDK. Во многих фреймворках с ходу включены клиенты вроде AWS SQS или IronMQ


      1. Suvitruf
        27.12.2016 12:38
        +7

        Ну, взять вот даже эту картинку — одна какашка и 5 какашек. Что легче зарефакторить? Что будет меньше потенциальных сбоев во время рефакторинга давать? (деплои 1/5 системы или каждый раз деплой всей системы)
        Потенциальных сбоев в микросервисах куда больше становится. Если взять приведённый вами монолит, то там проблема будет в каком-то модуле (мы же пишем модульно, да?). В микросервисах может фаервол затупить, сервис дискавери тулза откажет, подвиснут соединения не пойми почему. То есть, тут ОГРОМНАЯ проблема помимо кодинга ещё и в плане администрирования всего этого.

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

        А временные затраты на общение сервисов не такое большое — все библиотеки и провайдеры предоставляют SDK. Во многих фреймворках с ходу включены клиенты вроде AWS SQS или IronMQ
        Я вот смотрю пинги между нашими сервами в приватной сети. Он может до 1мс доходить. В случае с http — там ещё куча мусорных хедеров будет.
        В случае с RabbitMQ каким-нить, вам нужен будет кластер (нам же нужна надёжная система). Вот только, что вы будете делать при большой нагрузке, когда кластер откажет? Пойдёте пробовать кафку? Хорошо, если у вас есть тот, кто имеет опыт с такими монстрами, а если нет?


        1. dusterio
          28.12.2016 12:23
          -2

          — 1мс — это очень даже низкая задержка, учитывай что голое приложение с микро-фреймворком может 20+ мс занимать. В целом в мире ответ API в 100-150мс считается ризонно быстрым

          — Можно полностью положится на облачных провайдеров, очереди и сообщения обычно стоят очень недорого.


        1. aso
          28.12.2016 13:18
          +1

          Потенциальных сбоев в микросервисах куда больше становится. Если взять приведённый вами монолит, то там проблема будет в каком-то модуле (мы же пишем модульно, да?).


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


        1. AlexanderG
          29.12.2016 13:32

          То есть, тут ОГРОМНАЯ проблема помимо кодинга ещё и в плане администрирования всего этого.

          Девопсы тоже хотят кушать :)


  1. lair
    27.12.2016 12:14
    +9

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

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


    1. dusterio
      27.12.2016 12:16

      1) Развертывание один раз настраивается и редко меняется, обычно. Зато развертывание изолированное — по частям, что безопаснее (вся система не рухнет из-за одного элемента)
      2) Время ops зачастую дешевле времени разработчиков стоит, да и ops обычно меньше в штате :)
      3) А какие сложности с управлением версиями?


      1. lair
        27.12.2016 12:21
        +7

        Развертывание один раз настраивается и редко меняется, обычно.

        "Обычно". То-то я регулярно что-нибудь перенастраиваю и переразворачиваю.


        Зато развертывание изолированное — по частям, что безопаснее (вся система не рухнет из-за одного элемента)

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


        Время ops зачастую дешевле времени разработчиков стоит, да и ops обычно меньше в штате

        Это пока ops не начинают будить разработчиков вопросами "тут твоя [...] упала, что делать-то?"


        А какие сложности с управлением версиями?

        Ну как же, есть у вас микросервис D, от которого зависят микросервисы A и B. Вы разрабатываете микросервис A, и вас не устраивает функциональность D. Вы ее дописываете. Разворачиваете D — и внезапно, B падает, потому что вы чего-то не учли.


        (вот вам и "безопасное изолированное развертывание": развернули один компонент — уронили все его зависимости)


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


        1. tangro
          28.12.2016 11:42
          +1

          То-то я регулярно что-нибудь перенастраиваю и переразворачиваю.

          Это называется «работа». За неё опсам платят деньги.

          Это пока ops не начинают будить разработчиков вопросами «тут твоя [...] упала, что делать-то?»

          О, видите, даже в этой истории у разработчика всё-таки было время поспать. Что делать? Глупый вопрос — читать логи, конечно.

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


          1. dusterio
            28.12.2016 12:07

            Ура, первый сторонник микросервисов в комментариях :))


            1. unet900
              28.12.2016 13:07

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

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

              Вот если нужно что-то сбоку к большому приложению прикрутить ИМХО микросервисы тут отличный выход.

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


              1. dusterio
                29.12.2016 03:42

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

                Самим командам работать станет проще — с их точки зрения достаточно написать небольшое приложение, удовлетворяющее спецификациям API.

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

                Можно написать фронт-енд на jQuery в 1000 строк, можно на Angular в 50. Второе эффективнее и проще обновляется в будущем, но требует изучения фреймворка, понимания хороших практик программирования.


                1. VolCh
                  29.12.2016 10:43

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


                  1. dusterio
                    29.12.2016 12:42

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


                    1. VolCh
                      29.12.2016 13:11

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


                1. lair
                  05.01.2017 00:36

                  Самим командам работать станет проще — с их точки зрения достаточно написать небольшое приложение, удовлетворяющее спецификациям API.

                  Ага, это если спецификации есть и не меняются. А они всегда меняются, и дальше начинается цирк с версионированием.


                  1. VolCh
                    05.01.2017 14:23

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


                    1. Borz
                      05.01.2017 23:23

                      проще не значит лучше.


                      И да, смена API без смены версии — зло.


          1. lair
            05.01.2017 00:35

            Это называется «работа». За неё опсам платят деньги.

            Разработчикам тоже за работу платят деньги. Внезапно.


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

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


            Дело же не в том, что микросервисы плохи, дело в том, что они не бесплатны.


  1. maxru
    27.12.2016 13:37

    Как обычно, просто оставлю это здесь. Читайте оригинал.
    http://microservices.io/patterns/index.html


    1. dusterio
      27.12.2016 14:17

      Лучше тогда давать ссылку на бесплатный ebook от nginx :) Там намного больше информации


      1. martin_wanderer
        28.12.2016 12:13

        Ну так и дали бы. А то получается как в том анекдоте про… :)


        1. dusterio
          28.12.2016 12:23

          Книга на английском. Судя по количеству переводов на Хабре в последнее время — далеко не все могут читать на английском


          1. martin_wanderer
            28.12.2016 12:36
            +1

            Эта книга? А насчет переводов: умение читать на языке и умение переводить — две большие разницы. Чтобы текст понять, его не нужно и даже вредно переводить. А для перевода требуется еще и родным языком владеть на уровне несколько выше среднего.


            1. grossws
              28.12.2016 13:33
              +2

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

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


  1. Demtriy
    27.12.2016 14:36

    В заголовке статьи и в тегах ни слова не говорится о том, что речь идет о сервер-сайд разработке. Как применить этот подход в рамках клиентских приложний, положим, для .Net Core (через pipe-WCF) я представляю. Но вот как делать это для мобильных приложений на Obj-C / Swift — ума не приложу. Посыл — делить все на Фреймворки и библиотеки — вряд ли можно назвать сколько бы то ни было ООП подходом. Да, можно использовать глобальные оповещения, но это треш еще больший чем «монолитная» но сбалансированная архитектура.


    1. dusterio
      27.12.2016 16:05

      Вы правы — я об этом даже не подумал. Среди тегов не было ничего более подходящего

      Конечно, это относится как правило в коллекции back-end сервисов


  1. http3
    27.12.2016 16:05

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

    1. Следование модным идеям — разве залог успеха? :)
    От этих модных идей программа распухнет со 100 строк до 200. :)
    2. Я хз, но читать и разбираться в 100 строках говнокода — это разбираться в говнокоде.

    Вероятно, вы начинаете делить исходные файлы на модели, контроллеры и так далее.

    и ранее
    А когда файлов стало много, вы начинаете организовывать их в папки.

    То есть сначала файлы группировали от балды по папкам? :)

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

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


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

    А перед этим в монолите они без надобности вызывали что-то? :)

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

    Шта?
    У меня 200 классов.
    199 классов и 1 микросервис вряд ли чем-то помогут.
    Ну и 200 микросервисов — вряд ли что-то хорошее. :)


    1. dusterio
      27.12.2016 16:08

      У Netflix 600+ микросервисов — это ок.
      Если у вас миллион пользователей, то перевести 200 классов в 200 сервисов — может быть вполне разумной идеей.

      До перехода, в независимости от нагрузки, каждому классу «нужны» будут остальные 199 — остальные 199 деплоятся вместе и находятся в ОЗУ вместе. После перехода на микросервисы, у 2 классов может быть по 100 «инстансов», а у остальных 198 всего по одному (потому что они проще).


    1. Suvitruf
      27.12.2016 17:16
      +1

      Вообще забавно, да. Я про «Так как отдельно взятый микросервис – это не более, чем класс или два». Это если не считать всех зависимостей. В итоге получается 1 свой класс и сотни, если не тысячи классов из зависимостей.


  1. VolCh
    27.12.2016 20:55

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

    Класс или два обычно нет смысла выделять в микросервис, если этого не требуют админы/пользователи. «Микро» в «микросервис» значит, имхо, не мало кода в сервисе, а мало ответственностей перед клиентом у сервиса, тот же SRP из SOLID, вынесенный на уровень приложения (как относительно независимой программы). А проще говоря unix-way.
    то теперь у вас меньше, значительно меньше файлов в рамках одного открытого приложения в IDE.

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

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

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


  1. Deosis
    28.12.2016 11:33

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


  1. romanitalian_net
    28.12.2016 12:04

    Наверняка я плохо знаком с Микросервисной архитектурой.

    Но через что будет проходить связь микросервисов — по tcp/ip стеку (http запросы)?

    И как при этом организовывать протоколы передачи данных между мСервисами?
    Как между ними согласовывать работу (какой-то диспетчер)?
    Какие параметры передавать и по какому адресу?


    1. dusterio
      28.12.2016 12:06

      1) Самые распространенные способы — это http (REST) или очереди/сообщения (tcp/udp/web)
      2) Как правило создается некий реестр сервисов по типу, из которого можно всегда адрес живого инстанса (экземпляра) сервиса взять. Популярное бесплатное ПО — consul.

      В Docker Cloud создается внутренняя сеть автоматически между всеми сервисами, достаточно друг друга по хостнейму стучать.

      В AWS можно на мониторинг и Route53 достаточно просто привязать


    1. VolCh
      28.12.2016 14:16

      В общем случае ip/tcp/udp, часто http поверх ip/tcp.

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

      Адреса определяются какими-то service discovery или просто хардкодятся в конфигах клиентов DNS-имена, а на DNS прописываются серверы.


  1. heleo
    28.12.2016 12:52

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


    1. dusterio
      28.12.2016 13:09

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


      1. heleo
        29.12.2016 00:29

        Я скорее со стороны уровней абстракции от живого кода смотрю) Да, по OSI оно низковато, но если сравнивать с модулями на подобие COM, вполне себе высоко.


    1. VolCh
      28.12.2016 14:18

      Как по мне, главное в том, что монолит в общем случае — одна программа, модули которых общаются с собой в рамках одного процесса,, а микросервис — множество изолированных, общающихся между собой средствами IPC, включая RPC.


      1. heleo
        29.12.2016 00:42

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


  1. donRumatta
    28.12.2016 19:29

    Вопрос по микросервисам: как шарится общий код, например, всякие утилиты, хелперы, экстешны, которые требуются везде и всюду? Дублируется во всех подсистемах?

    А контракты, через которые происходит общение между сервисами, например, те же классы-сообщения, ходящие в RabbitMQ?


    1. vearutop
      29.12.2016 00:03

      По опыту живого проекта, общий код выделяется в библиотеки которые потом доставляются менеджером зависимостей (например composer для php, или glide для golang). Зависимости актуализируются согласно семантическому версированию.


      Что касается контрактов, для REST есть спецификация описания интерфейсов swagger, из неё можно сгенерировать клиентскую библиотеку (методы и структуры) и внедрить её как зависимость.


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


    1. dusterio
      29.12.2016 03:28
      +1

      Да, дублируются. 10-15 лет назад это бы считалось минусом, а сегодня с текущими ценами на пространство и хостинг — всем уже без разницы. Поднимите пустой проект на React — у вас зависимостей на 500-700 мегабайт скачается (это не комплимент обществу Node :). Один дополнительный хелпер или утилита не сделают погоды вообще :)

      У меня каждый микросервис экспортирует документацию в формате Swagger (как и у vearutop), а данные которые полезны более, чем одному сервису транслируются в топиках SNS в формате JSON. Нет никакой сериализации объектов, так как используются разные языки и фреймворки.

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


    1. VolCh
      29.12.2016 10:55

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

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


  1. vearutop
    29.12.2016 00:23
    +1

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


    1. vearutop
      29.12.2016 00:29

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


      1. dusterio
        29.12.2016 03:34

        Для этого есть стандартные решения, но это, безусловно, усложнение

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

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


    1. dusterio
      29.12.2016 03:21
      +1

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

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


  1. ImLiar
    29.12.2016 00:29

    Ой, камон.

    Основная суть микросервисов — это масштабирование на бизнес-уровне.
    Пусть в компании X определена общая политика — все микросервисы должны предоставлять REST API. Вот книжка с good practice, следуйте.

    Теперь каждая команда обозначает API через какой-нибудь swagger/graphql/whatever и имплементирует уже как хочет. Полная независимость разработки между командами, никаких баундов. Технологии и языки вольна выбирать команда, ответственность за продукт end to end, бизнес-домен как зона ответственности команды и продукта.

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

    Теперь повторите такой же трюк с монолитом на масштабах больше 1к разработчиков. Чтоб гибко и независимо. Вот почему это работает для таких гигантов как Netflix или Spotify

    Для команд по 5-6 человек на всю компанию вы на нормальный девопс убьете не меньше ресурсов, чем на, собственно, разработку микрух. Это из собственного опыта.
    Хотя сейчас kubernetes + AWS сервисы и облегают задачу с service discovery, failover и т.п., но мороки все равно хватает.


    1. dusterio
      29.12.2016 03:18

      Вы привели пример еще одного объективного преимущества :)

      Я пользуюсь Docker Cloud, он очень много сам за меня делает «behind the scenes». Но мне немного повезло — я сетевой инженер в прошлом, поэтому нам не пришлось нанимать devops вообще.


      1. ImLiar
        29.12.2016 11:46

        Преимущество только для кейса «много разработчиков @ много команд». На малых масштабах летит так себе


        1. VolCh
          29.12.2016 12:16

          Есть и преимущества в случае даже «один разработчик». Как минимум, деплой новой фичи/багфикса в рамках одного компонента в случае SOA/микросервисов часто приводит к даунтайму только функциональности, связанной с этим компонентом, а монолита — всего, причём значительно большей. Есть, конечно, практики нулевого даунтайма и для монолитов, но, как правило, они требуют ещё больших ухищрений и от девопсов, и от разработчиков.


          1. ImLiar
            29.12.2016 13:27

            Какие ухищрения? Round-robin на фронте?

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

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


            1. VolCh
              29.12.2016 13:48

              Как поможет Round-robin на фронте, когда идёт часовая миграция схемы БД?


              1. ImLiar
                29.12.2016 18:39

                Так а как тут поможет монолит или микруха, если БД под завязку?
                Стейтлесс приложения обновляются один за другим без особых проблем. С тяжелыми базами будут проблемы вне зависимости от архитектуры системы.


                1. VolCh
                  29.12.2016 18:50

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


                  1. ImLiar
                    29.12.2016 22:10

                    И что? Вот у меня огромное хранилище у микрухи с заказами, миграция занимает часы. Что изменилось?


                    1. VolCh
                      02.01.2017 16:52

                      Мигрируют только заказы, остальные микросервисы работают штатно.


        1. dusterio
          29.12.2016 12:41

          Крупный проект == много разработчиков. Как сказано в статье, в маленьких проектах вообще не сильно важны технические исщихрения :)


          1. VolCh
            29.12.2016 13:13

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


  1. AndreyRubankov
    03.01.2017 13:02

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

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

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

    ps: Судя по прикрепленным изображениям Вы заменили спагетти-код на спагетти-микросервисы.


    1. dusterio
      03.01.2017 14:32

      Я нигде не писал, что микросервисы – это про чистоту кода ;-) Мой тезис, что цена плохого кода в микросервисах ниже. Причины Вы сами частично назвали только что.

      Про спагетти, вероятно, неудачные картинки. В Интернете ходит популярная картинка, где микросервисы с равиоли сравнивают (спагетти — плохой код 90-ых, лазанья — слои в MVC/монолитах, равиоли — микросервисы)


      1. AndreyRubankov
        03.01.2017 15:05

        Я нигде не писал, что микросервисы – это про чистоту кода ;-)

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