Как я создал 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 для разбора загрузки замедлившихся сервисов и помогло обнаружить несколько классов с неоптимальной логикой в конструкторах.

Ссылки

Analyzer: https://alexey-lapin.github.io/spring-boot-startup-analyzer

Demo Spring Boot App: https://realworld-backend-spring.herokuapp.com/actuator/startup

GitHub: https://github.com/alexey-lapin/spring-boot-startup-analyzer

DockerHub: https://hub.docker.com/r/lexlapin/spring-boot-startup-analyzer

Источник: https://habr.com/ru/company/luxoft/blog/585662/


Интересные статьи

Интересные статьи

Настройка любой площадки для CMS — это рутинный процесс, который должен быть доведен до автоматизма в каждой уважающей себя компании. А потому частенько воспринимается, как восход солнца — это происхо...
Искать утечки и уязвимости в своих продуктах не только интересно и полезно, но и необходимо. Еще полезнее подключать к таким поискам внешних специалистов и энтузиастов, у которых не ...
Всем привет, меня зовут Олег, я техлид в ДомКлике. В нашей команде ядром стека является Kotlin и Spring Boot. Хочу поделиться с вами своим опытом по взаимодействию и особенностях ра...
Речь пойдёт о способе защиты програмного обеспечения, который реализован в самом процессоре. В качества экспериментов я выбрал мультимедиа приставку Comigo Quattro. Цель — запустить своё ядро лин...
На сегодняшний день у сервиса «Битрикс24» нет сотен гигабит трафика, нет огромного парка серверов (хотя и существующих, конечно, немало). Но для многих клиентов он является основным инструментом ...