(java || kotlin) && devOps
368 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Нашел пару статей на тему автоматической валидации настроек Spring Boot, как средствами IDEA, так и в runtime. Работает для yaml и properties форматов.

Для авподополнения в IDEA используется spring-boot-configuration-processor, который сканируется файлы с Spring аннотацией @Configuration и формирует необходимые метаднные. Также можно создавать руками, полезно для чужого кода
https://www.baeldung.com/intellij-resolve-spring-boot-configuration-properties

В runtime это делается через Jacarta Bean Validation API https://beanvalidation.org/, самая известная реализация Hibernate Validator https://hibernate.org/validator/ Кстати, несмотря на название к ORM библиотека прямого отношения не имеет.
Детали см. https://habr.com/ru/post/505628/
Если не хватает возможностей аннотаций из Validation API можно даже валидацию в коде описать, с помощью Spring Validator https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/Validator.html

Как по мне - полезная штука, рекомендую использовать, позволяет быстрее обнаружить ошибки.

#spring_boot #java #IDEA #validation
Всем привет!

В разработке сейчас много хайповых понятий, те же микросервисы, Service Mesh, GitOps, Serverless. Обо всем этом как-нибудь напишу, а сегодня пару мыслей про Cloud Native.

Если подумать, то для того, чтобы сделать native приложение для облака, нужно не так уж много.

1) k8s должен как-то понимать, что приложение поднялось и может принимать траффик. Для этого облачный сервис должен реализовать probes, они же healthchecks.
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
Вообще их три, но в случае простейшего приложения хватит одной - liveness. Остальные две нужны если приложение долго стартует - startup или может быть недоступно в процессе работы - readyness.

2) облачное приложение не должно долго стартовать. Причина: k8s при добавлении новых нод или подов, или изменения их настроек Anti-affinity (возможности совместной работы на одной ноде) в любой момент может погасить под и поднять его на другом сервере. Да, можно указать startup probe чтобы траффик не шел на долго стартующее приложение. Можно указать maxUnavailable https://kubernetes.io/docs/tasks/run-application/configure-pdb/ для того, чтобы k8s оставлял запас подов при изменении их численности. Но все это обходные пути. Если вспомнить про Spring Boot, то я бы сказал что ему есть куда расти в плане оптимизации, не зря сейчас растет популярность его альтернатив, стартующих существенно быстрее: Quarkus, Micronaut, Helidon и использования native images.

3) cloud native приложение не должно зависеть от локального состояния - кэширования данных локально. Все критичные для работы данные должны хранится или в storage, или на клиенте. Причина все та же - k8s в любой момент может поднять под на другом сервере, локальный кэш при этом теряется.

4) для cloud native приложения крайне рекомендуется отбрасывать метрики и поддерживать distributed tracing - https://opentelemetry.io/docs/concepts/what-is-opentelemetry/. Причина: перенос в облако упрощает разработку, как правило идет рука об руку с микросервисами, следовательно, сервисов становится существенно больше, следовательно, должны быть инструменты для отслеживания их состояния и более точного понимания, где проблема.

Что на мой взгляд не относится к критичным требованиям для Cloud native приложений.

1) поддержка Docker. В Docker можно засунуть практически любое приложение, есть куча официальных образов. Даже IBM Websphere и WildFly, хотя использование их в облаке выглядит странным) Вижу проблему только с Windows native приложениями, но их остается не так уже много

2) поддержка внутри приложения cloud \ fault tolerance функций: circuit breakers, retries, timeouts, service discovery. Например, этот функционал реализуется в Spring Cloud библиотеке. Почему так? Потому что в связке k8s + service mesh все эти функции можно реализовать на уровне облака. Не хочу сказать, что Spring Cloud и его аналоги не нужны, но точно не обязательны для облака.

3) использование REST API. С одной стороны для HTTP траффика k8s + service mesh дает больше возможностей по маршрутизации, но с другой стороны tcp трафик тоже маршрутизируется.

#cloud_native #microservices #spring_boot #tracing
Всем привет!

Интересная статья про динамическую перезагрузку properties https://www.baeldung.com/spring-reloading-properties в Java приложении.
Два варианта:
1) Apache Сommons Сonfiguration
2) Spring Cloud
Первое работает через отслеживание изменений в файле, второе - управляемое извне перечитывание после вызова /refresh endpoint.

#java #cloud #spring_boot
Всем привет!

У любого Spring Boot приложения есть настройки. В базовом варианте они хранятся в application.yaml файле. Но вообще говоря алгоритм, по которым Spring ищет эти настройки достаточно сложный. Вот тут https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config и вот тут https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files он описан детальнее.
Когда это "тайное знание" может быть полезно - если нужно задать настройки по умолчанию или, наоборот, переопределить их. Или разобраться - откуда тянется та или иная настройка.

#spring_boot #spring
Всем привет!

Чем хорош Spring Framework?
1) Inverse of Control и Dependency Injection
2) Очень много модулей-адаптеров к различным технологиям: Data, Data Kafka, Web MVC, WebFlux, Security, Statemachine, Cloud ... с упрощенным и насколько это возможно единообразным API.
Но это не все.
Но Spring приходит на помощь и там, где его не особо ждали) Хочу рассказать о менее известном, но полезном функционале Spring:
1) Расширенный маппинг Enum при передаче значений через REST API: https://www.baeldung.com/spring-boot-enum-mapping
2) Улучшение логирования при падении Spring Boot при старте - все эти bean not found exception: https://www.baeldung.com/spring-boot-failure-analyzer
3) Централизованная обработка ошибок: https://www.baeldung.com/exception-handling-for-rest-with-spring

#spring #spring_boot
Всем привет!

Продолжим рассказ про разные способы ускорения Java. Для начала я бы разделил ускорение в целом на 4 более конкретных направления:
1) ускорение запуска приложения за счет оптимизации\отмены первоначальной загрузки классов
2) ускорение выхода приложения на оптимальную производительность путем оптимизации JIT - Just In Time - компиляции байт-кода в нативный
3) ускорение запуска и в какой-то степени выполнения приложения за счет более легковесного фреймворка, используемого для разработки приложения
4) оптимизация сборщика мусора для достижения нужного баланса между затрачиваемыми ресурсами и паузой в обслуживании клиентских запросов, она же Stop the World

Сегодня поговорим про первое направление. С одной стороны упомянутые ранее и native image, и CRaC тоже ускоряют запуск. Но обе технологии имеют ограничения. native image запрещает reflection и динамическую загрузку классов. Образ, сохраненный с помощью CRaC, может содержать что-то лишнее, и с данной технологией нельзя просто так перезапустить приложение при сбое - т.к. возможно причина сбоя лежит в данных, подгруженные из образа.

Начну издалека.
В Java 5 появилась вот такая фича - https://docs.oracle.com/en/java/javase/21/vm/class-data-sharing.html Class-Data Sharing, сокращенно CDS.
Фича появилась и была забыта. Есть такие фичи, про которые все забывают сразу после релиза новой Java) Еще модульность из Java 9 можно вспомнить.

О чем эта фича? Мы записываем в файл метаданные загруженных классов из classpath. Потом этот файл мапился в память работающей JVM. Зачем? Цели было две:
1) расшаривание классов между несколькими инстансами JVM и т.об. уменьшение потребления RAM
2) ускорение запуска (вот оно!)

Вначале фича работала только с классами Java core. Файл с архивом классов Java core входит в состав JDK, найти его можно по имени classes.jsa. Занимает на диске сравнительно немного - 10-15 Мб. И кстати, CDS в Java включена по умолчанию, используется как раз этот файл.

Позже, в Java 10 https://openjdk.org/jeps/310 появилась возможность дампить и пользовательские классы, эту фичу назвали AppCDS. В Java 13 создание архива было упрощено https://openjdk.org/jeps/350
Пользовательские классы можно добавить в архив предварительно запустив процесс со специальной опцией командной строки -XX:ArchiveClassesAtExit

А если у нас Spring? Ребята в Spring 6.1 обратили внимание на данную опцию и добавили ключ командной строки, позволяющий собрать информацию о динамически загружаемых классах именно для Spring Boot приложения https://docs.spring.io/spring-framework/reference/integration/cds.html
А еще дали рекомендации, как максимально точно собрать информацию о классах и подтвердили, что данная опция ускоряет загрузку на ~30% https://spring.io/blog/2023/12/04/cds-with-spring-framework-6-1 Почему подтвердили - именно такую цель ставили разработчики CDS в JEP 310, упомянутом выше.

Итого - идея в чем-то похожа на Profile-Guided Optimization. Только здесь мы предварительно собираем информацию не об использовании кода, а о загруженных классах. Чем больше информации соберем - тем быстрее будет старт приложения. Минусы - версия JDK, Spring и classpath в целом должны совпадать при тестовом прогоне и использовании в ПРОМе.


#jre #performance #spring_boot #spring #java_start_boost