Как я создал Spring Boot startup analyzer

Ни для кого не секрет, что приложения на Spring могут задумываться на старте. Особенно это заметно с развитием проекта: новый сервис стартует быстро и радует отзывчивостью, потом начинает обрастать функционалом, появляются всё новые и новые зависимости, а итоговый дистрибутив распухает на десятки мегабайт. И вот, для того чтобы просто запустить этот сервис локально, приходится ждать полминуты, минуту, две… В такие моменты ожидания у разработчика могут возникнуть вопросы: почему же так долго? что там такого происходит под капотом? может, не нужно было добавлять ту библиотеку?

Всем привет, меня зовут Алексей Лапин, я ведущий разработчик в Luxoft. В статье расскажу про инструмент в виде веб-приложения для анализа фазы старта сервисов на Spring Boot, использующий данные actuator startup endpoint. Это может помочь ответить на вопросы выше.

Небольшое введение

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

Spring Boot Startup Endpoint

Начиная с версии 2.4 в Spring Boot появилась реализация ApplicationStartup, записывающая события, произошедшие во время старта сервиса, и actuator endpoint, возвращающий список этих событий.

Ответ данного endpoint (/actuator/startup) выглядит следующим образом:

{ "springBootVersion": "2.5.3", "timeline": { "startTime": "2021-09-06T13:38:05.049490700Z", "events": [ { "endTime": "2021-09-06T13:38:05.159435400Z", "duration": "PT0.0898001S", "startTime": "2021-09-06T13:38:05.069635300Z", "startupStep": { "name": "spring.boot.application.starting", "id": 0, "tags": [ { "key": "mainApplicationClass", "value": "com.github.al.realworld.App" } ], "parentId": null } }, ... { "endTime": "2021-09-06T13:38:06.420231Z", "duration": "PT0.0060049S", "startTime": "2021-09-06T13:38:06.414226100Z", "startupStep": { "name": "spring.beans.instantiate", "id": 7, "tags": [ { "key": "beanName", "value": "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory" } ], "parentId": 6 } }, ... ]
….}
}

Подробное описание всех полей сообщения можно найти в документации Spring Boot Actuator, но все названия и так говорят сами за себя. У события есть id и parentId, что позволяет создать древовидное представление. Также есть поле duration, показывающее время, затраченное на событие + сумму времён всех дочерних событий. Поле tags содержит список атрибутов события, например имя или класс создаваемого bean.

Для того чтобы активировать сбор данных о событиях загрузки, необходимо передать экземпляр класса BufferingApplicationStartup в метод setApplicationStartup у SpringApplication. В данном случае используется конструктор, принимающий количество событий для записи. Все события сверх этого предела будут проигнорированы и не попадут в выдачу startup endpoint.

@SpringBootApplication
public class App { public static void main(String[] args) { SpringApplication application = new SpringApplication(App.class); application.setApplicationStartup(new BufferingApplicationStartup(1000)); application.run(args); }
}

По умолчанию данный endpoint имеет путь /actuator/startup и поддерживает методы GET для получения событий и POST для получения событий и очистки буфера, так что последующие обращения в этот endpoint вернут пустой список событий.

Таким образом информацию, выдаваемую startup endpoint, будем считать источником данных для анализа. Веб-приложение-анализатор представляет из себя SPA (Single Page Application) без бэкенда. В него нужно загрузить события, произошедшие во время запуска сервиса, а оно построит их визуализацию. Загруженные данные никуда не передаются и нигде не сохраняются.

Для реализации был выбран язык Typescript, так как он кажется более привлекательным вариантом для Java-разработчика по сравнению с Javascript из-за привычной строгой типизации и множества ООП возможностей. Мне показалось, что было очень легко переключиться с Java на Typescript и быстро написать работающий код. В качестве фреймворка для построения UI был выбран VueJS 3. Я не имею ничего против React, Angular и других представителей фронтенд-ландшафта, однако на данный момент VueJS показался хорошей опцией ввиду низкого порога вхождения и отличного набора инструментов из коробки. Следующим шагом была выбрана библиотека компонентов. От неё требовалась совместимость с VueJS 3 и наличие компонентов для работы с таблицами. Рассматривались Element Plus, Ionic Vue, NaiveUI, но из-за наличия кастомизируемых компонентов для работы с таблицами была использована библиотека PrimeVue.

Приложение имеет строку навигации с элементами Analyzer (это главный экран приложения), Usage (инструкцией по использованию) и ссылкой на GitHub-репозиторий проекта.

На главной странице приложения отображается форма с тремя способами ввода данных для анализа. Первый способ позволяет указать ссылку на развёрнутый сервис Spring Boot. В этом случае будет сделан http-запрос в указанный endpoint и данные автоматически загрузятся для визуализации. Данный способ применим для случаев, когда сервис доступен из интернета или поднят локально. Также для загрузки по url может потребоваться дополнительная конфигурация сервиса в части CORS-заголовков и Spring Security. Второй и третий способы — это загрузка json-файла или напрямую его контента.

Развёрнутое приложение находится по адресу https://alexey-lapin.github.io/spring-boot-startup-analyzer

В качестве демонстрации работы анализатора используется мой сервис Spring Boot, развёрнутый на Heroku. Этот сервис реализует бэкенд проекта RealWorld (https://github.com/gothinkster/realworld). Нужный endpoint можно найти по адресу https://realworld-backend-spring.herokuapp.com/actuator/startup. Сервис сконфигурирован таким образом, чтобы отправлять корректные CORS-заголовки на GET-запросы от анализатора. 

После загрузки событий с помощью одного из способов данные визуализируются в виде древовидной структуры. При этом все строки, имеющие дочерние элементы, скрыты. Для навигации по этому дереву можно использовать иконки > слева от идентификатора записи, либо сразу раскрывать или скрывать все записи, используя кнопки Expand All / Collapse All.

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

В табличном виде сразу отображаются все события. При этом все колонки, кроме Tags, сортируются.

CI + хостинг

На одном из предыдущих проектов я был вовлечён в глобальную DevOps-трансформацию организации и решал задачи по автоматизации процессов релизного цикла и выстраиванию CI/CD-пайплайнов. Это был интересный опыт, который сейчас помогает разрешить вопросы, касающиеся написания исходного кода продукта. В данном случае, как и для большинства моих OSS-проектов, в качестве git-хостинга используется GitHub, предоставляющий множество полезных инструментов для CI, хранения артефактов, документации, project management, хостинга статических сайтов и множество других. Для нужд анализатора были использованы Actions и Pages.

GitHub Actions настроен на автоматическую сборку проекта по созданию pull request, commit в master и push тэга. При этом по push тэга также произойдёт развёртывание собранного проекта на GitHub Pages, а также сборка Docker-образа и отправка его на DockerHub.

В дополнение к общедоступному инстансу анализатора на GitHub Pages (https://alexey-lapin.github.io/spring-boot-startup-analyzer) есть возможность использования Docker образа на основе Nginx (https://hub.docker.com/r/lexlapin/spring-boot-startup-analyzer). Это может быть полезно, например, для тех случаев, когда сервисы Spring Boot находятся во внутренней сети организации, из которой нет доступа в интернет, но есть Docker и есть возможность загрузить образ.

Для запуска контейнера нужно выполнить следующую команду:

docker run -d --name sbsa -p 8080:80 lexlapin/spring-boot-startup-analyzer

Если есть необходимость обращаться к этому контейнеру через reverse proxy, то для этого предусмотрена возможность передачи пути через переменную среды (UI_PUBLIC_PATH):

docker run -d --name sbsa -p 8080:80 -e UI_PUBLIC_PATH=/some-path lexlapin/spring-boot-startup-analyzer

Что улучшить

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

Заключение

Предлагаемый анализатор позволяет в удобной форме визуализировать данные, полученные от actuator startup endpoint, детально оценить время, затраченное на различные типы событий, происходящих во время старта сервиса, и в целом эффективнее обработать startup-информацию. Приложение имеет публичный инстанс на GitHub Actions, а также доступно в виде Docker-образа. Данное приложение было успешно применено на одном из проектов Luxoft для разбора загрузки замедлившихся сервисов и помогло обнаружить несколько классов с неоптимальной логикой в конструкторах.

Ссылки

Читайте так же:

  • Ускорение сайта путём выявления проблемных участков кода: xDebug + phpStormУскорение сайта путём выявления проблемных участков кода: xDebug + phpStorm Привет, Хабр! Это мой первый пост, поэтому поделюсь с вами кейсом ускорения работы одного сайта на WP + WooCommerce. Сам занимаюсь веб-разработкой, последние два года только на фрилансе. Не претендную на идеальную статью, я сам каждый день учусь новому, но в статье максимально стараюсь […]
  • Meta прогнозирует потери от Apple ATT на уровне $10 млрд в 2022 годуMeta прогнозирует потери от Apple ATT на уровне $10 млрд в 2022 году По оценкам Meta, изменения в правилах отслеживания на iOS сократят доходы компании примерно на $10 млрд в 2022 году. Об этом говорится в отчете за четвертый квартал 2021 года. «Мы считаем, что влияние iOS в целом станет сдерживающим фактором для нашего бизнеса в 2022 году. Это порядка […]
  • Видеокарты опять начали дорожатьВидеокарты опять начали дорожать Согласно информации ресурса Videocardz, новый анализ рынка компьютерных комплектующих в Германии показывает, что цены на видеокарты снова начали подниматься после месяца затишья и предшествующего этого небольшого снижения. Пользователи опять не могут купить графические адаптеры по […]
  • Google закрыл функцию «Вопросы и ответы» в поискеGoogle закрыл функцию «Вопросы и ответы» в поиске Google официально отказался от функции вопросов и ответов в результатах поиска. Об этом сообщает западное издание Search Engine Land со ссылкой на представителей компании. Функция была запущена в Индии в 2019 году.  После закрытия функции вопросов и ответов пользователи не смогут […]