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

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

Достаточно долго обслуживание инфраструктуры оставалось трудоемкой и достаточно специализированной задачей. Только умельцы-админы могли развернуть в инфраструктуре какой-нибудь кэш или очередь. О том, чтобы у каждой части приложения была собственная инфраструктура, и речи не шло – кто же весь этот зоопарк будет обслуживать?!

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

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

Казалось бы, что здесь может пойти не так?


Увы, разделение приложение на части – не бесплатно. Прежде всего, возрастает стоимость поддержки API внутри инфраструктуры.

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

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

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

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


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

Второй. Как часто будет меняться API между компонентами? Если история git покажет, что API будет меняться каждый день, стоимость его поддержки, вероятно, окажется запредельной. Это может убить производительность разработки.

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

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


  1. maxzh83
    24.07.2018 14:09
    +5

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

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


    1. fzn7
      24.07.2018 14:24
      +2

      В пору ставить нулевым


    1. Demetrikl
      24.07.2018 14:24
      +1

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


      1. VolCh
        24.07.2018 17:54

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


  1. Mishiko
    24.07.2018 16:02

    Про сериализацию и трафик надо бы поподробней — одно дело когда мы получаем ссылку на объект в JVM, другое дело когда речь идет о сериализации данных в XML/JSON и передачу их по сети через HTTP. Кто нибудь вообще считал какой тут оверхед?


    1. rzerda
      24.07.2018 18:55

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

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


      1. Mishiko
        24.07.2018 19:20

        Парень моей подруги

        — смешно


        1. riky
          25.07.2018 02:56

          да, жаль что «муж моей жены» уже не так звучит.


          1. rzerda
            25.07.2018 04:35

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


            1. VolCh
              25.07.2018 14:44

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


  1. APXEOLOG
    24.07.2018 18:47

    метросервисы

    Это что такое? Сервисы метро?