Верхняя полка📝
362 subscribers
284 photos
11 videos
3 files
145 links
Путевые заметки программного инженера и легкоатлета-любителя.

Автор: Владимир @Toparvion Плизга

Домашняя страница: https://toparvion.pro/
Download Telegram
В блоге компании AxiomJDK на Хабре позавчера вышла статья Алексея Рагозина о работе с JDK Flight Recorder'ом из командной строки. Фишка статьи в том, что она не только рассказывает, как запускать/мониторить/останавливать записи JFR, но и как смотреть их результаты прямо на лету, т.е. без дампа в файлы с последующим открытием. Мне довелось немного поучаствовать в подготовке этой статьи; в основном, как рецензенту 🤓

Если кто не знает, Алексей — один из топовых российских экспертов по производительности JVM. Он пишет глубокие технические статьи, выступает с докладами, ведёт тренинги и сам разрабатывает инструменты для диагностики JVM. Кстати, его проект SJK (Swiss Java Knife) используется, например, в Apache Cassandra 💪🏼

Послезавтра, 13 ноября в 19:00 МСК Алексей проведёт открытый вебинар по работе с JFR из командной строки, но в отличие от статьи, там будет возможность в живую увидеть пример применения JFR к приложению на #Java 25, включая совсем свежие улучшения, вышедшие в этой версии в сентябре. Кто хочет быть на гребне прогресса, подключайтесь 📺
🔥9
В продолжение темы про JFR ✈️

Вчера разбирался с забористым багом — барахлила асинхронная связь между двумя модулями приложения (на одной JVM): один обновлялся, а второй не всегда. Помимо нестабильности воспроизведения дело усложнялось тем, что проблема стреляла только на удалённом сервере заказчика. Короче, всё по классике😏

При помощи ряда экспериментов, интуиции и такой-то матери мне удалось выяснить, что один из асинхронно выполняемых методов прерывается из-за какого-то исключения. Но этого исключения не было в логах, потому что в методе не предусмотрели try/catch, а сам метод вызывался так:
executorService.submit(this::fireBatchedEvents)

, то есть отправлялся на исполнение в пул безо всякой обратной связи (что уже не хорошо, но это отдельная тема✍️)

И вот ситуация:
— исключение есть
— логов нет
— добавить логирование в код нельзя, потому что после перезапуска проблема опять перестанет повторяться.
"И как теперь что?" 🫤 (© Масяня)

К счастью, внутри JVM на выбросы исключений заведено отдельное событие для JDK Flight Recorder, оно называется jdk.JavaExceptionThrow. Если его включить и провести запись JFR во время проявления проблемы, то в ней (в записи) должны осесть данные обо всех исключениях, даже если само приложение их "глотает" 😋

Запуск записи в моём случае выглядел так:
./jattach <PID> jcmd JFR.start settings=none +jdk.JavaExceptionThrow#enabled=true +jdk.JavaExceptionThrow#stackTrace=true

, где:
jattachутилита для подключения к JVM, когда под рукой только JRE, а не JDK (в частности, нет jcmd);
jcmd JFR.start settings=none — команда на старт записи с полностью выключенными событиями (чтобы не писать лишнего);
+jdk.JavaExceptionThrow#enabled=true — флаг включения события JavaExceptionThrow. Символ "+" здесь нужен потому, что мы не меняем значение какой-то настройки из параметра settings (там же none), а добавляем его;
+jdk.JavaExceptionThrow#stackTrace=true — флаг добавления стектрейсов к регистрируемым событиям; по умолчанию он снят, а без стектрейсов смотреть на исключения скучно.

После старта записи я выполнил в приложении проблемное действие, а потом остановил запись вот таким заклинанием:
./jattach <PID> jcmd JFR.stop name=1 filename=error.jfr

, где:
jcmd JFR.stop name=1 — команда на останов конкретной записи (их может быть несколько). Имя записи можно либо задать явно при её запуске, либо посмотреть назначенное в ответе команды JFR.start 🚀

На выходе получился файл error.jfr, открыв который в Java Mission Control, удалось быстро отыскать пропавшее исключение и, главное, увидеть его стектрейс (хотя всего их там оказалось аж 320😳)

Кажется, это неплохой пример применения JFR в сложной ситуации. Если бы не помог и он, можно было бы расчехлить BTrace, но давайте останемся в рамках приличия 🤭
🔥174👍4
Увидимся на Подлодке 🌊

В следующую среду, 19 ноября с 10:00 до 11:00 МСК будем общаться онлайн с ребятами из конференции Podlodka #Java Crew:
Интервью «Эволюция инструментов диагностики в Java»
В формате интервью поговорим с Владимиром про различные способы диагностики проблем производительности в Java, такие как JFR, NMT, Heap и Thread дампы, профилирование. Обсудим новшества в этой области, а также то, какие проблемы и тренды есть сейчас.

Всем, кому интересна тема анализа производительности и поиска "узких мест" в коде нагруженных приложений — милости просим 🙌🏼
5🔥2
🎞 Новые полезные видео по #Java Performance

1. Вебинар про JFR @ CLI
Опубликована запись недавно упоминавшегося здесь вебинара Алексея Рагозина по работе с JFR из командной строки. Помимо наглядности, видео интересно обилием всяких неочевидных фишечек, например, что целевой процесс для команды jcmd можно указать не только по старинке через его PID, но и простым именем главного Java-класса (в котором объявлен метод main). Для тех отважных, кто решится повторить эксперименты вебинара самостоятельно, Алексей оставил небольшую текстовую инструкцию — всего-то 57 шагов 🫠

2. Интервью про инструменты диагностики в Java
Недавно анонсированное мною интервью на онлайн-конференции Podlodka Java Crew состоялось — там я рассказывал об инструментах диагностики Java-приложений и их новшествах. Здорово и приятно, что моим интервьюером был Дмитрий Константинов, по докладам которого я сам ещё недавно постигал премудрости чтения и записи в Cassandra. В ходе разговора мы затронули самые разные темы, начиная от древних как мир дампов потоков и заканчивая новейшими JEP'ами и применениями AI. Плюс к тому поговорили об обновлениях не только встроенных инструментов JDK (таких как JFR и NMT), но и популярных сторонних: async-profiler, Eclipse MAT, VisualVM. И хотя это было именно интервью, а не доклад, в ходе ответов я старался многое демонстрировать, поэтому запись желательно не только слушать 👀

Приятного просмотра! 🍿
👍6🔥43
Пост-выходной впрыск новостей про #спорт

Вдохновленный своим относительно успешным прохождением Томского лыжного марафона (50 км коньковым ходом) в марте этого года, я решил не бросать это гиблое дело и выбрал новую цель — купил слот на аналогичный марафон, только уже в Кемерово, 14 марта. Старт называется KuzbasSki 🎯

Ту дистанцию в марте удалось "оформить" за 2:55:56 — во многом благодаря отличной погоде и сравнительно небольшому набору высоты (≈470 м). А вот на Кузбассе получить такой результат удастся едва ли, так как с погодой там часто бывают "сюрпризы", да и рельеф куда более забористый — набор ≈800 м 🏔

Но я всё продумал: специально взял слот заранее, чтобы не только успеть как следует подготовиться, но и передумать и слиться, а у вас было время забыть про этот пост и потом не срамотить меня за него🤪
👍9😁1
Как быстро растут детишки фреймворки 🌱

Кажется, ещё недавно я рассказывал со сцены на Joker в Петербурге о граблях обновления #SpringBoot c версии 1 на 2. Но оказывается прошло семь лет, и вот намедни был объявлен официальный релиз версии Spring Boot 4.0. Любопытно, что в этот же день на онлайн-конференции Подлодка был доклад про переход на эту версию; ребята здорово подгадали 👨‍🏫

В документе Spring Boot 4.0 Release Notes одной из первых идёт весьма обтекаемая формулировка:
... upgrading existing applications can be a little more involved that usual.

Как изящно они обошли фразу "вы офигеете разгребать поломки", не правда ли? 😉

Впрочем, наверняка опыт у всех будет разным. Судя по текущему Migration Guide, который в эти жаркие дни обновляется чуть ли не каждые несколько часов, основное веселье предстоит со стартерами ("кирпичиками" в Spring Boot), в том числе тестовыми, потому что одним из главных изменений в этой мажорной версии стала модуляризация фреймворка 🧱

Кроме того, похоже, не обойдётся и без развалов на этапе компиляции, так как многие классы разъехались по модульным пакетам, именуемым как org.springframework.boot.<module>. Конечно, умная InetlliJ IDEA, скорее всего, быстро подскажет, на что нужно поменять импорты, но если в проекте много явных обращений к классам Spring Boot, потыкаться всё равно придётся 👉

К счастью, такое масштабное обновление касается очень многих проектов, поэтому для него уже написана стопка рецептов на OpenRewrite, которая так и называется — Migrate to Spring Boot 4.0. По идее, она должна очень сильно упростить весь процесс, сведя его, по сути, к трём шагам:

1️⃣ Прописать в скрипте сборки рецепт (на примере build.gradle):
plugins {
id("org.openrewrite.rewrite") version("latest.release")
}
rewrite {
activeRecipe("org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0")
setExportDatatables(true)
}
dependencies {
rewrite("org.openrewrite.recipe:rewrite-spring:6.19.0")
}


2️⃣ Запустить автомиграцию командой gradle rewriteRun.

3️⃣ Отревьюить получившиеся изменения и заставить их работать (чертыхаясь и понося уже не себя, а умный скрипт).

Какой способ обновления лучше — вручную или автоматически — каждый решает сам.
Но какой бы вы не выбрали, после завершения напишите, пожалуйста, в комментариях к посту или в ЛС, как у вас всё прошло — попробуем вместе собрать реальную картину обновлений 🖼
12🔥1
Любопытно и порой не очень весело наблюдать за развитием некоторых программных инструментов. Например, когда-то я искал, на чём делать свою домашнюю страничку, и остановил выбор на Academic — шаблоне для сайтогенератора Hugo.
Выбрал, в том числе за простоту.
И вот как она преобразилась со временем (даты примерные, но состав точный)👇

Для локальной работы с сайтом на HugoBlox (ex. Wowchemy, ex. Academic) нужно:
2018: Hugo
2019: Hugo Extended
2021: Hugo Extended + Go
2023: Hugo Extended + Go + NodeJS
2025: Hugo Extended + Go + NodeJS + Tailwind CSS

Что дальше? Python? Rust? BrainF*ck?
Это ведь всё те же статически отдаваемые странички... Казалось бы 🤨
😁6
This media is not supported in your browser
VIEW IN TELEGRAM
Рубрика "Век живи, век учись" 🎓

Не первый год работаю на #Linux, но когда нужно вызвать недавнюю команду в консоли, по привычке либо тыкаю стрелку вверх, пока команда не появится, либо пишу что-то типа history | grep <что-то>. А тут на днях случайно нажал в консоли Ctrl+R (думал, что нахожусь в браузере) и увидел странное сообщение reverse-i-search. Стал гуглить, что это такое, и ахнул 🤩

Оказывается, это режим, в котором можно начать писать что угодно, и он будет выводить команды из истории, в которых содержался вводимый текст. Листать варианты можно как в обратном порядке (тем же Ctrl+R), так и в прямом (Ctrl+S). Когда команда найдена, остается только жмакнуть Tab либо Enter, в зависимости от того, нужно её поправить перед выполнением или нет ▶️

Как выяснилось, это довольно древняя фича, которая есть практически во всех оболочках (bash, zsh и других). Теперь уже не понимаю, как жил без неё раньше🤓
👍14🔥4
Сегодняшнее рабочее утро началось с необходимости повторной аутентификации в Telegram на всех устройствах, причем где-то двух-факторной, а где-то и трёх (даже не знал, что здесь такое бывает)🥴

Вторым неприятным сюрпризом оказалась заморозка аккаунта моего Telegram-бота для поиска своих фотографий в больших альбомах (про него здесь был отдельный пост). При этом ни @SpamBot, ни @BotFather ничего о заморозке не сообщают, равно как и не было сервисных уведомлений от самого Telegram 🤷‍♂️

Поэтому в качестве оперативной меры бот перезапущен под новым ником: @FramePhotoAlbumBot 🤖

Если кто-то в курсе, что происходит, расскажите, пожалуйста 👀
🤔8😱2
Кастомные JFR события в дикой природе 🦒

На моем тренинге по #JFR мы с участниками, кроме прочего, учимся делать собственные JFR события, чтобы эммитить их прямо из бизнес-логики, а потом анализировать так же, как встроенные события JVM. И хотя я стараюсь объяснять, зачем это надо, в воздухе нередко остаётся висеть незаданный вопрос участников: "А зачем бы я применил(а) это у себя в проекте?" 🧐

Делюсь свежим примером из своей практики 👇

Когда-то я рассказывал вам, что мы пилим свой условный аналог Excel на платформе AggreGate. Сейчас на этом решении наш партнёр реализует огромный проект для заказчика, и движок вычислений там используется в полный рост, потому что хотелки у заказчика тоже не слабые:
десятки больших таблиц
сотни тысяч ячеек в них
≈280К узлов в графе связей между ячейками разных таблиц 🕸

Ну и конечно же на этом фоне к нам в JIRA стали периодически поступать тикеты с интригующими заголовками в духе: "У нас где-то что-то когда-то почему-то не посчиталось/не обновилось/не сбросилось, но мы не поняли, где, когда и почему. Разбирайтесь😘"

Как вы наверняка догадываетесь, логировать вычисления в таких масштабах, а потом купаться в этих логах (или выгружать их в какой-то парсер-анализатор) — затея трудоёмкая и малоперспективная. Но видеть ход вычислений в точности до ячеек всё же надо. То есть нужен максимально простой, дешевый (с т.з. overhead'а) и пригодный для анализа результатов способ как-то фиксировать вычисления ✍️

И тут я снова вспомнил про кастомные события JFR, ведь у них очень простой, но при этом гибкий API, они весьма дешевы в эмиссии и хранении, а их анализ в Java Mission Control хоть и не так мощен, как какой-нибудь Logstash+Kibana, но всё же на порядок удобнее, чем с логами 🧶

Я завёл класс с описанием вычисления (см. скриншот 1) и стал эмитить с ним JFR события в двух местах:
— при инициации вычислений (на пользовательском вводе или открытии готовой таблицы)
— и при обновлении по слушателю (когда пересчёт одной ячейки аффектит другую).
Это позволило регистрировать 100% вычислений 💯

Зная масштабы проекта, я опасался, что JFR записи будут огромными и с ними будет тяжело работать, поэтому воспользовался фичей JFR API по добавлению кастомных настроек — поддержал фильтрацию регистрируемых вычислений по диапазону ячеек в обычной нотации Excel, например, sheet_a!B5:F16 (скриншот 2). Но моему к приятному удивлению, это оказалось лишним: недавно коллеги по запарке оставили JFR-запись включенной без этого фильтра на 21 час, и в неё набежало 303 000 событий, а получившийся JFR файл весил 105 МБ. При этом он без труда открылся в JMC, а работать с ним было также легко, как и с маленьким (скриншот 3) 🌿

Любопытно, что изначально я планировал управлять этой диагностикой через утилиту jattach, но в закрытый контур заказчика втащить даже безобидную jattach оказалось нельзя (небезопасно типа). Тогда мне пришлось извернуться и написать на платформенном low-code-языке функции, которые через JFR API дёргают методы запуска/останова записи, да еще и конфигурируют нужные события. Как ни странно, функции получились довольно компактными и сработали чётко, а в качестве бонуса их вызов удалось вывести прямо в UI-интерфейс платформы для удобства администраторов 👷🏼

Теперь мы этим активно пользуемся, и когда приносят очередную задачу по проблеме вычислений, знаем, с чего начинать анализ 🕵️‍♂️

Конечно, сама по себе диагностика на JFR-событиях сложные/редкие/заковыристые проблемы не решает. Но она прокладывает очень важный и довольно длинный кусочек мостика между "Черт возьми, что здесь вообще происходит!?" и статусом тикета "Resolved (Fixed)"
👍9🔥1
На втором часу общения с ChatGPT о том, почему у меня на Linux после обновления видеодрайвера на фиг отвалились все сетевые устройства 🥴
🤣14💯1
Forwarded from SnowOne-канал
Всем привет!

До конца года остается чуть меньше двух недель, а мы к вам уже с подарками 🎁

Во-первых, мы опубликовали новых прекрасных спикеров на сайт. Во-вторых, теперь это не просто имена, а темы и тезисы докладов!

Давайте посмотрим, что уже есть в программе SnowOne 2026:

1) Секция "Enterprise":

Сергей Петрелевич расскажет о NIO, как одним потоком обработать множество сетевых запросов;
Антон Курако приведет глубокий анализ производительности аспектов в Spring;
Александр Токарев представит продолжение своего доклада про дебаггинг в Java, где покажет, как отлаживать многопоточный, автогенеренный и нативный код;

2) Секция Хардкор:

Александр Ланцов будет сравнивать алгоритмы GC (включая новейшие) в Java и Go, чтобы разобраться, чем они отличаются и какой лучше подходит для ваших сценариев;
Иван Углянский расскажет о мега-проекте Valhalla и добавлении value классов в Java: зачем это вообще нужно, как повлияет на Java, и как развитие языка помогло реализации рантайма;

3) Секция "Расширение кругозора":

Пётр Портнов покажет, как Java разработчикам пользоваться инструментом Error Prone, чтобы заранее ловить их баги статическим анализом;
Сергей Луговой поделится опытом создания нового языка с JetBrains MPS;
Михаил Пилип расскажет о построении SCADA-системы своими руками, и как ему в этом помог Kotlin.



Мы продолжаем работать над программой и конференцией в целом. И уже с нетерпением ждем конца февраля, чтобы встретиться на ней с вами ☺️

Ну и напомним, что сейчас идеальный момент, чтобы купить билет. Так вы успеете до следующего подорожания (с января), а заодно сразу запланируете приятное дело на следующий год.

Всех с наступающим! 🎄
🔥5