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

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

Домашняя страница: https://toparvion.pro/
Download Telegram
Заметка для тех, кто, собираясь в отпуск, в первую очередь кладёт в сумку беговые кроссовки 👟

Горный Алтай, на мой взгляд – далеко не самое удачное место для комфортных пробежек: там то бежишь по узкой обочине нагруженной дороги, то корячишься вверх или вниз по ухабистым горным тропинкам. Но поскольку просторы там огромные (а виды и воздух упоительные), найти нормальные места для пробежек всё же можно. Поделюсь своим опытом 👇

Свой первый обзор беговых маршрутов Чемала (с фотками, треками и комментариями) я делал в 2019-ом году. С тех пор они почти не утратили актуальности (разве что траффик стал выше), а я открыл для себя ещё несколько. В дополнение к обзору привожу топ-3 из них в порядке возрастания клёвости.


🥉3 место: Чуйский тракт в районе с. Черга

Сама по себе трасса невероятно живописна, но бежать только вдоль нее может быть не комфортно: мало тени, много машин. К счастью, в районе базы отдыха Барсуган есть несколько ответвлений, по которым можно сбежать в поля поодаль от тракта (в других местах они тоже наверняка есть). Только бежать туда лучше в сухую погоду, иначе кроссовки будут мокрыми от травы и/или тяжелыми от налипшей грязи. Подходит для одиночного трейла. Пример трека здесь.


🥈2 место: Катуньское заречье (близ с. Аюла)

Это относительно плоский участок между Чемальской солнечной электростанцией, аквапарком Рублёвка и собственно рекой Катунь. Там много хоженых тропинок и прокатанных дорог, а со многих точек открываются шикарные виды. Подходит для небольшого кросса, без жести. Пример трека тут.


🥇1 место: Айский тракт

Необъяснимо, но факт: гладкая, ровная, длинная асфальтовая трасса с невысоким траффиком и хорошим приподнятым тротуаром, который ещё и скрывается в тени деревьев (на части пути). Располагается между озером Ая и комплексом баз Бирюзовая Катунь. Не удивительно, что именно там проходит беговой этап ежегодной триатлонной гонки AltaiTriRace. Отлично подходит для скоростной асфальтовой тренировки. Пример трека присутствует.


Кто знает другие годные маршруты в тех краях – welcome в комментарии 👐

#спорт
👍621
Лайфхак для performance-инженеров 👷‍♂️

Коротко: Парсить большие heap-дампы для анализа в Eclipse MAT лучше в recovery mode: получается быстрее и стабильнее

Подробно:


Давеча потребовалось распарсить 30 ГБ-ый дамп памяти JVM-приложения для анализа в Eclipse Memory Analyzer Tool (MAT). Для этого в MAT есть отдельный консольный парсер, который тоже, разумеется, работает на #Java 🤭

И поскольку у меня на рабочей машине (Ubuntu 24.04) всего 32 ГБ ОЗУ, встал вопрос, сколько выставить -Xmx (максимальный размер кучи) парсеру, чтобы он (а) не притеснял другие приложения и (б) сам не скукожился от OutOfMemory: Java Heap Space?

Первая попытка выставить 28 ГБ провалилась: парсер был жестко прибит несокрушимым OutOfMemory Killer’ом за попытку аллоцировать слишком много памяти, причем нативной. Для тех, кто не в курсе, почему так происходит, у меня был доклад “Скажите «Ой»: JVM и OOM Killer” – там описан этот механизм ядра Linux и способы избегать столкновения с ним 🔫

Второй была попытка сторговаться на 26 ГБ, и она удалась, правда, ждать пришлось минут 15-20. Оно и понятно, ведь при таком потреблении парсер солидную (если не бОльшую) часть времени провёл не за делом, а в обнимку с GC, пытаясь на лету подчищать за собой объекты. Как бы там ни было, задача была решена, и это клёво

Но уже через пару дней от того же заказчика пришёл новый дамп, на сей раз на 55 ГБ, и стало ясно, что так просто я уже не отскочу 🫠

Не особо веря в успех, я всё же решил попробовать отдать парсеру вообще всю память машины. Но для этого надо как-то заставить ОС не мешаться. А как это сделать? Правильно – Recovery Mode: максимально голый режим командной строки, используемый обычно для восстановления после жестких аварий ОС (в Windows есть его аналог под названием Safe Mode, хотя там графическая оболочка всё равно запускается)

Выставив в этом режиме -Xmx30G (с отступом на аллокации в нативной части), я был приятно удивлен тем, что парсинг успешно завершился. Больше того, он завершился гораздо быстрее, минуты за три. Видимо, возможность беспрепятственно бросить все 16 ядер CPU на борьбу с мусором позволили JVM максимально эффективно распорядиться памятью и не аффектить производительность прикладного кода ⛲️

Разумеется, здесь есть щепотка везения, ведь пиковое потребление памяти парсером во многом зависит от характера графа объектов в обрабатываемом дампе, а значит, в следующий раз такой трюк может и не пройти 🤹

Тем не менее, Recovery Mode — достаточно простой и эффективный способ превратить ваш ноутбук в настоящую Java-машину, поэтому предлагаю взять на заметку ✍️
🔥15👍32👏1
Тот случай, когда в написанном слове точно есть одна из двух опечаток (буквы не хватает или буква лишняя), но будучи написанным DevOps-инженером, оно в любом случае не теряет смысла:

... чтобы ноды не залебывались от нагрузки ...
😁19
Минувшие выходные целиком прошли под хэштегом #спорт — вместе с товарищами по спортивному клубу я был в Красноярске на двухдневном фестивале открытой воды Шумиха 2025 🌊

В оба дня нас забрасывали катерами на дикие речные берега, откуда мы возвращались вплавь в стартовый городок. В субботу у меня был заплыв на 3,8 км по заливу Енисея с прикольным названием Шумиха, а в воскресенье — 5 км уже по самому Енисею-батюшке. Оба старта, в целом, прошли хорошо; я показал результаты, соответствующие своему текущему уровню подготовки. Правда, во второй день плылось заметно сложнее — несмотря на твёрдое намерение не упарываться в первый день, сил было потрачено немало, а они, как известно, не бесконечные 🙃

Высокие берега, сплошь поросшие вековыми хвойными деревьями; чистая прохладная вода, местами придававшая изюминки своим волнением; несокрушимая мощь и масштабное величие Красноярской ГЭС, расположенной всего в 1,5 км от места старта — всё это вкупе с хорошей организацией и отличной компанией сделали прошедшие два дня очень яркими и богатыми на позитивные впечатления, хоть и напряженными физически🫠

Не знаю, удастся ли ещё поплавать в открытой воде в этом сезоне; всё же наше сибирское лето весьма скоротечно. Но даже если нет, эти выходные вполне можно считать достойным завершением сезона🌅

P.S. Для любопытствующих: итоговый протокол соревнований лежит здесь.
🔥15👏2
SSH-туннели для #Java Dev&Ops 🔭

Ни один из последних моих проектов не обходился без подключения по SSH, чтобы что-то посмотреть/настроить/отладить/пофиксить и т.д. Но часто для этого нужно подключиться к определённому TCP-порту удалённого сервера, а он недоступен: то открыт лишь на localhost, то где-то маршрута не хватает, то безопасники запрещают. Во всех этих случаях на выручку приходили SSH-туннели. Расскажу о них чуть подробнее, вдруг кто-то не знал или недооценивал 🧐

Что это?
Фича SSH клиента и сервера, позволяющая "пробросить" порт с удалённого сервера на свою локальную машину (где запущен SSH клиент). То есть сделать так, чтобы обращение на этот порт у localhost'а волшебным образом приводило к обращению на этот же (или другой) порт у сервера, но при этом весь траффик оставался закрытым внутри SSH-соединения.
По смыслу это похоже на port-forwarding у kubectl и docker, но может применяться в бОльшем числе случаев ⚒️

Зачем?
Чтобы мультиплексировать множество соединений с удалённым сервером по одному SSH-каналу без открытия портов на внешних сетевых интерфейсах сервера. Проще говоря, чтобы завернуть весь траффик внутрь SSH независимо от протокола. Например:
• чтобы удалённо отлаживать JVM-приложение, не выпячивая порт отладчика наружу;
• чтобы мониторить приложение по JMX, не заморачиваясь с настройкой SSL для этого;
• чтобы дергать Spring-приложение за actuator, не затеваясь с получением сертификатов для HTTPS 📌

Как включить?
В общем случае включение сводится примерно к такой команде в консоли:
ssh -L <local-port>:<remote-address>:<remote-port> -N -f <ssh-host>

, где:
-L — команда на включение локального туннеля;
local-port — порт, на котором вы хотите видеть удалённый сервис на своей машине (как правило, равен remote-port);
remote-port — порт удаленного сервера, который нужно сделать доступным у себя (как правило, равен local-port);
remote-address — IP или имя сетевого интерфейса, на котором открыт удалённый пробрасываемый порт; чаще всего это localhost, но могут быть и другие;
-N — признак отсутствия команды, которую нужно выполнить на удалённом сервере (обычно она не нужна);
-f — признак запуска туннеля в фоновом режиме; если не добавить, управление не вернётся в консоль, и туннель будет висеть в ней;
<ssh-host> — либо имя хоста для подключения (может быть с именем пользователя, например, root@somehost.com), либо название настроек подключения из файла ~/.ssh/config, например:
Host my-sandbox-vps
Hostname 55.555.555.0
User root
IdentityFile ~/.ssh/id_dsa
IdentitiesOnly yes

С такими настройками включение SSH-туннеля для удалённой отладки может выглядеть так:
ssh -L 5005:localhost:5005 -N -f my-sandbox-vps

Причём и эта команда, и файл настроек останутся точно такими же даже под Windows, если у вас установлен OpenSSH 🪟

Как выключить?
Поскольку каждый туннель — это отдельный процесс, для его выключения достаточно этот процесс остановить. На Linux/MacOS это может выглядеть примерно так:
$ ss -tulpn | grep 5005
tcp LISTEN 0 128 127.0.0.1:5005 0.0.0.0:* users:(("ssh",pid=307017,fd=5))
$ kill 307017

А если туннель запущен без флага -f, то в его консоли достаточно нажать Ctrl+C✖️

Какие недостатки?
• быстродействие: как правило, скорость передачи заметно падает, поэтому смотреть видосики в UHD по такой схеме будет не комфортно;
• искажение цепочки вызовов: все запросы в целевой сервис будут приходить с localhost, где запущен SSH-сервер; это может создавать проблемы;
• непрозрачность: если целевой хост перестанет быть доступен, туннель просто молча упадёт, не подавая явных признаков и не пытаясь переподключиться (это всё преодолимо, но потребует усилий) 🧟

P.S. Картинка взята из этой статьи Ивана Величко, где он также объясняет и другие варианты построения туннелей на SSH. Почитайте, и пусть вам это никогда не пригодится 🫠
🔥171
В последнее время, в связи со сдачей напряжённого проекта с московскими коллегами, стало нередко приходиться начинать рабочий день по Новосибирску, а заканчивать по Москве.

На этом фоне в обиход вошёл новый речевой оборот:

Сегодня в третьей половине дня...
😢14😁10
Новость для тех, кто всерьёз задумывался начать своё дело в IT 💼

C 26 сентября по 30 октября в Новосибирском Технопарке пройдёт 31-ый сезон А:Старт — одной из топовых в России и уж точно крутейшей за Уралом акселерационной программы для начинающих предпринимателей и технологических стартапов. Туда можно прийти с IT-проектом на любой стадии от голой идеи до рабочего решения, а уйти с упакованным продуктом, готовым к выводу на рынок или даже имеющим выручку 💰

Для этого на протяжении пяти недель (как правило, по три дня: четверг-суббота) нужно посещать профильные лекции, прорабатывать конкретные вопросы с экспертами и менторами и, конечно, выполнять много домашней работы по контролем трекера: проводить проблемные интервью, анализировать рынок, считать unit-экономику, стряпать лендинги и (наверняка) допиливать свой продукт. Легко будет едва ли, а вот полезно — по-любому 💯

Фишка программы в привлечении множества экспертов из индустрии: владельцев бизнесов, опытных технопредпринимателей, инвесторов — словом, тех, кто собственными руками и головой уже добился значимых успехов и понимает реальные проблемы начинающих. Об них можно как следует "обстучать" все свои идеи, вопросы и сомнения, что очень сильно помогает трезво взглянуть на свою задумку и выбрать ей правильный путь развития 🌄

Участие в программе платное: 12К лично и 24К за команду. Но есть лайфхак. Незадолго до начала акселератора, 13 сентября в том же Академпарке будет проходить Easy Pitch — открытая презентация идей и проектов для всех желающих. Если к ней нормально подготовиться и уверенно выступить, то присутствующие там эксперты могут подарить бесплатную проходку на акселератор. Схема рабочая, проверял сам в 2023-ем и в этом году 👌🏼

Кому интересно, можно полистать сайт программы, а также задать вопросы организаторам (они хорошо реагируют) или мне — как выпускник весеннего А:Старт 2023, ни разу не пожалевший о содеянном, я с удовольствием поделюсь своим опытом участия 👐
🔥3❤‍🔥1
Media is too big
VIEW IN TELEGRAM
Сегодня с товарищами завершил сезон плавания на открытой воде. В этом году он выдался славным: помимо разных водоёмов Новосибирска, довелось поплавать в водах Кузбасса, Урала, Ленинградской области и Красноярска 🗺

А завершением стал рекордно туманный заплыв на домашнем Обском водохранилище — видимость была не больше 100 метров, и это вскрыло любопытный эффект: кто бы ни был направляющим группы, без визуальных ориентиров он всё равно не мог плыть прямо и забирал вправо, постепенно вырисовывая круг и возвращаясь к берегу. Разница между пловцами была только в радиусе этого круга 🤭

На этом фоне вспомнилось закрытие аналогичного сезона в 2020-ом — тогда заплыв, напротив, выдался необыкновенно солнечным, и поскольку я был начинающим дроноводом, вместо плавания с товарищами я снимал их с воздуха 🚁

Делюсь с вами кадрами того дня. Едва ли вы захотите приобщиться, но, быть может, хотя бы поймёте, за что я полюбил это отнюдь не самый комфортный #спорт 🏊‍♂️
🔥7
This media is not supported in your browser
VIEW IN TELEGRAM
На заметку troubleshooter'ам ✍️

На днях вышел alpha-релиз четвертой версии Recaf — среды для реверс-инжениринга приложений на #Java. Она позволяет получить множество сведений о готовом приложении (или его процессе) даже без доступа к исходному коду 👨‍💻

Вот примеры применений из моего опыта:
• проверить, что недавние изменения в определённом классе действительно попали в финальный артефакт приложения — это бывает полезно при косячном CI/CD или путанице с версиями приложения;
• выяснить значение определённого свойства или флага у запущенной JVM — пригождается при анализе проблем производительности и расследовании некорректного поведения;
• определить classLoader, которым был загружен такой-то класс в runtime — бывает полезно при разбирательствах с ClassNotFoundException, NoClassDefFoundError, ClassCastException и прочими непотребствами 🐞

Разумеется, всё это можно сделать и другими средствами (я так и делал), но, согласитесь, удобнее и быстрее работать, когда есть единый инструмент с интуитивно понятным интерфейсом, который не надо каждый раз вспоминать (в отличие от синтаксиса под-команд jcmd) 🛠

Из любопытного: Recaf также позволяет менять байт-код (в том числе структуру классов) и применять эти изменения на лету. Интуитивно кажется, что это нужно, например, чтобы обманывать локальный Minecraft и накручивать себе очки и жизни (такой ArtMoney для Java). Если знаете реальные кейсы применения такой фичи в неигровых приложениях (и с законными целями), то поделитесь, пожалуйста — будет интересно 🤲
👍7🔥2
По моим наблюдениям за последние 10+ лет, почти все самые сложные вопросы и проблемы в разработке ПО начинаются со слов "Почему не ...?" 🧐

— Почему не был вызван этот метод?
— Почему не пришёл ответ на вон тот запрос?
— Почему не обработано отправленное событие?
— и т.д., и т.п., и др.

Их все объединяет тот факт, что в качестве вводной даётся лишь негативное следствие (где-то что-то не произошло), а первопричина (где-то что-то произошло, но не так) остаётся спрятанной раньше на шаг, два или больше... И эти шаги приходится делать в обратном направлении исходного развития событий, то есть реверс-инженирингом 🥷🏼

А если такой подход неприменим, то приходится брать ту же или аналогичную систему, и повторять в ней те же шаги в прямой последовательности, пытаясь понять/заметить/угадать момент, в который поведение могло стать ошибочным. Любопытно, но по моему опыту, примерно в 1/3 таких случаев инженер, пошедший этим путём, приходит к неутешительному выводу в духе: "ДА ОНО ВАЩЕ НЕ МОГЛО РАБОТАТЬ!" 🫠

Универсального решения для всех проблем "почему не...?" мне неизвестно, но как разработчик я нередко вижу на code review, что алгоритм воплощается в коде по сугубо оптимистичному пути, т.е. автор как бы ведёт его строго в успешном направлении, а всё, что может сбить с этого пути, но не мешает явно, игнорирует (зачастую несознательно). Код получается компактным, менее развесистым, пишется быстро, читается легко — казалось бы, всем хорошо. Вот только этими намерениями выстлана дорога в "почему не ...?" 🛣

В этом свете хочется пожелать почаще включать в себе параноика. И в местах соприкосновения компонентов системы спрашивать себя: "А что если здесь сломается?", "А точно ли я могу полагаться на эти данные?", "А где гарантии, что это будет так?" Все эти сомнения необязательно выражать громоздкими if'ами, зашумляющими код. Есть ряд компактных однострочных решений, например:
— ключевое слово assert (с которым, правда, есть серьёзные нюансы);
— семейство методов java.util.Objects.require*()
— семейства методов check* и verify* из классов Preconditions и Verify в библиотеке Google Guava 🥑

Выбор конкретного способа проверок — тема отдельной дискуссии. Главное — эти проверки добавлять. По сути, это применение принципа fail-fast, только с целью обратить что-то не произошедшее вовсе (и оттого сложное для диагностики) во что-то произошедшее не так. Тогда и отвечать на трудный вопрос "почему не ...?" придётся пореже 🙂

#мыслиВслух
🔥12👍103