Привет, Хабр. Для будущих студентов курса "Highload Architect" подготовили перевод материала.Также приглашаем на открытый вебинар по теме «Репликация как паттерн горизонтального масштабирования хранилищ». На занятии участники вместе с экспертом разберут репликацию — одну из техник масштабирования баз данных, обсудят смысл и ее назначение, рассмотрят преимущества и недостатки различных видов репликации.   Микросервисы на Java замечательны тем, что с помощью них можно создавать большие и сложные системы из множества независимых компонент. Вместо одного приложения получается несколько мини-приложений или сервисов. Компоненты могут тестироваться, развертываться и обслуживаться независимо друг от друга. Так что, если убрать один кирпич, то здание не разрушится полностью. Тем не менее очевидное преимущество микросервисов может стать и причиной возникновения проблем. Если раньше вы уже работали с микросервисами на Java, то знаете, что для получения высокой производительности без потери функциональности могут потребоваться усилия. Но если вы справитесь с этим, то получите потрясающие результаты. Spring Boot — это быстрый способ создания микросервисов на Java. В этой статье мы рассмотрим, как улучшить производительность Spring Boot-микросервиса. Мы будем использовать два микросервиса: External-service (внешний сервис): "реальный" микросервис, доступный по HTTP. Facade-service (фасад): микросервис, который будет читать данные из external-service и отправлять результат клиентам. Будем оптимизировать этот сервис. Java 8 Jmeter 5.3 Java IDE Gradle 6.6.1 Прежде всего, скачайте исходный код, который мы будем улучшать, отсюда. Сервис был создан с помощью Spring Initializer. В нем один контроллер, имитирующий нагрузку: Запустите ExternalServiceApplication. Сервис должен быть доступен по адресу https://localhost:8543/external-data/300 .  Этот сервис также был создан с помощью Spring Initializer. В нем два основных класса: ExternalService и ExternalServiceClient. Класс ExternalService читает данные из сервиса External Service с помощью externalServiceClient и вычисляет сумму. Для чтения данных из external service класс ExternalServiceClient использует библиотеку openfeign. Реализация HTTP-клиента на основе OKHttp выглядит следующим образом: Запустите класс FacadeServiceApplication и перейдите на  http://localhost:8080/data/1,500,920,20000. Ответ будет следующим: Запустите Jmeter 5.3.1 и откройте файл perfomance-testing.jmx в корне проекта. Конфигурация теста: Нагрузочный тест будем проводить по следующему URL-адресу: http://localhost:8080/data/1,500,920,200  Перейдите в Jmeter и запустите тест. Сервер стал недоступен. Это связано с тем, что в ExternalService мы использовали parallelStream(). Stream API для параллельной обработки данных использует ForkJoinPool. А по умолчанию параллелизм ForkJoinPool рассчитывается на основе количества доступных процессоров. В моем случае их три. Для операций ввода-вывода это узкое место. Итак, давайте увеличим параллелизм ForkJoinPool до 1000. И запустим Jmeter еще раз. Как вы видите, пропускная способность (throughput) увеличилась с 6 до 26 запросов в секунду. Это хороший результат. Кроме того, сервис работает стабильно без ошибок. Но тем не менее среднее время (average time) составляет 9 секунд. У меня есть предположение, что это связано с затратами на создание HTTP-соединение. Давайте добавим пул соединений: Таким образом, приложение может поддерживать до 2000 HTTP-соединений в пуле в течение 10 секунд. Пропускная способность улучшилась почти в три раза: с 26 до 71 запросов в секунду. В целом пропускная способность улучшилась в 10 раз: с 6 до 71 запросов / сек, но мы видим, что максимальное время запроса (maximum time) составляет 7 секунд. Это много и влияет как на общую производительность, так и на задержку в UI. Поэтому давайте ограничим количество обрабатываемых запросов. Сделать это можно, используя указанные ниже свойства Tomcat в application.properties: Приложение будет отклонять запросы на подключение и отвечать ошибкой "Connection refused" (отказ соединения) всем клиентам, как только количество подключений достигнет 160. Теперь максимальное время составляет меньше пяти секунд и число запросов увеличилось с 71 до 94 запросов в секунду. Процент ошибок ожидаемо увеличился до 29%. Это все ошибки "Connection refused".  В этой статье мы продемонстрировали реальный сценарий повышения производительности в 15 раз с 6 до 94 запросов / сек без каких-либо сложных изменений кода. Кроме того, упомянутые выше шаги позволяют снизить стоимость инфраструктуры, такой как AWS. Возможно, для вашего следующего проекта вам стоит подумать об использовании микросервисов. Хотя одна из тенденций последних лет — переход к бессерверной архитектуре, но вы должны всё взвесить при переходе к такой архитектуре. Мы рассмотрели общий подход к улучшению производительности Java-приложений, который вы можете использовать на практике. Однако в статье не рассматриваются некоторые специфичные случаи, такие как работа с базами данных. В мире Java-микросервисов есть еще много места для открытий и экспериментов. Узнать подробнее о курсе "Highload Architect". Смотреть открытый вебинар по теме «Репликация как паттерн горизонтального масштабирования хранилищ».  Редактор