Микросервисная архитектура на современном стеке Java-технологий
| Тип технологии | Название | Версия |
|---|---|---|
| Платформа | JDK | 11.0.1 |
| Язык программирования | Kotlin | 1.3.10 |
| Фреймворк приложения | Spring Framework | 5.0.9 |
| Spring Boot | 2.0.5 | |
| Система сборки | Gradle | 5.0 |
| Gradle Kotlin DSL | 1.0.4 | |
| Фреймворк для unit-тестирования | JUnit | 5.1.1 |
| Spring Cloud | ||
| Единая точка доступа (API gateway) | Spring Cloud Gateway | Входит в Release train Finchley SR2 проекта Spring Cloud |
| Централизованное конфигурирование (Centralized configuration) | Spring Cloud Config | |
| Трассировка запросов (Distributed tracing) | Spring Cloud Sleuth | |
| Декларативный HTTP клиент (Declarative HTTP client) | Spring Cloud OpenFeign | |
| Обнаружение сервисов (Service discovery) | Spring Cloud Netflix Eureka | |
| Предохранитель (Circuit breaker) | Spring Cloud Netflix Hystrix | |
| Клиентская балансировка нагрузки (Client-side load balancing) | Spring Cloud Netflix Ribbon | |
Проект состоит из 5-и микросервисов: 3-х инфраструктурных (Config server, Service discovery server, UI gateway) и примеров front-end’а (Items UI) и back-end’а (Items service):
Все они будут последовательно рассмотрены далее. В «боевом» проекте, очевидно, будет значительно больше микросервисов, реализующих какую-либо бизнес-функциональность. Их добавление в подобную архитектуру технически выполняется аналогично Items UI и Items service.
Disclaimer
В статье не рассматриваются инструменты для контейнеризации и оркестрации, т. к. в настоящее время они не используются в проекте.
Config server
Для создания централизованного хранилища конфигураций приложений был использован Spring Cloud Config. Конфиги могут быть прочитаны из различных источников, например, отдельного git-репозитория; в этом проекте для простоты и наглядности они находятся в ресурсах приложения:
При этом конфиг самого Config server ( application.yml ) выглядит так:
Программный код этого микросервиса состоит из всего лишь одного файла, в котором находятся объявление класса приложения и main-метод, являющийся, в отличие от эквивалентного кода на Java, функцией верхнего уровня:
Классы приложения и main-методы в остальных микросервисах имеют аналогичный вид.
Service discovery server
Service discovery — это паттерн микросервисной архитектуры, позволяющий упростить взаимодействие между приложениями в условиях возможного изменения числа их инстансов и сетевого расположения. Ключевым компонентом при таком подходе является Service registry — база данных микросервисов, их инстансов и сетевых расположений (подробнее здесь).
В этом проекте Service discovery реализован на основе Netflix Eureka, представляющего собой Client-side service discovery: Eureka server выполняет функцию Service registry, а Eureka client перед выполнением запроса к какому-либо микросервису обращается к Eureka server за списком инстансов вызываемого приложения и самостоятельно осуществляет балансировку нагрузки (используя Netflix Ribbon). Netflix Eureka, как и некоторые другие компоненты стека Netflix OSS (например, Hystrix и Ribbon) интегрируется с Spring Boot приложениями с помощью Spring Cloud Netflix.
В конфиге Service discovery server, находящемся в его ресурсах ( bootstrap.yml ), указывается только название приложения и параметр, определяющий, что запуск микросервиса будет прерван, если невозможно подключиться к Config server:
Оставшаяся часть конфига приложения располагается в файле eureka-server.yml в ресурсах Config server:
Eureka server использует порт 8761, что позволяет всем Eureka client’ам не указывать его, используя значение по умолчанию. Значение параметра register-with-eureka (указано для наглядности, т. к. оно же используется по умолчанию) говорит о том, что само приложение, как и другие микросервисы, будет зарегистрировано в Eureka server. Параметр fetch-registry определяет, будет ли Eureka client получать данные из Service registry.
Список зарегистрированных приложений и другая информация доступны по http://localhost:8761/ :
Альтернативными вариантами для реализации Service discovery являются Consul, Zookeeper и другие.
Items service
Это приложение представляет собой пример back-end с REST API, реализованным с использованием появившегося в Spring 5 фреймворка WebFlux (документация здесь), а точнее Kotlin DSL для него:
Рассмотрим один из способов отправки дополнительных метаданных на Eureka server:
Убедимся в получении Eureka server этих данных, зайдя на http://localhost:8761/eureka/apps/items-service через Postman:
Items UI
Этот микросервис, помимо того, что демонстрирует взаимодействие с UI gateway (будет показано в следующем разделе), выполняет функцию front-end для Items service, с REST API которого может взаимодействовать несколькими способами:
И используется таким образом:
И используется таким образом:
В том, что все три способа возвращают одинаковый результат, можно убедиться, зайдя на http://localhost:8081/example :
Я предпочитаю вариант с использованием OpenFeign, т. к. он даёт возможность разработать контракт на взаимодействие с вызываемым микросервисом, обязанности по имплементации которого берёт на себя Spring. Объект, реализующий этот контракт, инжектируется и используется, как обычный бин:
Для работы Feign-клиента требуется аннотировать класс приложения @EnableFeignClients :
Для работы Hystrix fallback в Feign-клиенте в конфиг приложения нужно внести:
UI gateway
Паттерн API gateway позволяет создать единую точку входа для API, предоставляемого другими микросервисами (подробнее здесь). Приложение, реализующее этот паттерн, осуществляет маршрутизацию (роутинг) запросов к микросервисам, а также может выполнять дополнительные функции, например, аутентификацию.
В этом проекте для большей наглядности реализован UI gateway, то есть единая точка входа для различных UI; очевидно, что API gateway реализуется аналогично. Микросервис реализован на основе фреймворка Spring Cloud Gateway. Альтернативным вариантом является Netflix Zuul, входящий в Netflix OSS и интегрированный с Spring Boot с помощью Spring Cloud Netflix.
UI gateway работает на 443 порту, используя сгенерированный SSL-сертификат (находится в проекте). SSL и HTTPS сконфигурированы следующим образом:
Логины и пароли пользователей хранятся в Map-based имплементации специфичного для WebFlux интерфейса ReactiveUserDetailsService :
Параметры безопасности настроены таким образом:
Эта страница использует средства фреймворка Bootstrap, подключаемого к проекту с помощью Webjars, который даёт возможность управлять client-side библиотеками как обычными зависимостями. Для формирования HTML-страниц используется Thymeleaf. Доступ к странице логина конфигурируется с помощью WebFlux:
Маршрутизация средствами Spring Cloud Gateway может быть настроена в YAML- или java-конфиге. Роуты к микросервисам либо прописываются вручную, либо создаются автоматически на основе данных, полученных из Service registry. При достаточно большом количестве UI, к которым требуется осуществлять маршрутизацию, удобнее будет воспользоваться интеграцией с Service registry:
Значение параметра include-expression указывает, что роуты будут созданы только для микросервисов, названия которых оканчиваются на -UI, а значение параметра url-expression — что они доступны по HTTP протоколу, в отличие от самого UI gateway, работающего по HTTPS, и при обращении к ним будет использоваться клиентская балансировка нагрузки (реализуемая с помощью Netflix Ribbon).
Рассмотрим пример создания роутов в java-конфиге вручную (без интеграции с Service registry):
Первый роут осуществляет маршрутизацию на ранее показанную домашнюю страницу Eureka server ( http://localhost:8761 ), второй нужен для загрузки ресурсов этой страницы.
В нижележащих микросервисах может возникнуть необходимость получить доступ к логину и/или ролям пользователя, прошедшего аутентификацию в UI gateway. Для этого я создал фильтр, добавляющий в запрос соответствующие заголовки:
Spring Cloud Sleuth — это решение для трассировки запросов в распределённой системе. В заголовки запроса, проходящего через несколько микросервисов, добавляются Trace Id (сквозной идентификатор) и Span Id (идентификатор unit of work) (для более лёгкого восприятия я упростил схему; здесь более детальное объяснение):
Указав соответствующие настройки логирования, в консоли соответствующих микросервисов можно будет увидеть примерно следующее (после названия микросервиса выводятся Trace Id и Span Id):
Для графического представления распределённой трассировки можно воспользоваться, например, Zipkin, который будет выполнять функцию сервера, агрегирующего информацию о HTTP-запросах из других микросервисов (подробнее здесь).
Сборка
Учитывая возможность использования Gradle wrapper, нет необходимости в наличии установленного локально Gradle.
Сборка и последующий запуск успешно проходят на JDK 11.0.1. До этого проект работал на JDK 10, поэтому допускаю, что на этой версии проблем со сборкой и запуском не возникнет. По поводу более ранних версий JDK данных у меня нет. Кроме того, нужно учитывать, что используемый Gradle 5 требует как минимум JDK 8.
Запуск
Рекомендую стартовать приложения в порядке их описания в этой статье. Если вы используете Intellij IDEA с включённым Run Dashboard, то должно получиться примерно следующее:
Заключение
В статье был рассмотрен пример микросервисной архитектуры на актуальном в Java-мире стеке технологий, её основные компоненты и некоторые фичи. Надеюсь, для кого-то материал окажется полезным. Благодарю за внимание!
Веб-платформа на Java за 30 минут
Опытные разработчики могут не читать дальше, так-как эта статья рассчитана скорее на новичков, но всё-же я был бы очень рад, если бы кто-нибудь оставил конструктивную критику в мой адрес или указал на ошибки.
В этой статье я бы хотел рассказать начинающим разработчикам, как можно с минимальными усилиями создать свою веб-платформу начального уровня.
В статье я расскажу, как практически с нуля можно, даже не владея огромным стеком технологий, развернуть на удаленном облаке свой собственный уютненький ресурс. Это может быть ваш личный блог, какой-то интересный сервис или просто ресурс о котором вы давно мечтаете. Что может быть приятнее, чем отправить другу ссылку на свой собственный ресурс и вместе обсудить какие-то интересные моменты или просто посмеяться.
Для предпринимателей или начинающих бизнесменов, или владельцев каких-либо площадок будет интересно узнать, что им в начале их бизнеса совсем не обязательно вкладывать большие деньги на «крутой» сайт, а достаточно воспользоваться открытыми библиотеками и единственное за что заплатить — это за то, чтобы взять в аренду виртуальный сервер.
В статье я покажу, как сделать простейший сайт, имеющий простую функциональность. Это скорее статья, посвященная именно тому, чтобы показать общую концепцию и помочь начинающим разработчикам сформировать понимание того, как именно создаются такие известные ресурсы, как Google, Facebook, Вконтакте.
Вы должны понимать, что все интернет-сервисы создаются по одному принципу, отличаются только детали и реализация каких-то уникальных и конкретных вещей, но суть остаётся единой.
Для тех, кто заинтересовался:
Подготовка
Установка того, что нам понадобиться:
Писать наш сервис мы будем на Java, как самом распространённом языке для веб-сервисов.
Проверьте, что на вашем компьютере установлена последняя версия Java, сейчас это 8 версия. Проверить это можно здесь проверить Java. В 97% случаях так оно и есть, но если это не так, то следуя инструкциями на этом сайте вы без труда исправите это, установив и настроив окружение.
Если же всё-таки это не удалось, сразу договоримся с вами так, первым делом вы пытаетесь решить проблему на этих сайтах:
Вообще, открою вам секрет, в программировании, когда у вас всё заработало с 1 раза — это означает только одно, что что-то не работает. Это неоспоримый факт. Куча ошибок, несовместимость версий, отсутствие в библиотеке классов и прочее — это нормальное явление.
Ваш покорный слуга сам просидел 3 недели с ошибкой, облазив такие закоулки интернета, что на какое-то время потерял связь с реальностью и пролежал несколько месяцев в психиатрической больнице, но не будем об этом… Это история для отдельной статьи.
Итак, Java стоит — всё хорошо.
Теперь нам нужен инструмент. Да, нам нужна идея. Качаем и ставим отсюда JetBrains.
Только учтите, что вам нужна именно Ultimate — версия. Простая версия не позволяет разрабатывать веб-приложения. Там есть бесплатный пробный период на 30 дней, думаю с этим не будет проблем.
Итак, среда разработки есть, Java есть.
Начнём
В своё время я перечитал кучу статей и прочего, и решил, что в этой статье я исключу по максимуму картинки и визуальную составляющую, обычно она только отвлекает, у меня может быть другая версия, другой порядок модулей и прочее.
Часто вижу вопросы от новичков про такие интересные вещи, как Spring и Hibernate (https://spring.io/, hibernate.org). В 96% случаях вам это пока что не надо, и без хорошей подготовки и хорошего скилла «solve problem» вы увязните там очень надолго и выбраться обратно будет очень тяжело.
Ваша альма-матер на первых порах — это 2 технологии:
«Application server». Что это такое? А вот, что Application server.
Концепция веб-ресурсов
Суть такая, сервер. Что такое сервер? Это программный код, который «зацикленно» крутиться в системе и слушает порты. Это тема отдельного разговора. Но в общем, рассмотрим 2 варианта того, что вообще сервер умеет делать, он умеет отдать данные (GET) — просто вернуть число, страницу, или ещё бог знает что. Но, есть ещё и POST — он тоже возвращает данные, но и принимает от клиента их перед этим.
Если ничего не понятно, читаем тут ru.wikipedia.org/wiki/REST.
Статья начинает слишком сильно расти. Теперь буду стараться писать более кратко.
Идём в мой репозиторий. Предполагаем, что человек совершенно не понимает, что такое система контроля версий, поэтому идём путём дилетанта, там есть кнопка («Download ZIP» — качаем и разархивируем).
В окне приветствия идеи есть кнопка «import project» — жмём. Выбираем скачанный и разархивированный проект.
Жмём далее, далее и далее, пока не откроется проект.
Первые сложности
Проект открыт, но вы не запустите сервер и не сможете открыть сайт. Почему? Потому что, идея не знает, что ей делать, она умна, но не настолько.
Объяснение того, как это сделать, заняло бы пару страниц и оказало бы вам «медвежью» услугу. Первые сложности — первые трудности. Это будет вашим «боевым крещением». Программировать — не пирожки печь. Ссылки сверху вам помогут. Потратить 1-2 часа на это — это нормально. Я знаю хороших и опытных программистов, которые сидели несколько дней, но так и не сумели правильно запустить сервер. Это не делает им чести — но факт — есть факт. Вперед. Запустите — возвращайтесь к чтению.
Не забудьте сообщить идее, что используем tomcat (как? ссылки вверху, по ним есть ответ).
Локальное тестирование сервиса
Получиться у вас должно примерно вот это:
Но есть проблема — не работает! Ну что же, этого следовало ожидать. У нас не создана таблица в базе данных. В проекте мы используем базу данных SQLite
Объяснить, что это такое будет с 0 не просто. Попробуйте почитать об этом на специализированных ресурсах.
Могу посоветовать хороший сервис: www.codecademy.com (там есть Java, SQL, Git, JavaScript и другие супер полезные вещи), поэтому милости прошу.
В итоге, нам нужно создать нашу таблицу, делаем это так:
Таблица создана. Можно проверить как работает наша система. Добавьте пару имён и посмотрите, как они будут вам возвращены уже из самой базы.
Разбор кода
Начнём смотреть, что же у нас в коде:
Так уж повелось, что в Java все конфигурации пишутся в xml-файлах, тут не исключение — файл web.xml контролирует, то, какой сервлет за что отвечает. Внимательно посмотрите на код и попробуйте поменять ссылку или имя сервлета.
Приложение у нас простое, поэтому у всего 2 класса (SQLiteClass и MainServlet).
Очевидно, думаю, что первый отвечает за работу с базой данных, а второй и есть наш пресловутый сервлет.
А вот и наши, упомянутые выше POST и GET запросы, эти функции являются обработчиками и задают поведение сервлета в ответ на запросы от клиента. Суть одна — данные пришли, данные ушли. Ничего сложного. Попробуйте поиграться с методами.
Переходим к классу, реализующему JDBC:
Здесь тоже всё просто, те же SQL запросы, только завёрнутые в Java-код. Небольшой совет — остерегайтесь всяких надстроек и фреймворков. Они хороши только в больших проектах, когда у вас миллионы записей, и сложные транзакционные операции. Но, настоящий контроль вы получите только, когда пишете именно вручную запрос, без таких вещей как сериализация жить намного проще (особенно поначалу).
Всё, с серверной частью закончим. Тут вам придётся посидеть, почитать специальные статьи и руководства. Без реальной практики тут никак.
Клиентская часть
Вот и пришло время взглянуть на то, что твориться у клиента в браузере. А ничего сверхъестественного. Но, скажу вам прямо, конечно всё зависит от проекта, но, клиентская часть обычно намного сложнее в реализации, чем серверная. И всё в основном из-за JavaScript-а. Очень быстро клиентский код превращается в набор «простыней», заплат, хардкода и прочих веселостей. JavaScript суров и беспощаден. На чистом нём писать очень тяжело. Поэтому мы используем JQuery. Есть куча других фреймворков и другого творения, но их касаться здесь не будем. Есть такая поговорка, что назови любое слово и это будет названием JS-фреймворка. Известен в узких кругах фреймфорк Mocha, я не представляю какие мысли посещали человека, когда он придумывал ему название, ну ладно, это было его право, конечно же.
Итак, что у нас там с клиентом?
Опять дам ссылку на отличнейший ресурс www.codecademy.com. Фронтенд там разобран очень хорошо и даёт необходимую базу для начинающих.
Тут рассмотрим только функцию
Что она делает? Правильно, шлёт тот самый POST — запрос и разбирает ответ. Всё просто, отдал данные и получил с сервера. По русски он говорит серверу «Дай мне имена всех, кто у тебя в базе» или «Занеси в базу это имя» и даёт ему имя.
Вот и вся клиентская часть.
Отправляем ресурс в настоящий мир
Как можно было заметить, наш сервис крутиться на локальном хосте. Другими словами на нашем же компьютере. Пришло время это исправить.
Тут я опишу лишь общий принцип сего действия. Это так или иначе потребует от вас денег на сервер, поэтому маловероятно, что кто-то действительно этим будет заниматься, особенно в самом начале своего программистского пути. Но понимать общую концепцию вы должны уже сейчас. Если кто решиться — знайте вы молодцы, вполне вероятно из вас может выйти толк.
И по традиции сразу несколько ссылок:
Читаем, что там написано, формируем в голове общую концепцию, того, как происходит взаимодействие программиста и удаленного сервера.
Сами сервера можно приобрести на amazone. Ссылку не даю, ибо реклама, можете сами поискать, это не сложно. Есть бесплатный тестовый период. НО! Будьте предельно осторожны, ваш покорный слуга сам слышал истории, как со счетов списывались тысячи долларов без ведома хозяина, ибо система сама умеет докупать себе мощности. Не попадитесь, я сам уже платил несколько раз за непонятные услуги, там всё на английском. Если не уверены, что делаете — лучше вообще не делайте.
Порядок действий таков:
На всякий случай я оставлю тут эти ссылки, вдруг, кто-то застопорился на каком-то моменте и решил спуститься в самый низ статьи, может помогут:
Заключение
Вот мы и добрались до кульминации нашего здесь обсуждения Джавы и веб-разработки на ней. Сложно? Да. Интересно? Да. Все, абсолютно все сервисы, будь то, поисковая система с миллиардами индексов, будь то видео-сервис с миллионами стрим-каналов — всё строиться по одному принципу. Отдать — забрать данные. Понимая эту концепцию вы сможете написать любую систему, сервис или платформу.
Я не стану лукавить и обманывать вас уважаемые читатели. Вряд ли вы за 2 или 3 недели станете супер профессионалами и будете свободно писать код. Этому можно научиться только потом и долгими ночами. Чем дальше вы будете залазить в дебри, тем больше вы будете понимать, что вы так мало знаете. Дорогу осилит идущий, вперед, дерзайте.
Вперед. Пришло время действовать. Стареющим Дурову и Брину пора уйти на покой, время их славы уже прошло, пришло время обновить учебники истории и списки Forbs. И кто знает, может эту статью читает тот, кто в своё время напишет отличнейшую платформу, которая затмит собой таких гигантов как Google, Facebook и других. Удачи, спасибо, что дочитали до конца.
Микросервисы на Java: практическое руководство
Вы можете использовать это руководство, чтобы понять что такое Java микросервисы, как вы будете их разрабатывать и создавать. А также получить обзор библиотек для разработки Java микросервисов.
7000 слов, вероятно, не стоит читать ее на мобильном устройстве. Добавьте ее в закладки и вернитесь позже.
Содержание
Основы Java микросервисов
Чтобы получить реальное представление о микросервисах Java, имеет смысл начать с самых основ: печально известного монолита на Java, что это такое и каковы его преимущества или недостатки.
Что такое монолит Java?
Представьте, что вы работаете на банк или финтех-стартап. Вы предоставляете пользователям мобильное приложение, которое они могут использовать для открытия нового банковского счета.
Для этого коде на Java требуется класс контроллера, который, упрощенно, выглядит примерно так, как показано ниже.
В чем проблема с Java монолитами?
По своей сути, в монолите Java нет ничего плохого. Просто опыт проекта показал, что если у вас:
В результате ваш маленький файл bank.jar превращается в гигантский кодовый гигабайт, который все боятся развертывать.
Как уменьшить размер монолита Java?
Это естественно приводит к вопросу о том, как уменьшить монолит. На данный момент ваш bank.jar работает в одной JVM, один процесс на одном сервере. Ни больше ни меньше.
Теперь вы можете придумать идею: «Служба проверки рисков используется другими отделами в моей компании, и она на самом деле не имеет ничего общего с моим доменом Mono (lithic) Bank, поэтому мы можем попробовать вырезать его из монолита и развернуть как его отдельный продукт, или, если говорить технически, запустите его как свой собственный процесс Java.
Что такое микросервис Java?
В практическом плане это означает, что вместо вызова метода riskCheck() внутри вашего BankController вы переместите этот метод / bean-компонент со всеми его вспомогательными классами в свой собственный проект Maven / Gradle, поместите его под контроль системы управления исходным кодом и разверните его независимо от вашего. банковского монолита.
Весь этот процесс извлечения не делает ваш новый модуль RiskCheck микросервисом как таковым, и это потому, что определение микросервисов открыто для интерпретации (что приводит к изрядному количеству обсуждений в командах и компаниях).
Вместо того, чтобы рассуждать об этом, мы будем придерживаться прагматичного подхода и делать две вещи:
Итак, подведем итог: сначала у вас был один процесс JVM, один банковский монолит. Теперь у вас есть процесс JVM банковского монолита и микросервис RiskCheck, который работает в своем собственном процессе JVM. И ваш монолит теперь должен вызвать этот микросервис для проверки рисков.
Как общаться между Java микросервисами?
По существу, у вас есть два варианта: синхронное взаимодействие или асинхронное взаимодействие.
Синхронное взаимодействие с помощью HTTP/REST сервисов
Синхронное взаимодействие микросервисов обычно осуществляется через HTTP и REST-подобные сервисы, которые возвращают XML или JSON — хотя это ни в коем случае не является обязательным (посмотрите, например, на Google Protocol Buffers).
Используйте REST-коммуникацию, когда вам нужен немедленный ответ, который мы используем в нашем случае, так как проверка риска обязательна перед открытием счета: нет проверки риска, нет счета.
Посмотрите ниже раздел Какие библиотеки лучше всего подходят для синхронных вызовов Java REST?
Асинхронное взаимодействие с помощью обмена сообщениями
Асинхронная микросервисная связь обычно осуществляется посредством обмена сообщениями с помощью реализации JMS и / или с помощью протокола, такого как AMQP. Обычно, на практике не следует недооценивать интеграцию по электронной почте / SMTP.
Используйте асинхронное взаимодействие, когда вам не нужен немедленный ответ, скажем, пользователи нажимают кнопку «купить сейчас», и вы хотите сгенерировать счет-фактуру, что, безусловно, не должно происходить в рамках цикла запроса-ответа пользователя на покупку.
Посмотрите ниже раздел Какие инструменты лучше всего подходят для асинхронного обмена сообщениями Java?
Пример: вызов REST API в Java
Предположим, что мы решили использовать синхронную микросервисную связь, наш Java код на низком уровне будет выглядеть примерно так. Низкоуровневый, потому что для микросервисных коммуникаций вы обычно создаете клиентские библиотеки, которые абстрагируют вас от реальных HTTP-вызовов.
Глядя на код, становится ясно, что теперь вы должны развернуть два Java (микро) сервиса: ваш банк и сервис RiskCheck. В итоге вы получите две JVM, два процесса. Графическое изображение этого будет выглядеть так:
Но остается вопрос: как именно вы вырезаете или настраиваете эти микросервисы? Что это за мелкие фрагменты? Какой правильный размер?
Давайте посмотрим что в реальности.
Микросервисная архитектура на Java
На практике компании пытаются разработать или спроектировать микросервисные проекты различными способами. Это зависит от того, пытаетесь ли вы превратить существующий монолит в проект микросервисов или начинаете с нового проекта.
От монолита к микросервисам
Одна довольно органичная идея — вычленить микросервисы из существующего монолита. Обратите внимание, что «микро» здесь на самом деле не означает, что сами извлеченные сервисы действительно будут микро — они сами могут быть довольно большими.
Давайте рассмотрим немного теории.
Идея: разбить монолит на микросервисы
Унаследованные проекты выигрывают от микросервисного подхода. Главным образом по трем причинам:
Это означает, что вы можете взглянуть на свой монолит Java-банка и попытаться разбить его по границам домена — это вполне разумный подход.
Реальность: пусть кто-то другой сделает это
Хотя этот подход определенно выглядит хорошо на бумаге и UML-подобных диаграммах, у него есть свои недостатки. В основном, вам нужны очень сильные технические навыки, чтобы справиться с этим. Почему?
Потому что существует огромная разница между пониманием того, что было бы неплохо извлечь, скажем, сильно связанный модуль управления учетными записями из вашего монолита, и сделать это (правильно).
Большинство корпоративных проектов достигают стадии, когда разработчики боятся, скажем, обновить 7-летнюю версию Hibernate до более новой, которая является лишь обновлением библиотеки, но требуются значительные усилия, чтобы не сломать ничего.
Эти же разработчики теперь должны копаться в старом, унаследованном коде с неясными границами транзакций базы данных и извлекать четко определенные микросервисы? Возможно, но часто это реальная проблема, и ее нельзя решить на доске или на совещаниях по архитектуре.
Здесь уместна цитата из @simonbrown в Twitter:
Я буду повторять это… если люди не могут правильно строить монолиты, микросервисы не помогут.
I’ll keep saying this… if people can’t build monoliths properly, microservices won’t help.
Simon Brown
Новый проект с микросервисой архитектурой
Ситуация выглядит немного иначе при разработке новых проектов на Java. Теперь эти три пункта, перечисленные выше выглядят немного иначе:
Это приводит к тому, что компании пытаются использовать микросервисы в новых Java проектах.
Техническая микросервисная архитектура
Первый подход является наиболее очевидным для разработчиков, вопреки настоятельным рекомендациям против него. Hadi Hariri (https://twitter.com/hhariri) рекомендует использовать рефакторинг «Extract Microservice» в IntelliJ.
Хотя следующий пример слишком упрощен, реализации, наблюдаемые в реальных проектах, к сожалению, не слишком далеки от него.
До микросервиса
С использованием Java микросервиса подстроки
Таким образом, вы, по сути, включаете вызов метода Java в вызов HTTP, без очевидных причин для этого. Одна из причин, однако, заключается в следующем: отсутствие опыта и попытка форсировать подход на основе микросервисов Java.
Рекомендация: не делайте этого.
Микросервисная архитектура, ориентированная на workflow (рабочий процесс)
Следующим распространенным подходом является разработка ваших микросервисов Java на основе рабочего процесса.
Пример из реальной жизни: в Германии, когда вы обращаетесь к (государственному) врачу, он должен записать ваше назначение в своем программном обеспечении CRM для здравоохранения.
Чтобы получить оплату от страховой компании, он отправит ваши данные о лечении и всех других пациентов, которых он лечил, посреднику через XML.
Посредник рассмотрит этот XML-файл и (упрощенно):
Если вы сейчас попытаетесь смоделировать этот рабочий процесс с помощью микросервисов, у вас получится это как минимум.
Примечание. В этом примере взаимодействие между микросервисами не имеет значения, но вполне может быть выполнено асинхронно с использованием брокера сообщений, таким как RabbitMQ, поскольку врач все равно не получает немедленной обратной связи.
Опять же, это то, что хорошо выглядит на бумаге, но сразу приводит к нескольким вопросам:
Интересно, что для некоторых архитекторов приведенная выше диаграмма выглядит проще, потому что у каждого сервиса теперь есть свое точное, четко определенное назначение. Раньше это выглядело как этот страшный монолит:
Несмотря на то, что можно спорить о простоте этих диаграмм, теперь вам определенно нужно решить дополнительные операционные задачи.
Рекомендация:
→ Не делай этого.
Прим. перев.:
Chaos Monkey — архитектурный принцип Netflix для поддержки автомасштабируемых stateless-микросервисов — любой инстанс может быть остановлен и автоматически заменен без какой-либо потери состояния. Chaos Monkey следит за тем, чтобы никто не нарушал этот принцип.
Однако с меньшей гиперболой.
Попытка моделировать микросервисы по доменным границам — очень разумный подход. Но граница домена (скажем, управление пользователями или выставление счетов) не означает, что нужно взять один рабочий процесс и разделить его на крошечные отдельные части (получить XML, проверить XML, переслать XML).
Следовательно, всякий раз, когда вы начинаете с новый проект на Java микросервисах, и границы домена все еще очень расплывчаты, старайтесь поддерживать размер ваших микросервисов на нижнем уровне. Вы всегда можете добавить больше модулей позже.
И убедитесь, что у вас есть исключительно сильные навыки DevOps в вашей команде / компании / подразделении для поддержки вашей новой инфраструктуры.
Полиглото или командно-ориентированная микросервисная архитектура
Существует третий, почти либертарианский подход к разработке микросервисов: предоставление вашим командам или даже отдельным лицам возможности реализовывать пользовательские истории с использованием любого количества языков или микросервисов (маркетинговый термин: полиглотное программирование).
Таким образом, приведенная выше служба проверки XML может быть написана на Java, в то время как микросервис правдоподобия написан на языке Haskell (чтобы сделать его математически обоснованным), а микросервис пересылки страховки должен быть написан на языке Erlang (потому что он действительно должен масштабироваться 🙂 ).
То, что может показаться забавным с точки зрения разработчика (разработка идеальной системы с вашим идеальным языком в изолированной среде), в сущности, никогда не является тем, чего хочет организация: унификация и стандартизация.
Это означает относительно стандартизированный набор языков, библиотек и инструментов, чтобы другие разработчики могли продолжать поддерживать ваш микросервис Haskell в будущем, когда вы перейдете на более экологичные пастбища.
Что интересно: историческая стандартизация зашла слишком далеко. Разработчикам в больших компаниях из списка Fortune 500 иногда даже не позволяли использовать Spring, потому что это «не входило в план компании по технологиям». Но переход на полноценный полиглотный подход — это почти то же самое, просто другая сторона той же монеты.
Рекомендация: если вы собираетесь использовать полиглотный подход, попробуйте меньшее разнообразие в одной и той же экосистеме языка программирования. Пример: Kotlin и Java (на основе JVM со 100% совместимостью друг с другом), а не Haskell и Java.
Развертывание и тестирование Java микросервисов
И есть одна замечательная вещь об экосистеме Java, или, скорее, о JVM: вы пишете свой код Java один раз, вы можете запустить его в основном на любой операционной системе, если хотите, если вы не скомпилировали свой код с более новой версией Java, чем ваша целевая версия JVM).
Это важно понимать, особенно когда речь идет о таких темах, как Docker, Kubernetes или The Cloud. Почему? Давайте рассмотрим различные сценарии развертывания:
Пример минимального развертывания микросервиса Java
Продолжая пример с банком, мы получили файл monobank.jar (монолит) и наш недавно извлеченный riskengine.jar (первый микросервис).
Следовательно, минимальное развертывание может состоять из двух каталогов, которые выглядят примерно так:
К сожалению, есть множество соблазнительных ответов на этот вопрос.
Как использовать инструменты сборки, SSH и Ansible для развертывания микросервисов Java
Скучный, но совершенно прекрасный ответ на развертывание Java-микросервисов — это то, как администраторы разворачивали любую серверную Java-программу в компаниях за последние 20 лет. С использованием набора инструментов:
Если вы не зациклены на создании «дышащего» облака на основе серверов с автоматической балансировкой нагрузки, chaos monkeys, управляющих вашими машинами, или горячего и неясного ощущения, что выборы ведущего в ZooKeeper работают, то эта установка уведет вас достаточно далеко.
Олдскулно, скучно, но работает.
Как использовать Docker для развертывания микросервисов Java
Вернемся к заманчивым выборам. Пару лет назад на сцену вышел Docker или тема контейнеризации.
Если у вас нет опыта работы с ним, это то, что нужно для конечных пользователей или разработчиков:
Это выглядит немного иначе для языков, таких как PHP или Python, где несовместимость версий или настройки развертывания исторически были более сложными.
Или, если ваше Java-приложение зависит от множества других установленных служб (с правильными номерами версий): например от базы данных, такой как Postgres, или хранилища значений ключей, таких как Redis.
Итак, основное преимущество Docker для микросервисов Java, а точнее для приложений Java, заключается в:
Если ваши развертываемые файлы похожи или вы хотите запустить небольшую базу данных Oracle на своем компьютере разработки, попробуйте Docker.
Как использовать Docker Swarm или Kubernetes для развертывания микросервисов Java
Теперь возникает вопрос: как вы управляете этим кластером, что означает запуск ваших контейнеров Docker, проверки работоспособности, развертывание обновлений, масштабирование (brrrr)?
Два возможных ответа на этот вопрос — Docker Swarm и Kubernetes.
Подробное описание обоих вариантов невозможно в рамках данного руководства, но на самом деле важно следующее: оба варианта в конце концов полагаются на то, что вы пишете файлы YAML (см. ниже Не вопрос: Рассказы об отступах в Yaml) для управления вашим кластером. Сделайте быстрый поиск в Твиттере, если хотите знать, какие чувства это вызывает на практике.
Таким образом, процесс развертывания для ваших микросервисов Java теперь выглядит примерно так:
Как протестировать микросервисы Java
Предположим, вы решили внедрить микросервисы в производство, но как вы тестируете интеграцию n-микросервисов во время разработки? Чтобы увидеть, работает ли полный рабочий процесс, а не только отдельные части?
На практике вы найдете три разных способа:
Кроме того, в дополнение к вашим микросервисам Java вам, вероятно, также понадобится работающий брокер сообщений (например, ActiveMQ или RabbitMQ) или, возможно, сервер электронной почты или любой другой компонент обмена сообщениями, с которым ваши микросервисы Java должны взаимодействовать друг с другом.
Это приводит к значительному занижению сложности на стороне DevOps. Взгляните на Microservice Testing Libraries, чтобы смягчить эту боль.
В любом случае, эта сложность приводит нас к общим проблемам микросервиса:
Общие вопросы о Java микросервиах
Давайте рассмотрим проблемы микросервисов, характерные для Java, от более абстрактных вещей, таких как устойчивость к конкретным библиотекам.
Как сделать микросервис Java устойчивым?
Напомним, что при создании микросервисов вы по сути заменяете вызовы методов JVM
на синхронные вызовы или асинхронный обмен сообщениями.
В то время как выполнение вызова метода в основном гарантировано (за исключением того, что JVM неожиданно завершает работу), сетевой вызов по умолчанию ненадежен.
Он может работать, он также может не работать по разным причинам: от неработающей или перегруженной сети, до внедрения нового правила брандмауэра и взрыва вашего брокера сообщений.
Чтобы увидеть, какое это имеет значение, давайте взглянем на примерный пример BillingService.
Шаблоны устойчивости HTTP / REST
Скажем, клиенты могут купить электронные книги на сайте вашей компании. Для этого вы только что внедрили микросервис биллинга, который может вызвать ваш интернет-магазин для создания фактических счетов в формате PDF.
Сейчас мы сделаем этот вызов синхронно, через HTTP. (Было бы более разумно вызывать эту службу асинхронно, потому что генерация PDF не обязательно должна быть мгновенной с точки зрения пользователя. Но мы хотим повторно использовать этот самый пример в следующем разделе и увидеть различия.)
Подумайте, какие возможные результаты может иметь этот HTTP-вызов. Обобщая, вы получите три возможных результата:
Обработка ошибок, а не только счастливых случаев, ожидается для любой программы. То же самое относится и к микросервисам, даже если вам нужно приложить дополнительные усилия для обеспечения совместимости всех развернутых версий API, как только вы начнете с развертываний и выпусков отдельных микросервисов.
И если вы хотите полностью использовать Chaos Monkey, вам также придется смириться с возможностью того, что ваши серверы будут просто очищены во время обработки запроса, и вы можете захотеть, чтобы запрос был перенаправлен на другой работающий экземпляр.
Интересный случай с предупреждением — это отложенный случай. Возможно, микросервисный жесткий диск респондента заполнен, и вместо 50 мс для ответа требуется 10 секунд. Это может стать еще более интересным, когда вы испытываете определенную нагрузку, так что неотзывчивость вашего BillingService начинает каскадно проходить через вашу систему. Подумайте о медленной кухне, медленно запускающей блок всех официантов ресторана.
Этот раздел, очевидно, не может дать исчерпывающий обзор темы устойчивости микросервисов, но служит напоминанием для разработчиков о том, что на самом деле это то, что нужно решать, а не игнорировать до вашего первого выпуска (что, по опыту, происходит чаще, чем следует)
Популярной библиотекой, которая помогает вам думать о задержках и отказоустойчивости, является Hystrix от Netflix. Используйте его документацию, чтобы больше погрузиться в тему.
Шаблоны устойчивости обмена сообщениями
Давайте подробнее рассмотрим асинхронное общение. Наш код BillingService теперь может выглядеть примерно так, при условии, что мы используем Spring и RabbitMQ для обмена сообщениями.
Чтобы создать счет, мы теперь отправляем сообщение нашему брокеру сообщений RabbitMQ, у которого есть несколько работников, ожидающих новых сообщений. Эти работники создают счета в формате PDF и отправляют их соответствующим пользователям.
Теперь потенциальные ошибки выглядят немного иначе, так как вы больше не получаете немедленных ответов OK или ERROR, как это было с синхронным HTTP-соединением. Вместо этого у вас будут примерно три случая ошибки:
Опять же, детальное описание каждого отдельного шаблона устойчивости асинхронного микросервиса выходит за рамки данного руководства. Более того, оно лишь дает указатели в правильном направлении, тем более что они также зависят от используемой вами технологии обмена сообщениями. Примеры:
Какой Java-микросервисный фреймворк лучший?
Недавно, частично вдохновленные параллельными разработками, такими как реактивное программирование, Kubernetes или GraalVM, возникла пара специализированных микросервисных сред.
В конце концов, вам придется сделать свой собственный выбор, но эта статья может дать некоторые, возможно, нетрадиционные рекомендации:
За исключением Spring Boot, все фреймворки для микросервисов обычно позиционируют себя как невероятно быстрые с очень быстрым временем запуска, малый объемом памяти, возможностью масштабирования до бесконечности, с впечатляющими графиками, сравнивающими себя с бегемотом Spring Boot или друг с другом.
Это поражает воображение разработчиков, которые поддерживают устаревшие проекты, которые иногда занимают несколько минут, чтобы загружаться, или разработчикам, работающим в облаке, которые хотят запустить-остановить столько микроконтейнеров, сколько им сейчас нужно, или они хотят им нужно в течение 50 мс.
Проблема, однако, заключается в том, что (искусственное) время запуска на «голом железе» и время повторного развертывания едва ли влияют на общий успех проекта, гораздо меньше, чем сильная экоструктура платформы, хорошая документация, сообщество и навыки разработчика.
Вы должны смотреть на это так.
Тогда добавление дополнительных требований для микросервисов (устойчивость, сеть, обмен сообщениями, DevOps, инфраструктура) будет иметь гораздо большее влияние на ваш проект, чем загрузка пустого hello world. А для горячих повторных развертываний во время разработки вы, наконец, вы можете использовать такие решения, как JRebel или DCEVM.
Вернемся к цитате Саймона Брауна (Simon Brown): если люди не могут создавать (быстрые и эффективные) монолиты, им будет трудно создавать (быстрые и эффективные) микросервисы — независимо от фреймворка.
Итак, выбирайте свой фреймвок с умом.
Какие библиотеки лучше всего подходят для синхронных REST вызовов Java?
Поговорим о более практических аспектах вызова HTTP REST API. На низком техническом уровне вы, вероятно, придете к одной из следующих клиентских библиотек HTTP:
Обратите внимание, что здесь я говорю «вероятно», потому что есть и другие способы, от старых добрых клиентов JAX-RS до современных клиентов WebSocket.
В любом случае, существует тенденция к генерации HTTP-клиента, вместо того чтобы возиться с HTTP-вызовами самостоятельно. Для этого вам нужно рассмотреть проект OpenFeign и его документацию в качестве отправной точки для дальнейшего чтения.
Какие брокеры являются лучшими для асинхронного обмена сообщениями Java?
Начиная разработку с асинхронного обмена сообщениями, вы, скорее всего, придете к ActiveMQ (Classic или Artemis), RabbitMQ или Kafka. Опять же, это просто популярный выбор.
Вот несколько основных моментов:
Чтобы лучше понять, когда использовать RabbitMQ (или традиционных брокеров сообщений в целом) или Kafka, в качестве отправной точки взгляните на соответствующий пост Pivotal в качестве отправной точки.
Тем не менее, в общем, старайтесь игнорировать любые искусственные причины производительности при выборе вашего брокера. Было время, когда команды и интернет-сообщества много спорили о том, насколько быстрым был RabbitMQ и насколько медленным был ActiveMQ.
Теперь у вас те же аргументы в отношении того, что RabbitMQ медленен, с только 20-30K сообщений в секунду. Для Kafka сообщается о 100K сообщений в секунду. С одной стороны, такие сравнения можно игнорировать учитывая, что вы на самом деле сравниваете яблоки и апельсины.
Но даже более того: оба значения пропускной способности могут быть на нижней или средней стороне для Alibaba Group, но вы и автор, никогда не видели проекты такого размера (миллионы сообщений в минуту) в реальном мире. Они определенно существуют, но эти цифры — не то о чем нужно беспокоиться для остальных 99% обычных бизнес-проектов Java.
Так что не обращайте внимания на шумиху и выбирайте мудро.
Какие библиотеки я могу использовать для микросервисного тестирования?
В зависимости от вашего стека вы можете использовать инструменты Spring (экосистема Spring) или что-то вроде Arquillian (экосистема JavaEE).
Вы захотите взглянуть на Docker и действительно хорошую библиотеку Testcontainers, которая помогает, например, легко и быстро настроить базу данных Oracle для разработки, локальных тестов или интеграции.
Для макетирования целых HTTP-серверов, посмотрите на Wiremock. Для тестирования асинхронного обмена сообщениями попробуйте встраивание (ActiveMQ) или докеринг (RabbitMQ), а затем написать тесты с помощью Awaitility DSL.
Кроме этого, применяются все ваши обычные «подозреваемые», такие как Junit, TestNG для AssertJ и Mockito.
Обратите внимание, что это далеко не полный список, и если вам не хватает вашего любимого инструмента, опубликуйте его в разделе комментариев, и я включу его в следующую редакцию этого руководства.
Как включить ведение журнала для всех моих микросервисов Java?
Ведение журнала в микросервисах — интересная и довольно сложная тема. Вместо того, чтобы иметь один файл журнала, с которым вы можете использовать less или grep, теперь у вас есть n файлов — журнала, которые вы хотели бы просматривать вместе.
Отличной отправной точкой для всей экосистемы ведения журнала является эта статья. Обязательно прочитайте ее, особенно раздел «Централизованное ведение журнала» с точки зрения микросервисов.
На практике вы найдете различные подходы:
Как мои микросервисы находят друг друга?
До сих пор мы предполагали, что все наши микросервисы знают друг друга, знают соответствующий IPS. Это статическая настройка. Итак, наш банковский монолит [ip = 192.168.200.1] знает, что ему нужно поговорить с сервером риска [ip = 192.168.200.2], который жестко задан в файле свойств.
Однако вы можете сделать вещи более динамичными:
В общих чертах, это то, что называется микросервисной оркестровкой и еще одна огромная тема.
Такие библиотеки, как Eureka или Zookeeper, пытаются «решить» эти проблемы, например, создание клиентов или маршрутизаторов, знающих, какие службы доступны и где. С другой стороны, они вносят много дополнительной сложности.
Просто спросите любого, кто когда-либо запускал установку ZooKeeper.
Как сделать авторизацию и аутентификацию с помощью микросервисов Java?
Еще одна огромная тема, достойная собственного эссе. Опять же, варианты варьируются от жестко закодированной базовой аутентификации HTTPS с собственными фреймворками безопасности до запуска установки Oauth2 с вашим собственным сервером авторизации.
Как мне убедиться, что все мои окружения выглядят одинаково?
То, что верно для развертываний без микросервиса, также верно и для развертываний микросервиса. Вы можете попробовать комбинацию Docker / Testcontainers, а также сценариев / Ansible.
Попробуйте и сохраняйте его проще.
Не вопрос: Рассказы об отступах в Yaml
Сделаем резкий разворот от конкретных библиотечных вопросов, давайте кратко рассмотрим Yaml. Это формат файла, который используется в качестве фактического формата файла для «записи конфигурации в виде кода». От более простых инструментов, таких как Ansible, до могучих Kubernetes.
Чтобы испытать «мучения» от отступов в YAML, попробуйте написать простые файлы Ansible и посмотрите, как часто вам нужно повторно редактировать файл, чтобы заставить отступ работать правильно, несмотря на различные уровни поддержки IDE. А затем вернитесь, чтобы закончить это руководство.
А как насчет распределенных транзакций? Тестирование производительности? Другие темы?
К сожалению, эти темы не вошли в эту редакцию данного руководства. Оставайтесь с нами, чтобы узнать больше.
Концептуальные проблемы микросервисов
Помимо специфических проблем микросервисов в Java, существуют также проблемы, которые возникают в любом микросервисном проекте. Их больше с организационной, командной или управленческой точки зрения.
Несоответствие фронтенд и бэкеенд
То, что происходит во многих микросервисных проектах, я бы назвал несоответствием внешнего интерфейса и интерфейса микросервиса. Что это обозначает?
Что в старых добрых монолитах, у разработчиков веб-интерфейса был один конкретный источник для получения данных. В микросервисных проектах у разработчиков веб-интерфейса неожиданно появляются n источников для получения данных.
Представьте, что вы создаете какой-то проект микросервисов Java-IoT. Скажем, вы выполняете мониторинг машин, таких как промышленные печи по всей Европе. И эти печи регулярно отправляют вам обновления с указанием их температуры и т.д.
Рано или поздно вы, возможно, захотите выполнять поиск печи в пользовательском интерфейсе администратора, возможно, с помощью микросервисов «поиска печи». В зависимости от того, насколько строго ваши бэкэнд-коллеги могут интерпретировать domain driven design или законы о микросервисах, может случиться так, что микросервис «поиск печи» возвращает только ваши идентификаторы, но не другие данные, такие как тип, модель или местоположение.
Для этого разработчикам фронтенда может потребоваться выполнить один или n дополнительных вызовов (в зависимости от вашей реализации пейджинга) в микросервисе «получить данные о печи» с идентификаторами, которые они получили от первого микросервиса.
И хотя это всего лишь простой (но взятый из реального проекта (!)) Пример, он демонстрирует следующую проблему:
Реальные супермаркеты получили огромное признание по определенной причине. Потому что вам не нужно ходить в 10 разных мест, чтобы покупать овощи, лимонад, замороженную пиццу и туалетную бумагу. Вместо этого вы идете в одно место.
Это проще и быстрее. То же самое касается разработчиков интерфейсов и микросервисов.
Ожидания руководства
Эта проблема вызывает нежелательные побочные эффекты со стороны отдельных разработчиков, программистских журналов или облачных компаний, предлагающих микросервисы:
У руководства сложилось впечатление, что вы теперь можете вкладывать в (всеобъемлющий) проект бесконечное количество разработчиков, поскольку разработчики теперь могут работать совершенно независимо друг от друга, каждый на своем микросервисе. В самом конце требуется лишь небольшая работа по интеграции (т.е. незадолго до запуска).
Давайте рассмотрим в следующих параграфах, почему этот взгляд является серьёзной проблемой.
Меньшие части не означают лучшие части
Одна довольно очевидная проблема состоит в том, что 20 меньших частей (как в микросервисах) на самом деле не означают 20 лучших частей. Чисто с точки зрения технического качества это может означать, что ваши отдельные службы по-прежнему выполняют 400 запросов Hibernate для выбора пользователя из базы данных по слоям и слоям не поддерживаемого кода.
Возвращаясь к цитате Саймона Брауна: если людям не удастся построить монолиты должным образом, им будет сложно создать надлежащие микросервисы.
Во многих микросервисных проектах мысли об устойчивости происходят после запуска, является такой, поэтому немного страшно смотреть, как микросервисы работают вживую.
Это имеет простую причину: поскольку Java-разработчики обычно не заинтересованы в том, чтобы не обучены должным образом в области устойчивости, сетей и других смежных тем.
Меньшие части приводят к большему количеству технических частей
Кроме того, существует печальная тенденция к тому, чтобы пользовательские истории становились все более и более техническими (и, следовательно, глупыми), более микро и отвлеченными от пользователя, от которого они получены.
Представьте, что вашей микросервисной команде предлагается написать технический микросервис для входа в систему с базой данных, примерно такой:
Теперь ваша команда может решить (и, возможно, даже убедить бизнесменов): это слишком просто и скучно, вместо службы входа в систему давайте напишем действительно «умный» микросервис UserStateChanged — без каких-либо реальных и ощутимых бизнес-требований.
А поскольку Java в настоящее время не в моде, давайте напишем микросервис UserStateChanged в Erlang. И давайте попробуем где-нибудь использовать красно-черные деревья, потому что Steve Yegge написал, что вы должны знать их наизнанку, чтобы подать резюме в Google.
С точки зрения интеграции, обслуживания и общего проекта это так же плохо, как написание слоев спагетти-кода внутри одного монолита.
Придуманный и заурядный пример? Да.
К сожалению, также не редкость в реальной жизни.
Меньшие кусочки ведут к меньшему пониманию
Затем возникает тема понимания всей системы, ее процессов и рабочих процессов, если вы, как разработчик, несете ответственность только за работу на изолированном микросервисе [95: login-101: updateUserProfile].
Это гармонирует с предыдущим параграфом, но в зависимости от вашей организации, уровня доверия и коммуникации это может привести к большому пожиманию плечами и обвинениям, если сломается какая-то часть всей микросервисной цепочки — никто не больше принимает полную ответственность.
Это не является недобросовестностью, скорее проблема в том, что на самом деле очень трудно понять количество отдельных частей и их место в общей картине.
Коммуникации и обслуживание
Это связано с последней проблемой: коммуникации и обслуживание. Это, очевидно, сильно зависит от размера компании, с общим правилом: чем больше, тем проблематичнее.
Кто работает на микросервисе № 47?
Они только что развернули новую несовместимую версию микросервиса? Где это было задокументировано?
С кем мне нужно поговорить для запроса новой функции?
Кто будет поддерживать микросервис на Erlang после того, как Макс покинул компанию?
Все наши микросервисные команды работают не только на разных языках программирования, но и в разных часовых поясах! Как мы правильно координируем?
Главной темой здесь является то, что, подобно навыкам DevOps, полноценный подход к микросервисам в более крупной, возможно, даже международной компании, сопряжен с кучей дополнительных коммуникационных проблем. Как компания, вы должны быть готовы к этому.
Заключение
Прочитав эту статью, вы можете заключить, что ваш автор строго рекомендует микросервисы. Это не совсем верно — я в основном пытаюсь выделить моменты, которые забыты в безумии микросервисов.
Баланс микросервисов
Полное использование Java-микросервисов — это одно положение маятника. Другое положение — что-то вроде сотен старых добрых модулей Maven в Монолите. Вы должны найти правильный баланс.
Особенно в новых проектах ничто не мешает вам придерживаться более консервативного, монолитного подхода и создавать меньше, лучше определенных модулей Maven, вместо того чтобы сразу начинать работу с двадцатью готовыми к работе облачными микросервисами.
Микросервисы создают тысячи дополнительных сложностей
Имейте в виду, что чем больше у вас микросервисов и чем меньше у вас действительно сильных талантов DevOps (нет, выполнение нескольких сценариев Ansible или развертывание на Heroku не учитывается), тем больше проблем у вас возникнет позже в работе.
Прочитать раздел Общие вопросы о Java микросервисах этого руководства уже утомительно. Затем подумайте о реализации решений для всех этих инфраструктурных задач. Вы очевидно поймете, что все это больше не связано с бизнес-программированием (за что вам платят), а скорее с фиксацией большего количества технологий на еще большем количестве технологий.
Siva Prasad Reddy (Шива Прасад Редди) отлично подвел итог в своем блоге:
Я не могу объяснить, как это ужасно, когда команда тратит 70% времени на борьбу с этой современной инфраструктурой и 30% времени на реальную бизнес-логику.
Стоит ли создавать микросервисы Java?
Чтобы ответить на этот вопрос, я хотел бы закончить эту статью очень дерзко, похоже на тизер Google интервью. Если вы знаете ответ на этот вопрос по своему опыту, даже если он, по-видимому, не имеет ничего общего с микросервисами, вы можете быть готовы к микросервисному подходу.
Сценарий
Представьте, что у вас есть монолит Java, работающий самостоятельно на самой маленькой выделенной машине Hetzner. То же самое относится и к вашему серверу баз данных, он также работает на аналогичной машине Hetzner.
И давайте также предположим, что ваш Java-монолит может обрабатывать рабочие процессы, такие как регистрация пользователей, и вы создаете не сотни запросов к базе данных на рабочий процесс, а только разумное количество (



