JavaRush /Java блог /Java Developer /Руководство по микросервисам Java. Часть 3: общие вопросы...

Руководство по микросервисам Java. Часть 3: общие вопросы

Статья из группы Java Developer
Перевод и адаптация Java Microservices: A Practical Guide. Предыдущие части гайда: Давайте рассмотрим свойственные Java проблемы микросервисов начиная с абстрактных вещей и заканчивая конкретными библиотеками. Руководство по микросервисам Java. Часть 3: общие вопросы - 1

Как сделать микросервис Java устойчивым?

Напомним, что при создании микросервисов вы по сути меняете вызовы методов JVM на синхронные вызовы HTTP или асинхронный обмен сообщениями. В то время как выполнение вызова метода в основном гарантировано (за исключением неожиданного завершения работы JVM), сетевой вызов по умолчанию ненадежен. Он может работать, но может и не работать по разным причинам: перегружена сеть, внедрили новое правило брандмауэра и так далее. Чтобы увидеть, какое это имеет значение, давайте взглянем на пример BillingService.

Паттерны устойчивости HTTP / REST

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

@Service
class BillingService {

    @Autowired
    private HttpClient client;

     public void bill(User user, Plan plan) {
        Invoice invoice = createInvoice(user, plan);
        httpClient.send(invoiceRequest(user.getEmail(), invoice), responseHandler());
        // ...
    }
}
Если обобщить, вот три возможных результата этого HTTP-вызова.
  • ОК: звонок прошел, счет успешно создан.
  • ЗАДЕРЖКА: звонок прошел, но потребовалось слишком много времени для этого.
  • ОШИБКА. Вызов не состоялся, возможно, вы отправили несовместимый запрос или система не работала.
От любой программы ожидают обработку ошибочных ситуаций, а не только успешных. То же самое относится и к микросервисам. Даже если вам нужно приложить дополнительные усилия для обеспечения совместимости всех развернутых версий API, как только вы начнете с развертываний и выпусков отдельных микросервисов. Руководство по микросервисам Java. Часть 3: общие вопросы - 2Интересный случай, на который стоит обратить внимание, — случай задержки. Например, микросервисный жесткий диск респондента переполнен, и вместо 50 мс для ответа требуется 10 секунд. Ещё интереснее становится тогда, когда вы испытываете определенную нагрузку, так что неотзывчивость вашего BillingService начинает каскадно проходить через вашу систему. В качестве наглядного примера вообразите кухню, меееедленно запускающую “блок” всех официантов ресторана. Этот раздел, очевидно, не может дать исчерпывающий обзор темы устойчивости микросервисов, но служит напоминанием для разработчиков о том, что на самом деле это то, что нужно решать, а не игнорировать до вашего первого выпуска (что, по опыту, происходит чаще, чем следует). Популярной библиотекой, которая помогает вам думать о задержках и отказоустойчивости, является Hystrix от Netflix. Используйте её документацию, чтобы больше погрузиться в тему.

Messaging Resilience Patterns (Отказоустойчивые паттерны обмена сообщениями)

Давайте подробнее рассмотрим асинхронную коммуникацию. Наша программа BillingService теперь может выглядеть примерно так, при условии, что мы используем Spring и RabbitMQ для обмена сообщениями. Чтобы создать счет, мы теперь отправляем сообщение нашему брокеру сообщений RabbitMQ, где есть несколько работников, ожидающих новых сообщений. Эти работники создают счета в формате PDF и отправляют их соответствующим пользователям.

@Service
class BillingService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

     public void bill(User user, Plan plan) {
        Invoice invoice = createInvoice(user, plan);
        // преобразует счет, например, в json и использует его как тело сообщения
        rabbitTemplate.convertAndSend(exchange, routingkey, invoice);
        // ...
    }
}
Теперь потенциальные ошибки выглядят немного иначе, так как вы больше не получаете немедленных ответов OK или ERROR, как это было с синхронным HTTP-соединением. Вместо этого у нас может быть три потенциальных варианта неправильного развития событий, которые могут вызвать следующие вопросы:
  1. Было ли мое сообщение доставлено и использовано работником? Или это потеряно? (Пользователь не получает счет-фактуру).
  2. Мое сообщение было доставлено только один раз? Или доставлено более одного раза и обрабатывается только один раз? (Пользователь получит несколько счетов).
  3. Конфигурация: От «Использовал ли я правильные ключи маршрутизации/имена для обмена» до «Правильно ли настроен и поддерживается мой брокер сообщений или переполнены его очереди?» (Пользователь не получает счет-фактуру).
Детальное описание каждого отдельного паттерна устойчивости асинхронного микросервиса выходит за рамки данного руководства. Тем не менее, тут есть указатели в правильном направлении. Тем более что они будут зависеть от технологии обмена сообщениями. Примеры:
  • Если вы используете реализации JMS, например, ActiveMQ, вы можете обменять скорость на гарантии двухфазных (XA) коммитов (two-phase (XA) commits).
  • Если вы используете RabbitMQ, для начала прочитайте это руководство, а затем хорошенько обдумайте подтверждения, отказоустойчивость и надежность сообщений в целом.
  • Возможно, кто-то хорошо разбирается в конфигурировании серверов Active или RabbitMQ, особенно в сочетании с кластеризацией и Docker (кто-нибудь?;))

Какой фрейморк будет лучшим решением для микросервисов Java?

С одной стороны, можно установить очень популярный вариант, такой как Spring Boot. Он позволяет очень легко создавать файлы .jar, поставляется со встроенным веб-сервером, таким как Tomcat или Jetty, и который можно запустить быстро и где угодно. Идеально подходит для создания приложений микросервиса. Не так давно появилась пара специализированных микросервисных фреймворков Kubernetes или GraalVM, частично вдохновлённых реактивным программированием. Вот ещё несколько интересных претендентов: Quarkus, Micronaut, Vert.x, Helidon. В конце концов, вам придется выбирать самостоятельно, но мы можем дать вам парочку рекомендаций, возможно, не вполне стандартных: За исключением Spring Boot, все платформы микросервисов обычно позиционируются как невероятно быстрые, с почти мгновенным запуском, малым объемом используемой памяти, возможностью масштабирования до бесконечности. В маркетинговых материалах обычно фигурируют впечатляющие графики, представляющие платформу в выгодном свете рядом с “бегемотом” Spring Boot или друг с другом. Это по идее щадит нервы разработчиков, поддерживающих легаси-проекты, которые порой загружаются по несколько минут. Или разработчикам, работающим в облаке, которые хотят запустить\остановить столько микроконтейнеров, сколько им сейчас нужно в течение 50 мс. Руководство по микросервисам Java. Часть 3: общие вопросы - 3Проблема, однако, заключается в том, что такое (искусственное) время старта «голого железа» и время повторного развертывания едва ли влияют на общий успех проекта. По крайней мере влияют гораздо меньше, чем сильная инфраструктура фреймворка, сильная документация, сообщество и сильные навыки разработчика. Так что лучше смотреть на это так: Если до сих пор:
  • Вы позволяете своим ORM работать в режиме безудержной генерации сотен запросов для простых рабочих процессов.
  • Вам нужны бесконечные гигабайты для запуска вашего монолита умеренной сложности.
  • У вас так много кода и сложность столь высока (сейчас мы говорим не о потенциально медленных стартерах, таких как Hibernate), что вашему приложению нужно несколько минут для загрузки.
Если дело обстоит именно так, то добавление дополнительных микосервисных проблем (отказоустойчивостьЮ сеть, обмен сообщениями, DevOps, инфраструктура) гораздо больше повлияет на ваш проект, чем загрузка пустого Hello, world. А для горячих повторных развертываний во время разработки вам, в конце концов, могут пригодиться такие решения, как JRebel или DCEVM. Не поленимся вновь процитировать Саймона Брауна: “если люди не могут создавать (быстрые и эффективные) монолиты, им будет трудно создавать (быстрые и эффективные) микросервисы независимо от структуры”. Так что выбирайте фрейморки с умом.

Какие библиотеки лучше всего подходят для синхронных вызовов Java REST?

На низкоуровневой технической стороне вы, вероятно, получите одну из следующих клиентских библиотек HTTP: Собственный HttpClient Java (начиная с Java 11), HttpClient Apache или OkHttp. Обратите внимание, что здесь я говорю «вероятно», потому что есть и другие варианты, начиная со старых добрых клиентов JAX-RS до современных клиентов WebSocket. В любом случае, существует тенденция к генерации HTTP-клиента, с отходом от самостоятельной возни с HTTP-вызовами. Для этого вам нужно взглянуть на проект OpenFeign и его документацию в качестве отправной точки для дальнейшего чтения.

Какие брокеры являются лучшими для асинхронного обмена сообщениями Java?

Скорее всего, вы столкнётесь с популярными ActiveMQ (Classic или Artemis), RabbitMQ или Kafka.
  • ActiveMQ и RabbitMQ являются традиционными, полноценными брокерами сообщений. Они предполагают взаимодействие “умного брокера” и “глупеньких пользователей”.
  • Исторически ActiveMQ имел преимущество простого встраивания (для тестирования), которое можно смягчить с помощью настроек RabbitMQ/Docker/TestContainer.
  • Kafka нельзя назвать традиционным “умным” брокером. Наоборот, это относительно «глупое» хранилище сообщений (файл журнала), для обработки которого нужны умные потребители.
Чтобы лучше понять, когда использовать RabbitMQ (или другие традиционные брокеры сообщений в целом) или Kafka, взгляните на этот пост в Pivotal(на английском языке) в качестве отправной точки. В целом, когда выбираете брокер обмена сообщениями, старайтесь игнорировать искусственные причины производительности. Было время, когда команды и интернет-сообщества постоянно спорили о том, насколько быстрым был RabbitMQ и насколько медленным ActiveMQ. Теперь те же аргументы приводятся в отношении RabbitMQ, дескать он медленно работает с 20-30 тысячами сообщений в секунду. У Kafka фиксируется 100 тысяч сообщений в секунду. Откровенно говоря, такие сравнения подобны сравнению теплого с мягким. Кроме того, в обоих случаях значения пропускной способности могут быть на нижнем или среднем уровне, скажем, для Alibaba Group. Однако вы вряд ли сталкивались с проектами такого масштаба (миллионы сообщений в минуту) в реальности. Они определенно существуют, и у них были бы проблемы. В отличие от остальных 99% “обычных” бизнес-проектов Java. Так что не обращайте внимания на моду и хайп. Выбирайте с умом.

Какие библиотеки я могу использовать для тестирования микросервисов?

Это зависит от вашего стека. Если у вас развёрнута экосистема Spring, будет разумно использовать специальные инструменты этого фреймворка. Если JavaEE — что-то вроде Arquillian. Возможно, стоит взглянуть на Docker и действительно хорошую библиотеку Testcontainers, которая помогает, в частности, легко и быстро настроить базу данных Oracle для локальных тестов разработки или интеграции. Для мок-тестов целых HTTP-серверов, обратите внимание на Wiremock. Для тестирования асинхронного обмена сообщениями попробуйте внедрить ActiveMQ или RabbitMQ, а затем написать тесты с помощью Awaitility DSL. Кроме этого, применяются все ваши привычные инструменты — Junit, TestNG для AssertJ и Mockito. Обратите внимание, что это далеко не полный список. Если вдруг вы не нашли здесь вашего любимого инструмента, опубликуйте его в разделе комментариев.

Как включить логирование для всех микросервисов Java?

Логирование в случае с микросервисами — интересная и довольно сложная тема. Вместо того, чтобы иметь один файл лога, с которым вы можете работать посредством команд less или grep, теперь у вас есть n файлов логирования, и желательно, чтобы они не были слишком разрознены. Хорошо расписаны особенности экосистемы логирования в этой статье (на английском языке). Обязательно прочитайте его, и обратите внимание на раздел Централизованное ведение лога с точки зрения микросервисов. На практике вы столкнётесь с различными подходами: Системный администратор пишет определённые сценарии, которые собирают и объединяют файлы логов с различных серверов в один файл логов и помещают их на FTP-серверы для загрузки. Запуск комбинаций cat/grep/unig/sort в параллельных SSH-сессиях. Именно так поступает Amazon AWS, о чём вы можете сообщить своему менеджеру. Используйте такой инструмент, как Graylog или ELK Stack (Elasticsearch, Logstash, Kibana)

Как мои микросервисы находят друг друга?

До сих пор мы предполагали, что наши микросервисы знают друг о друге, знают соответствующий IPS. Поговорим о статической настройке. Итак, наш банковский монолит [ip = 192.168.200.1] знает, что ему нужно поговорить с риск-сервером [ip = 192.168.200.2], который захардкожен в файле properties. Однако вы можете сделать всё более динамичным:
  • Используйте облачный сервер конфигурации, с которого все микросервисы извлекают свои конфигурации вместо развертывания файлов application.properties на своих микросервисах.
  • Поскольку экземпляры ваших служб могут динамически менять свое местоположение, стоит присмотреться к службам, которые знают, где живут ваши службы, какие у них IP и как их маршрутизировать.
  • Теперь, когда все динамично, появляются новые проблемы, такие как автоматическое избрание лидера: кто является мастером, который работает над определенными задачами, чтобы например, не обработать их дважды? Кто заменяет лидера, когда он терпит неудачу? По какому принципу происходит замена?
В общих чертах, это то, что называется микросервисной оркестровкой и она представляет собой ещё одну бездонную тему. Такие библиотеки, как Eureka или Zookeeper, пытаются «решить» эти проблемы, показывая какие службы доступны. С другой стороны, они привносят дополнительную сложность. Спросите любого, кто когда-либо устанавливал ZooKeeper.

Как организовать авторизацию и аутентификацию с помощью микросервисов Java?

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

Как убедиться, что все мои окружения выглядят одинаково?

То, что верно для развертываний без микросервиса, также верно и для развертываний с ним. Попробуете комбинацию Docker/Testcontainers, а также Scripting/Ansible.

Не вопрос: кратко о YAML

Давайте ненадолго отойдём от библиотек и связанных с ними вопросов и вкратце рассмотрим Yaml. Этот формат файла, используется де-факто в качестве формата для «записи конфигурации в виде кода». Используют его и простые инструменты, наподобие Ansible и гиганты вроде Kubernetes. Чтобы испытать боль от отступов в YAML, попробуйте написать простой Ansible-файл и посмотрите, сколько вам придётся редактировать файл прежде, чем он заработает как нужно. И это невзирая на поддержку формата всеми крупными IDE! После этого возвращайтесь, чтобы дочитать это руководство.

Yaml:
  - is:
    - so
    - great

А как насчет распределенных транзакций? Тестирование производительности? Другие темы?

Может, когда-нибудь, в следующих редакциях руководства. А пока — всё. Оставайтесь с нами!

Концептуальные проблемы микросервисов

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

Несоответствие Frontend и Backend

Несоответствие Frontend и Backend — весьма распространенная проблема многих микросервисных проектов. Что она означает? Лишь то, что в старых добрых монолитах, у разработчиков веб-интерфейса был один конкретный источник для получения данных. В микросервисных проектах у разработчиков веб-интерфейса неожиданно появляются n источников для получения данных. Представьте, что вы создаете какой-то проект микросервисов IoT (интернет вещей) на Java. Скажем, заведуете геодезическими машинами, промышленными печами по всей Европе. И эти печи регулярно отправляют вам обновления с указанием их температуры и тому подобными данными. Рано или поздно вы, возможно, захотите найти печи в пользовательском интерфейсе администратора, возможно, с помощью микросервисов «поиска печи». В зависимости от того, насколько строго ваши бэкэнд-коллеги применяют предметно-ориентированное проектирование или законы микросервисов, микросервис “найти печь” может возвращать только идентификаторы печей, а не другие данные, такие как тип, модель или местоположение. Для этого фронтенд-разработчикам нужно будет выполнить один или n дополнительных вызовов (в зависимости от реализации пейджинга) в микросервисе «получить данные о печи» с идентификаторами, которые они получили от первого микросервиса. Руководство по микросервисам Java. Часть 3: общие вопросы - 4И хотя это всего лишь простой пример, пускай и взятый из реального (!) проекта, даже он демонстрирует следующую проблему: супермаркеты стали чрезвычайно популярны. А всё потому, что с ними вам не нужно идти в 10 разных мест, чтобы купить овощи, лимонад, замороженную пиццу и туалетную бумагу. Вместо этого вы идете в одно место.Это проще и быстрее. То же самое касается разработчиков интерфейсов и микросервисов.

Ожидания руководства

У менеджмента складывается ошибочное впечатление, что теперь нужно нанимать бесконечное количество разработчиков во (всеобъемлющий) проект, поскольку разработчики теперь могут работать совершенно независимо друг от друга, каждый на своем микросервисе. В самом конце требуется лишь небольшая работа по интеграции (незадолго до запуска). Руководство по микросервисам Java. Часть 3: общие вопросы - 5На самом деле такой подход крайне проблематичен. В следующих параграфах мы постараемся пояснить, почему.

“Меньшие кусочки” не равно “лучшие кусочки”

Будет большой ошибкой считать, что разделённый на 20 частей код обязательно будет качественнее одного цельного куска. Даже если взять качество с сугубо технической точки зрения: наши отдельные службы по-прежнему могут выполнять 400 запросов Hibernate для выбора пользователя из базы данных, проходясь по слоям не поддерживаемого кода. В очередной раз возвращаемся к цитате Саймона Брауна: если не удастся построить монолиты должным образом, будет сложно создать надлежащие микросервисы. Зачастую об отказоустойчивости в микросервисных проектах крайне несвоевременно. Настолько, что порой страшно смотреть, как микросервисы работают в настоящих проектах. Причина этого кроется в том, что Java-разработчики не всегда готовы изучать отказоустойчивость, сети и другие смежные темы на должном уровне. Сами “кусочки” — меньше, а вот “технических частей” — больше. Представьте, что вашей микросервисной команде предлагается написать технический микросервис для входа в систему базы данных, примерно такой:

@Controller
class LoginController {
    // ...
    @PostMapping("/login")
    public boolean login(String username, String password) {
        User user = userDao.findByUserName(username);
        if (user == null) {
            // обработка варианта с несуществующим пользователем
            return false;
        }
        if (!user.getPassword().equals(hashed(password))) {
            // обработка неверного пароля
            return false;
        }
        // 'Ю-ху, залогинились!';
        // установите cookies, делайте, что угодно
        return true;
    }
}
Теперь ваша команда может решить (и, возможно, даже убедить людей бизнеса), дескать, это всё слишком просто и скучно, лучше вместо службы входа в систему написать действительно полезный микросервис UserStateChanged (изменение состояния пользователя) без каких-либо реальных и ощутимых бизнес-требований. А поскольку к Java в настоящее время некоторые люди относятся как к динозавру, напишем наш микросервис UserStateChanged на модном Erlang. И давайте попробуем где-нибудь использовать красно-черные деревья, потому что Стив Йегге написал, что вы должны знать их изнутри, чтобы подать заявку в Google. С точки зрения интеграции, обслуживания и общего проекта это так же плохо, как написание слоев спагетти-кода внутри одного монолита. Искусственный и заурядный пример? Так и есть. Тем не менее, подобное может быть и в реальности.

Меньше кусочки — меньше понимания

Затем естественным образом всплывает вопрос о понимании системы в целом, её процессов и рабочих потоков, но при этом вы, как разработчик, несете ответственность только за работу на своём изолированном микросервисе [95: login-101: updateUserProfile]. Он гармонирует с предыдущим параграфом, но в зависимости от вашей организации, уровня доверия и коммуникации это может привести к большому количеству недоумения, пожиманий плечами, обвинениям в случае случайной поломки в микросервисной цепочке. И нет того, кто бы принял на себя полную ответственность за случившееся. И дело вовсе не в недобросовестности. На самом деле очень трудно соединить разные детальки и понять их место в общей картине проекта.

Коммуникации и обслуживание

Уровень коммуникации и обслуживания сильно зависит от размера компании. Тем не менее, общая зависимость очевидна: чем больше, тем проблематичнее.
  • Кто работает на микросервисе № 47?
  • Они только что развернули новую несовместимую версию микросервиса? Где это было задокументировано?
  • С кем мне нужно поговорить чтобы запросить новую функции?
  • Кто будет поддерживать тот микросервис на Erlang, после того, как единственный кто знал этот язык покинул компанию?
  • Все наши микросервисные команды работают не только на разных языках программирования, но и в разных часовых поясах! Как мы всё это правильно скоординируем?
Руководство по микросервисам Java. Часть 3: общие вопросы - 6Главная мысль заключается в том, что как и в случае с DevOps, полноценный подход к микросервисам в крупной, возможно, даже международной компании, сопряжен с кучей дополнительных коммуникационных проблем. И компания должна серьезно к этому подготовиться.

Выводы

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

Микросервисы или монолит?

Использование Java-микросервисов всегда и везде — это одна крайность. Другой оказывается что-то вроде сотен старых добрых модулей Maven в монолите. Ваша же задача найти правильный баланс. Особенно это касается новых проектов. Здесь вам ничто не помешает придерживаться более консервативного, “монолитного” подхода и создавать меньшее количество хороших модулей Maven, вместо того, чтобы начинать с двадцати микросервисов, готовых к работе в облаках.

Микросервисы генерируют дополнительную сложность

Имейте в виду, что чем больше у вас микросервисов и чем меньше у вас действительно мощных DevOps’ов (нет, запуск пары-тройки сценариев Ansible или развертывание на Heroku не считается!), тем больше проблем у вас возникнет позже в работе. Даже просто прочитать до конца раздел этого руководства, посвящённый общим вопросам о микросервисах Java — довольно утомительное занятие. Хорошенько подумайте о реализации решений для всех этих инфраструктурных задач, и вы внезапно поймете, что все это больше не связано с бизнес-программированием (за что вам платят), а скорее с фиксацией большего количества технологий на еще большем количестве технологий. Шива Прасад Редди отлично резюмировал в своем блоге: “Вы не представляете себе, как это ужасно, когда когда команда 70% времени борется с этой современной инфраструктурой и только 30% времени остаётся на реальную бизнес-логику” Шива Прасад Редди

Стоит ли создавать микросервисы Java?

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

Сценарий

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

Вопрос

Сколько соединений с базой данных должен открыть ваш монолит Java (пул соединений) на вашем сервере баз данных? Почему так? Как вы думаете, сколько активных пользователей одновременно может (приблизительно) масштабировать ваш монолит?

Ответ

Оставьте свой ответ на эти вопросы в разделе комментариев. Я с нетерпением жду всех ответов. Руководство по микросервисам Java. Часть 3: общие вопросы - 8Теперь решайтесь. Если вы дочитали до самого конца, мы очень вам благодарны!
Комментарии (6)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Sergey Drogunov Уровень 111 Expert
3 февраля 2023
Классные статьи но в заголовке слово «Руководство» не совсем подходит для них. Больше на введение похоже.
Сергей Уровень 22
11 апреля 2022
О чем эта статья? - без практических примеров создания с нуля и до запуска - НИ-О-ЧЕМ! Автор и переводчик видимо ошиблись. Программирование - это не про теорию, особенно такую бессмысленную и по верхам, как в этой статье. Программирование - это про практику!
Алексей Уровень 22
11 мая 2020
как то сумбурно все... Наверно я мало понимаю в этом. окей, докер - контейнер - любопытно, хотелось бы общего вида архитектуры. вот микросервис1 (мс далее), мс2, ... мсN вот очередь - она коннектится к этим сервисам вот тесты мы смотрим как оно все работает вот у нас (допустим модный мл) тензорфлоу, который распознает что-то тоже в виде сервиса вот какой-то персистенс(бд или бд и бакеты S3, что-то еще волшебное...) вот тут какой-то фронт для пользователей, на JS или TS фреймворке. когда структуры перед глазами нет как то трудно читается
andy.v Уровень 25
30 апреля 2020

@Service
class BillingService {

    @Autowired
    private HttpClient client;

     public void bill(User user, Plan plan) {
        Invoice invoice = createInvoice(user, plan);
        httpClient.send(invoiceRequest(user.getEmail(), invoice), responseHandler());
        // ...
    }
}
23 апреля 2020
О ужас! - первое впечатление от статьи. В это все надо вникать разработчику? Или все же это хлеб админов, или по модному, DevOps-ов?