(java || kotlin) && devOps
366 subscribers
6 photos
1 video
7 files
332 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
image_2025-07-30_16-31-11.png
290.4 KB
Хочу порекомендовать попробовать такую фичу IDEA, как Kotlin Notebook.

Это конечно заимствование из ML и Python. Суть на картинке выше, но я дам краткое описание.

У нас есть один файл, который содержит как куски кода, так и текст с картинками в формате Markdown. Куски кода (snippet) можно исполнять прямо в файле, т.е. output появляется под кодом. Исполнять можно как сразу все - не интересно - так и по очереди. Результат исполнения сохраняется в контексте. Т.е. если в первом snippet-е объявили функцию, вызвали его, то во-втором можно ее использовать. Она даже красным перестает в этот момент светится. Т.к. autocomplete, подсказки IDE, документация - все работает.
Как по мне - удобная штука для разработки и отладки алгоритмов. Да, их в энтрепрайзе мало, но они есть)
Почему удобная - рядом и аналитика, и код.

Создать новый Notebook можно в Kotlin или Java проекте через меню New.

P.S. Для Java такое можно сделать - с помощью того же jshell. Но IDEA пока не умеет.

P.P.S Да, как и всегда (почти) в мире Java - инициализация ноутбука долгая)))

#kotlin #java #idea
В продолжение предыдущей темы.

Вижу одну опасность при работе с noteboook-ом. Главная задача - отладить какой-то сложный алгоритм. Про структуру модулей, разделение на слои и классы никто понятное дело в это время не думает. Да и не предоставляет notebook для этого никаких средств.

Но настанет момент, и придётся вернуться к проектированию. Главное - не забыть об этом)

#notebooks
Что станет с языками программирования?

Недавно на одной AI конференции услышал две довольно радикальные мысли.
1) программирование на высокоуровневых языках исчезнет повторив судьбу ассемблера. Останутся только архитекторы.
2) если модели не нравится ваш код - в смысле она не может его доработать - значит проблема в коде

Вот мои мысли по этому поводу.

1) Эти два утверждения работают только вместе. Т.е. если LLM модель пишет код, то он стандартизирован. И тогда любой нестандартный код - плохой. Т.к. он нарушает code style. Назовем его AI code style. И потому что раз уж мы отдали писать код модели - не надо ей мешать

2) С одной стороны аналогия с заменой ассемблера языками высокого уровня красива. И некие аналогии тут есть. Скорость разработки в теории может так же ускориться. Сложность систем, которые можно разработать, вырастет. А запрос как на повышение скорости разработки, так и на создание все более сложных систем, есть. Да, программирование на LLM - это тоже переход на более высокий уровень

3) Где аналогия хромает? Что общего у ассемблера и Java. Оба они детерминированы. Как и разработка в целом. Да, у нас есть место случайности, но она сосредоточена в нескольких местах - реализация функции random, генерация уникальных идентификаторов приходят на ум. А LLM принципиально недетермирована. Использование недетермированной машины для выполнения детерминированного процесса - ну такое себе.

4) Программирование уже пытались убрать из процесса разработки коммерческого ПО. Вот сейчас появилось много AI платформ для no code (low code) разработки. Знакомые же слова. Я про "no code". Да, BPMN системы. И различные проприетарные low code платформы. Свою ниши они заняли, но эти ниши достаточно узкие. Tilda самый очевидный пример. Но если говорить о глобальной замене программирования и программистов - не взлетело

Что думаете по этому поводу?

#ai #llm #lang
👍1🔥1
На какие столбцы повесить индексы?

Есть несколько способов это определить.

1) экспертное мнение. Подходит для простых случаев. Ну и ограничение - нужно быть экспертом)

2) спросить условный ChatGPT, скормив ему код. Стильно, модно, молодёжно. Но с текущим уровнем развития LLM видится, что точность не гарантирована)

3) использовать план выполнения запроса, чтобы найти там full scan (seq scan).
Но тут возникает вопрос - на каких запросах его выполнять?
На медленных либо сильно нагружающих СУБД.
Есть несколько вариантов их найти:
а) slow log - отбрасывание наиболее медленных запросов в лог. Что считать медленным - настраивается через граничное время выполнения.
Может быть включён как на уровне Hibernate https://vladmihalcea.com/hibernate-slow-query-log/, так и на уровне базы данных https://www.cybertec-postgresql.com/en/3-ways-to-detect-slow-queries-in-postgresql/ (нужен VPN).
При наличии такой возможности - лучше не уровне БД, например, во время НТ.
Данный способ хорош тем, что прямо указывает на медленные запросы. И этим же плох, т.к. он не покажет массовый запрос, который выполняется быстро, но много.

б) более подробную информацию можно получить с помощью сбора статистики выполнения запросов. Для PostgreSQL это делает модуль pg_stat_statements. Детали тут https://habr.com/ru/articles/488968/
Модуль формирует табличку с данными, в которой можно отсортировать запросы по общему времени выполнения, среднему и максимальному времени, по величине отклонения от среднего, по числу вызовов и даже по нагрузке на процессор и дисковую подсистему.
В общем куча полезной информации, с которой придётся поработать)
Также рекомендую включить его на НТ. А потом измерить влияние включённого модуля на производительность и если оно в районе 1% - включить и на ПРОМе.

P.S. У MySQL аналога pg_stat не нашёл. У Oracle - AWR. У MSSQL - Query Store.

#db #performance
👍1
Редко делаю репосты, но кажется данный пост этого достоин.

Пару замечаний.
1) как раз по итогам вот таких углубленных исследований темы у меня часто появляются посты)
2) я не понимаю, как можно полдня ... развлекаться с LLM, не получить работающего кода и главное - не получить ощущения, что ты занимаешься ерундой. У меня в таких кейсах это ощущение уже через полчаса возникает) Видимо еще не вовлекся)
3) если нужно прокопать проблему - LLM может с этим помочь. Главное не зацикливаться на получении работающего кода здесь и сейчас. И задавать правильные вопросы. IMHO замечание про LLM как раз и показывает путь, как обойти опасность "отупения" при работе с LLM не отказываясь от нее
Почему многие программисты не станут синьорами никогда

И годы опыта не помогут. Сразу к сути: Ключевой критерий развития это то, как происходит отладка кода, когда мы впираемся в какие-то проблемы и не понимаем как их решить. И речь идет не о том, пользуетесь ли вы отладчиком, логами или просто принтами выводите инфу на экран, а речь идет о том, как вы разбираетесь с проблемой в принципе.

Запоминайте паттерн решения любого затыка в кодинге:

1. 5-10 минут пробуем применить какие-то быстрые догадки и метод тыка
2. 10-20 минут тратим на поиск готовых решений в ИИ и на reddit (стековерфлоу прости, ты больше не нужен)
3. И примерно спустя 30 минут тыкания останавливаемся. На этом этапе мы должны перейти в режим, а что это вообще за проблема? Начинаем читать по теме пытаясь понять как в целом работает эта штука, которая сломалась, что за ней стоит, какая теория подходы и все в этом духе. Разбираемся за час-два и фиксим
4. Если не помогло, тут уже надо с кем-то поговорить. Нельзя висеть на одной задаче без движения больше 2 часов.

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

Если спустя час отладки вы ничему не научились и не узнали ничего нового (не как факт, а системно, как что-то работает), то ваше развитие как девелопера не присходит вообще. Поэтому что при годе опыта, что при десяти, вы будете наталкиваться на одни и те же проблемы и скорость их решения будет такой же медленной, если эта проблема проявляется хотя бы немного по другому.

На практике так происходит очень часто. Человек тыкается не 5 минут, а часами никак не разбираясь в том, что он делает.

Сейчас ситуация еще хуже из-за ИИ, который позволяет входить в цикл "спросил-попробовал" на полдня без ощущения делания какой-то херни. Полдня общаться с ИИ нужно и можно, но только если вы тратите это время на попытку разобраться в вопросе, а не "поправь/вот ошибка", когда вы находитесь в цикле отладки.

Видео на эту тему одно из первых у меня на канале: https://www.youtube.com/watch?v=9iwYRcw3A8A

Ссылки: Телеграм | Youtube | VK
Java vs Python, часть не помню какая)

Я уже делал несколько постов про то, как инструменты, исходно появившиеся в экосистеме Python, мигрируют в Java.
Причина я думаю понятна - большое число Java программистов, развитая экосистема.

Вот еще пример.

Важной частью Data Science является веб скрапинг (Web Scraping) - обход сайтов в сети интернет и получение из них определенного рода данных. И если вбить эти два слова "веб скрапинг" в поиск - он сразу подставит python)
Вот типичная статья из выдачи Яндекса https://habr.com/ru/companies/ruvds/articles/796885/
Основные python инструменты оттуда - BeautifulSoup, Scrapy, Selenium, lxml, pyquery

А что есть в Java? Есть ли что-то?)

BeautifulSoup - собственно парсинг страниц сайтов. Аналог в Java - jSoup https://www.baeldung.com/java-with-jsoup
Scrapy - тоже парсинг, но с многопоточкой, работой с сессией, куками. Т.е. для массового скрейпинга и работы со сложными сайтами. В Java - Webmagic https://www.baeldung.com/java-webmagic-web-crawler Возможностей поменьше, но инструмент в наличии
Selenium - не зависит от языка, вообще говоря написан на Java. В интеграционных тестах на Java я его еще лет 15 назад использовал.
lxml - быстрый парсер xml\html. Вообще у Java большой выбор парсеров: DOM, SAX, Stax. Но тут речь про работу с HTML, а HTML - это конечно подмножество XML, но, как правило - XML с ошибками. Зато в Java есть библиотечка TagSoup, цитата: "SAX-compliant parser written in Java that, instead of parsing well-formed or valid XML, parses HTML as it is found in the wild".
pyquery - работа с HTML в стиле jquery. Вот тут аналога не нашел, но, кажется, не критично.

Итого - экосистемы не изолированы, хорошие идеи перетекают из одной в другую. Java хоронить рано)

#java #python #data_science
👍21🔥1
Нужны ли sidecar?

Напомню, sidecar - это паттерн распределенных систем. Суть - есть 2+ контейнера. Один главный — контейнер собственно сервиса, содержит основную логику. Второй - "прицепной" (это дословный перевод sidecar) контейнер. Его роль - дополнить и улучшить контейнер сервиса. Причем часто основной сервис даже не предполагает о его существовании. Удобно для прозрачного навешивания нового функционала. Примеры: добавление Service Mesh, логирования, шифрования, работа с секретами...

У себя в компании я наблюдаю тренд по отказу от sidecar.

Почему?
У нас микросервисы. Мы не делаем их большими, требования к ресурсам стараемся оптимизировать - получаем реалистичные бизнес-требования, проводим НТ, устанавливаем requests и limits. Так по крайней мере должно быть)
Но что получается в итоге?
Предположим у нас service mesh. Предположим есть требование безы - весь входящий и исходящий трафик идет через ingress\egress. Это уже минимум +3 контейнера envoy proxy со своими limits. Если один контейнер сервиса = один envoy proxy, + ingress + egress.
А если каждый из них нужно "обмазать" sidecar для шифрования. А еще для хранения секретов. А еще для логирования. И еще какие-то требования платформы.
Итого я видел кейсы, когда на один контейнер простого бизнесового сервиса в namespace было 7 или 8 служебных контейнеров. И даже если каждый из них потребляет меньше ресурсов, чем бизнес сервис - в итоге мы получаем х3 накладных расходов по ресурсам. Грустно(
Проблема на самом деле не только в контейнерах - любые служебные pod в namespace тоже вносят свой вклад.

Как же решается проблема?
Путей несколько:
1) часть функционала можно встроить в сам приклад. Если в прикладе уже есть клиентский модуль сервиса X и его все равно надо периодически обновлять с пересборкой - сделать этот клиентский модуль чуть толще вполне себе можно.
2) у k8s есть такая штука как операторы. Это сервис, работающий где-то рядом с ядром k8s, который может отслеживать изменения конфигурации в любом namespace и по этому событию делать что-то полезное. Например, по наличию определенной аннотации у пода подгружать для него секреты. Или собирать метрики с пода, опрашивая url Prometheus, построенный по определенному шаблону. Или настраивать Rate Limiter на envoy proxy при его старте. Оператор можно создать самому, это по сути plugin для k8s
3) если продолжить мысль из предыдущего пункта - по такому же сценарию можно поступить и с Istio proxy (он же envoy). Встречайте - Ambient Mesh. Вот статья про технологию https://habr.com/ru/articles/807117/, а вот как это внедряется в Сбере https://yandex.ru/video/preview/3928252140575819915 Все прокси не исчезают, трафик в облаке большой, оператор не может маршрутизировать его сам. Но прокси создаются на каждой node, а не на каждом контейнере. Требования к ресурсам у них будут побольше, но все равно получаем экономию по ресурсам в разы.

P.S. еще одна проблема, которую решает отказ от sidecar - с разработчика снимается обязанность отслеживать появление новых версий sidecar и их обновления.

#k8s #cloud #optimization
🔥21👌1
И снова AI агенты...

AI агент по определению должен делать что-то полезное, делать это с использованием AI, автономно и недетерминировано.
Сейчас я хочу рассмотреть свойство полезности.

AI агент в чем-то похож на умный proxy. Ум обеспечивает LLM (или не обеспечивает, тут идут споры))) ). А далее агент вызывает некую существующую функцию. Или несколько функций.
В терминологии AI это tool:
1) https://python.langchain.com/docs/concepts/tools/
2) https://docs.spring.io/spring-ai/reference/api/tools.html

tool - вообще говоря это просто метод Java, Python или любого другого языка, аннотированый соответствующим образом.
Как агент понимает, что умеет tool? Аннотации с описанием назначения тула, входных и выходных параметров.

Но если подумать - мы же живем в REST мире, в нем победил OpenAPI, а там вся необходимая информация есть. И текстовые описания, и граничные значения, и примеры. Даже адреса серверов на разных средах можно в спеке указать.
Нельзя ли это как-то переиспользовать? DRY все таки!

Можно. https://python.langchain.com/docs/integrations/tools/openapi/ на примере Python
Загружаем спеку, преобразуем в формат, понятный AI и создаем агента:

with open("spotify_openapi.yaml") as f:
raw_spotify_api_spec = yaml.load(f, Loader=yaml.Loader)
spotify_api_spec = reduce_openapi_spec(raw_spotify_api_spec)
...
spotify_agent = planner.create_openapi_agent(
spotify_api_spec,
requests_wrapper,
llm,
allow_dangerous_requests=ALLOW_DANGEROUS_REQUEST,
)


Почему не Java?
https://github.com/langchain4j/langchain4j/issues/1307
Ждем-с.
Что-то делается и для Spring AI, но пока сторонними разработчиками https://readmedium.com/connect-existing-openapis-to-llms-with-spring-ai-039ccabde406

Это самый простой способ вызвать существующий функционал.
Если он не подходит по одной следующих причин:

1) нет готового адаптера OpenAPI
2) нет OpenAPI спецификации, или она сделана криво, а доработка ее другой командой требует времени
3) хочется объединить несколько запросов в один tool или обогатить ответ tool-а локальной информацией
4) нужно убрать лишнее из ответа

то можно вернуться к исходному варианту - написать свой кастомный tool, возвращающий только то, что нужно и документированный так, как нужно.

Ну и третий вариант - отдельный MCP сервер https://t.me/javaKotlinDevOps/376.
У него два плюса:
1) MCP API - это специализированное API, адаптированное для использования LLM
2) tool-ом в виде MCP сервера может в теории воспользоваться любой AI агент

#ai #llm #spring #python
👍1
Можно ли засунуть PostgreSQL в облако?

Когда мы говорим о БД в облаке - обычно говорят о специально созданных для облака noSQL хранилищах.
Как пример можно привести YaDB и Amazon DynamoDB.
Их главные плюсы:
1) managed storage - администрирование идет в комплекте с облаком, неотъемлемая фича облака
2) возможность горизонтального масштабирования
Значит ли это, что старые добрые реляционные БД не попадут в облако и станутся в прошлом?
Нет.

На самом деле я уже об этом писал - https://t.me/javaKotlinDevOps/257
Существуют Azure Cosmos DB for PostgreSQL и Aurora PostgreSQL.
Это проприетарные решения под конкретное облако.

В связи с этим возникает два вопроса:
1) есть ли opensource решения?
2) как вообще удалось затащить PostgreSQL в облако?

Ответ на первый вопрос - да, но детали будут ниже.
А на второй - вспомним, как работает горизонтальное масштабирование в облаке для хранилищ.

Собственно хранилище - объектная файловая система, совместимая с S3 API - в любом облаке есть.
Это storage уровень. У него малая нагрузка на процессор, но большая I/O нагрузка на дисковую систему.

Еще у БД есть движок, рассчитывающий планы выполнения запросов и собственно их выполняющий. Это compute часть. Ей в теории хранилище вообще не нужно, а нужны CPU и RAM.
Т.е. compute часть является stateless, а этом значит ее можно быстро масштабировать с 0 до бесконечности. Ну не бесконечности конечно, а до свободного объема кластера. Учитывая, что тот же PostgreSQL написан на C - подыматься без данных он должен быстро.

Собственно, остается вопрос - позволяет ли PostgreSQL разделять compute и storage? И исходя из предыдущей информации - да, позволяет.
Например, есть https://www.orioledb.com/ Это storage движок для PostgreSQL, исправляющий несколько косяков в базовой архитектуре PostgreSQL в реализации MVCC (многоверсионности). Но это еще не облачное решение, оно позволяет эффективнее использовать ресурсы конкретного сервера. compute и storage все еще на одном сервере.

Но если как compute оставить движок PostgreSQL, а storage разнести по разным серверам(кластерам, зонам доступности) - мы получим облачное решение.

Самый известный opensource вариант - Neon, вот хорошая статья о нем:
https://habr.com/ru/companies/arenadata/articles/927464/
Если всмотреться в архитектуру https://habrastorage.org/r/w1560/getpro/habr/upload_files/30f/688/639/30f688639ad82b12c41b3c7928529d0a.jpg
то там все чуть сложнее, чем я описал выше.

А именно: storage слой - это не просто объектное хранилище S3.
Есть еще два уровня: safekeepers и pageservers.
Чтобы понять, зачем они нужны, следует вспомнить, что PostgreSQL хранит данные дважды:
1) в виде страниц (pages) на диске - слепок текущего состояния
2) и write-ahead logging (WAL) - append-only лог изменений, по которому восстановить состояние БД в любой момент времени.

safekeepers принимают WAL лог от compute node и сохраняют его на нескольких узлах (SSD диски) с соблюдением кворума, т.е. гарантий отказоустойчивости https://neon.com/blog/paxos.
Если safekeeper падает - запросы перенаправляются на другой узел. Но число safekeeper фиксированное, но благодаря кворуму падение какой-то части узлов система выдержит.

pageservers - получают WAL лог от safekeeper и преобразуют его в формат страниц PostgreSQL. После чего сохраняют все это - WAL и страницы с данными - в S3. pageservers тоже имеют SSD диски и являются кэширующим слоем перед S3. При падении конкретного pageserver - трафик переключается на резервный с некой задержкой.

Итого мы имеем:
1) "бесконечное" масштабирование объектного хранилища S3
2) ограниченное размером кластера масштабирование compute nodes
3) фиксированное число safekeepers и pageservers, что не является узким звеном в первом приближении, но требует понимания целевой нагрузки на чтение и запись.

Итого: традиционные СУБД не сдаются) Победит сильнейший)

#rdbms #cloud #nosql
👍1
Вдогонку про storage движки PostgreSQL

Во-первых - если говорить о классических СУБД, то storage движки - тема не новая, можно вспомнить MySQL, который исторически имел несколько движков. InnoDB - самый известный, а вот полный список из официальной поставки:
https://dev.mysql.com/doc/refman/8.4/en/storage-engines.html
Из интересного:
blackhole - ничего не сохраняет
csv - сохраняет понятно куда)
memory - аналогично)
federated - удаленные сервера, горизонтальное масштабирование, но похоже с рядом ограничений (не копал глубоко).
Плюс есть реализации от внешних поставщиков.

Во-вторых, возможность создания storage движков в PostgreSQL дает следующая фича - Table Access Method (TAM) Interface https://www.postgresql.org/docs/current/tableam.html
Это слой абстракции между storage и compute при работе с таблицами. И расширение PostgreSQL может переопределить метод. Например, для реализации принципиально другого способа хранения записей таблицы и конкурентной модификации данных (MVCC). Или реализации шардирования. Или сжатия данных.

Тут стоит упомянуть, что есть похожая технология Foreign Data Wrapper (FDW).
Это реализация стандарта SQL/MED, позволяющая подключать к PostgreSQL внешние удаленные хранилища и, соответственно, выполнять к ним SQL запросы. Т.е. дать унифицированный SQL API для внутренних и внешних таблиц.
Тут детали https://www.percona.com/blog/foreign-data-wrappers-postgresql-postgres_fdw/
В отличие от Table Access Method Interface данная технология сделана для подключения внешних источников данных, в то время как для TAM подразумевает внутреннее хранение. Или локально, или в случае cloud native - использование пусть и облачного, но своего хранилища.

Соответственно, полноценные storage движки - это движки, меняющие ТАМ.
Вот какие бы я выделил:

1) Orioledb, уже упомянутый ранее - ускорение сохранения данных за счет другой реализации MVCC. Еще умеют сжимать данные и работают над cloud ready storage с разделением compute и storage. В последнем случае позиционируют себя как конкурент Neon, но еще неготовый к production https://www.orioledb.com/blog/orioledb-neon-differences#orioledb-1.
Кандидат на замену основного движка PostgreSQL, но команда PostgreSQL пока сопротивляется)
Если нужно больше информации - лучше, чем описано тут я описать не смогу) https://t.me/rybakalexey/240
Из важных особенностей - требует патча ядра PostgreSQL, что нарушает идею бесшовной замены движков

2) TimescaleDB - оптимизация под хранение временных рядов. Если обычные данные PostgreSQL хранятся построчно (row storage), то новый движок добавляет column storage. Конкурент для InfluxDB и Prometheus. Тут можно найти больше деталей https://deepwiki.com/timescale/timescaledb/12-hypercore-and-columnar-storage

3) Citus - горизонтальное масштабирование, но без разделения compute и storage, а путем возможности создания shared-nothing шард и распределенного выполнения запросов. Это дает возможность безопасно хранить данных для разных потребителей на разных шардах, но при этом иметь возможность выполнять аналитические запросы по всему объему данных. Подходит для SaaS систем.

Для справки - есть достаточно много реализаций Foreign Data Wrapper, предоставляющие доступ к файлам:
0) PostgreSQL - единственный FDW, входящий в поставку PostgreSQL. Эталонная реализация.
1) Oracle
2) MSSQL
3) MySQL
4) parquet (parquet - стандартный формат для Data Lake - аналитических БД, Hadoop, spark и вот это все)
...

Маленькое замечание - в отличие от технологии dblink в Oracle, FDW хранит метаданные удаленной таблицы внутри, что позволяет оптимизировать план выполнения запроса. Например, выполнять какую-то агрегацию на удаленном сервере. Или вытаскивать с удаленного сервера только необходимые данные. Это плюс. А минус тот же, что у dblink - ходить в чужую БД плохо, и противоречит микросервисной архитектуре.
Поэтому видится, что основной способ применения FDW - прототипирование, какие-то временные решения или миграции. Вот пример использования для миграции данных из Oracle в PostgreSQL https://habr.com/ru/companies/vtb/articles/819133/

#db #cloud #postgresql
Как нам улучшить PostgreSQL?

Исходя из предудущих моих постов ответ напрашивается такой - установкой расширений (extension).

Вот так это примерно делается:

CREATE EXTENSION IF NOT EXISTS extension_name
WITH SCHEMA schema_name
VERSION version
CASCADE


Вот так обновление:
ALTER EXTENSION extension_name
UPDATE TO version


И удаление:
DROP EXTENSION IF EXISTS extension_name
CASCADE | RESTRICT


Из важного - расширения тоже имеют транзитивные зависимости, их установка/удаление решается опцией CASCADE.
Проблема несовместимых версий видимо решается установкой совместимых версий)
Расширение ставится в конкретную схему.
Всегда можно сделать условное обновление\удаление - с проверкой на существование.

Что меняют расширения:
1) механизм хранения данных в таблицах (Table Access Method Interface)
2) аналогично для индексов, т.е. новые типы индексов (Index Access Method Interface)
3) новые типы данных
4) новые функции
5) внешние источники данных (Foreign Data Wrapper)
6) SQL синтаксис

И к делу.
Вот что интересного я нашел (orioledb, timescaledb, citus и прочие Foreign Data Wrapper уже описал ранее, исключаем):

1) pg_stat_statements - статистика по времени и ресурсам, затраченным на выполнение запросов (где-то год назад уже писал о нем)

Выборка 10 "тяжелых" запросов по общему времени выполнения:
SELECT query, total_time, calls, rows FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;

2) PostGIS - новые типы данных в столбцах, индексы и функции для работы с геоданными (point, line, polygon)

Создание таблицы со геоданными:
CREATE TABLE spatial_data ( id SERIAL PRIMARY KEY, name VARCHAR, location GEOMETRY(Point, 4326);

Поиск объектов в радиусе 1000 метров от точки с определенными координатами:
SELECT * FROM spatial_data WHERE ST_DWithin(location, ST_GeomFromText('POINT(-73.975972 40.782865)', 4326), 1000);

3) HypoPG - создание гипотетических индексов. Т.е. индекса физически нет, но планировщик запросов думает, что он есть.

Создание гипотетического индекса:
SELECT * FROM hypopg_create_index('CREATE INDEX ON mytable (cardId)');

Проверка, подействовал ли он:
EXPLAIN SELECT * FROM mytable WHERE cardId = 1;

4) jsquery - более лучший поиск в стиле XPath по JSONB столбцам (столбцам, с бинарным оптимизированным хранением json) Детали: https://habr.com/ru/companies/selectel/articles/928922/

Поиск пользователей с именем «Иван» старше 30 лет или тех, у кого есть тег «vip»:

SELECT * FROM users WHERE data @@ '((name = "Иван" AND age > 30) OR tags.# = "vip")';

5) pgvector - работа с векторными типами данных, PostgreSQL как RAG, AI и все такое. Детали: https://habr.com/ru/companies/selectel/articles/920824/

Создание таблицы для хранения векторов:
CREATE TABLE items (
id SERIAL PRIMARY KEY,
title TEXT,
embedding VECTOR(1536)
);


Вставка данных :
INSERT INTO items (title, embedding) VALUES
('PostgreSQL embeddings', '[0.10, -0.80, 0.45]'),
('Neural image processing', '[0.42, 0.18, -0.35]'),
('Sound pattern matching', '[-0.20, 0.70, 0.60]'),
('Document clustering', '[0.09, -0.79, 0.48]');


Нахождение похожих векторов:

SELECT
a.title AS title_a,
b.title AS title_b,
a.embedding <-> b.embedding AS distance
FROM items a
JOIN items b ON
a.id < b.id
ORDER BY distance;

6) pgcrypto - криптографические функции в PostgreSQL. Детали: https://habr.com/ru/companies/selectel/articles/925848/

Сохранение хэшированного пароля:
INSERT INTO users (username, password_hash) VALUES ('new_user', crypt('highly-secure-password123', gen_salt('bf', 10)));

7) hstore - key-value тип данных. На оф.сайте https://www.postgresql.org/docs/current/hstore.html

Создание таблицы с key-value столбцом для хранения атрибутов книги:
CREATE TABLE books (
id serial PRIMARY KEY,
name varchar,
attributes hstore
);


Вставка:
INSERT INTO books (name, attributes) VALUES (
'Harry Potter and the Philosophers Stone',
'author => "J. K. Rowling", pages => 223, series => "Harry Potter"'
);


и выборка по ключу атрибута:
SELECT name, attributes->'author' as author
FROM books
WHERE attributes->'series' = 'Harry Potter'


To be continued...
#PostgreSQL #db
👍1
Продолжение поста про расширения PostgreSQL.

Все что не влезло в предыдущий)

8) citext - case-insensitive хранение, а скорее сравнение строк в БД.

Создание таблицы с case-insensitive столбцом и вставка данных:

CREATE TABLE users (user_id SERIAL PRIMARY KEY, username CITEXT, email CITEXT);
INSERT INTO users (username, email) VALUES ('Иван Смирнов', 'ivan.smironoff@mail.ru');


Поиск без учета регистра:

SELECT * FROM users WHERE username = 'иван смирнов';


9) pg_stat_kcache - еще больше статистики по выполнению запросов, в особенности про работу с файловой системой - например, чтение из кэша ОС vs чтение с диска.
Что за данные собираются - можно узнать тут https://github.com/powa-team/pg_stat_kcache

Пример запроса: 5 самых затратных по времени запросов, их частоту выполнения, объемы обращений к диску и оперативной памяти, а также количество переключений контекста ядра ОС.

SELECT
round(total_exec_time::numeric, 0) AS time,
calls,
pg_size_pretty(exec_minflts * 4096) AS reclaim, pg_size_pretty(exec_majflts * 4096) AS faults,
pg_size_pretty(exec_reads) AS reads, pg_size_pretty(exec_writes) AS writes,
round(exec_user_time::numeric, 2) AS user_time, round(exec_system_time::numeric, 2) AS sys_time,
exec_nvcsws AS virtual_switches, exec_nivcsws AS involuntary_switches,
LEFT(query, 27) AS query_text
FROM pg_stat_statements s
JOIN pg_stat_kcache() k
USING(userid, dbid, queryid)
ORDER BY total_exec_time DESC
LIMIT 5;


10) isn - добавляет новые типы данных для проверки разного рода штрих кодов EAN13, UPC, ISBN (books), ISMN (music), and ISSN (serials) на допустимые префиксы. У модуля есть минус - набор допустимых префиксов постоянном меняется, следовательно, надо поддерживать актуальность расширения и может быть гэп по времени по поступлению обновлений.

Создание и вставка данных в таблицу с ISBN столбцом (уникальный номер книги):

CREATE TABLE test (id isbn);
INSERT INTO test VALUES('9780393040029');


11) pg_hint_plan - позволяет "прибить гвоздями" кусок плана выполнения запроса

Тут мы указываем, что надо использовать HashJoin и сразу смотрим реальный план выполнения запроса:

/*+ HashJoin(pt st) */
EXPLAIN SELECT * FROM s1.t1 st
JOIN public.t1 pt ON (st.id=pt.id);


12) pg_cron - что делает - понятно. Можно подумать, что расширение нарушает принцип - никакой логики в БД. Но оно полезно для другого - для служебных задач, например, периодически делать VACUUM:

SELECT cron.schedule('59 23 * * *', 'VACUUM');


На цифре 12 пожалуй и остановлюсь.

Что еще важно.
Часть расширений уже входит в поставку.
Какие именно - можно узнать выполнив команду:

SELECT * FROM pg_available_extensions;


Набор может различаться, в официальном дистрибутиве их на данный момент 60, в PostgrePro - 48, Сбер Pangolin - 119.

#postgresql #db #plugins
Астрологи объявили 2025 годом уязвимостей в Tomcat)

По крайней мере у меня складывается такое впечатление.
И похоже не только впечатление.
https://www.cve.org/CVERecord/SearchResults?query=apache+tomcat
24 уязвимости в 2025 году, по сравнению 15 с 2024. И год еще не закончился)

Предположу, что проблема скорее не в том, что Tomcat кривой по архитектуре или дырявый, а это обратная сторона популярности. Все-таки Tomcat - вариант по умолчанию встроенного сервера для Spring Boot приложений. И большинство его не меняют. Больше инсталляций, больше людей, которые их хотят сломать.

Но не Tomcat единым, как говорится.
Есть еще как минимум 4 сервера для JVM приложений:
1) Jetty
2) Undertow
3) Netty
4) Open Liberty

Все они production ready.
Кто может заменить Tomcat для Spring Boot приложений?
И нужно ли менять?

Начнем с того, кто не сможет.
Netty - это не контейнер сервлетов, синхронное взаимодействие Spring Web MVC он просто не поддерживает. Зато это выбор номер один для реактивщины. Как в Spring, так и в конкурирующих фреймворках Quarkus/Micronaut/Vert.x/Helidon.
И очевидно он выдает намного большую производительность и меньшее потребление памяти, по сравнению с Tomcat. Но требует полного переписывания логики на принципах реактивного программирования. А это сложно и требует я бы сказал повышенной квалификации.

Open Liberty - бывший IBM Websphere Liberty Profile, ушедший в open source. Хотя он и совместим со Spring Boot https://openliberty.io/docs/latest/deploy-spring-boot.html, два факта говорят о том, что смысла так делать нет:
1) одна из главных фишек Open Liberty - полная поддержка Java EE/Microprofile. Это точно не про Spring.
2) среди встроенных серверов Spring Boot нет Open Liberty в отличие от остальных четырех кандидатов.
Тоже побыстрее Tomcat, поддерживает модульность (а это необходимое условие при полной поддержке Java EE).

Остаются два кандидата - Jetty и Undertow.

Undertow - полностью JBoss Undertow - тоже бывшая коммерческая разработка, ушедшая в open source. Архитектурно сделана в неблокирующем стиле а-ля Netty, но с поддержкой сервлетов (Spring Web MVC). Что должно положительно сказаться на производительности. Плюс можно плавно мигрировать с кода в классическом стиле к реактивному. Минус по сути один - мало распространена, меньше сообщество. Да, и уязвимостей мало https://www.cve.org/CVERecord/SearchResults?query=undertow

И наконец Jetty. Архитектура классическая, как и у Tomcat. Разработчики делают фокус на модульной структуре: даже поддержка http (обычного, HTTP v1) обеспечивается модулем и может быть отключена. Кому интересно - вот список модулей из стандартной поставки: https://jetty.org/docs/jetty/12.1/operations-guide/modules/standard.html
Сообщество поменьше, чем у Tomcat, но достаточно большое, учитывая 20 лет на рынке. Уязвимостей сильно меньше в этом году https://www.cve.org/CVERecord/SearchResults?query=Jetty, при сравнимом количестве в 2024.

Вывод: а надо ли куда-то переходить? Для Spring Web MVC приложения большой разницы в производительности, потреблении памяти и надежности на ПРОМ я не ожидаю. Как я говорил - все сервера production ready. Но в плане уязвимостей - возможно, с Jetty жизнь станет немного спокойнее. Не ложное ли это успокоение - может "хакеры" еще не добрались до Jetty? Время покажет, но учитывая 20 лет на рынке ... очень может быть, что и нет, не ложное.

P.S. Интересно, что и IBM, и Redhat (JBoss)) пошли одним путем - выделить ядро своего сервера в отдельный lite компонент и сделать его open source.

#java #web #servlet
Если LLM не понимает твой код (процесс)...

В продолжение поста про мысль о том, что код, который не понимает LLM - плохой код.

Пишу сейчас агента, постоянно сталкиваются с скажем так ... не очень хорошей и совсем не стабильной работой LLM.
Начиная с какого-то уровня сложности промта LLM глючит - игнорирует прямые указания, выполняет лишние действия.
Первая мысль - ну тупая...)
Вторая - а может использовать LLM как своеобразный критерий качества аналитики и\или бизнес-процесса?
Если LLM глючит - аналитика не логичная, а процесс - кривой?

Причем и объяснение такому поведению модели есть. Если у нас сложный процесс, то у него большое значение цикломатической сложности - возможных путей выполнения программы. Это аналогия с кодом, т.к. в системном промте мы, пусть и более декларативно, тоже по сути пишем код. А работа LLM - это вероятностный процесс, т.е. на каждой развилке есть вероятность, что процесс пойдет не туда. Плюс код анализируется и выполняется последовательно, а промт - единовременно, и любой кусок пользовательского или системного промта может повлиять на план выполнения агента. И что в итоге мы получим ...?)

P.S. Вопрос конечно провокационный, но справедливости ради в попытках заставить LLM отвечать корректно я нашел ряд логических противоречий в промте. И перешел от 3 агентов к одному, т.к. в рамках одного проще поддерживать непротиворечивость промта.
P.P.S. Все же русский язык совсем не идеален для описания бизнес-логики.
..P.S. Как со всем этим делать мультиагентную систему, где логика пишется разными людьми и выполняется разными агентами - вопрос.

#llm #ai
Новости AI

1) появился инструмент сравнения разных LLM моделей - один забра запрос передаётся в 2 разные модели, скорость и качество ответа можно сравнить глазами. https://lmarena.ai/ Что интересно - доступны коммерческие LLM без регистрации и СМС, в смысле без VPN и оплаты

2) сейчас у большинства AI чатов появляется режим Research. Это ризонинг + поиск в интернете + какой-то набор tool для обработки полученных данных. Ещё из важного: составляется план исследования и дозапрашиваются непроходимые данные у пользователя. По сути это AI агент, заточенный под исследования.
Недавно тестировал такой режим у Mistral.
На мою просьбу сравнить скорость сборки Docker образов, модель не просто поискала в интернете тесты, а вначале уточнила сложность образа и возможность включить кэширование(!), после чего сделала вот такой план выполнения запроса:
1) создать docker файлы с нужным настройками
2) сформировать команду для измерения времени сборки для всех видов сборки
3) запустить команду n раз, посчитать среднее

В ответе кроме плана и таблицы с результатами (среднее, max, min), была конфигурация тестового сервера (!!!), описание плюсов и минусов всех инструментов сборки и рекомендации по их использованию.

Думаю - вот до чего техника дошла. И LLM модель, и поиск в вебе, и ещё виртуалку для выполнения задачи подняли. Реально - AI джун. И все бесплатно.
Но червячок сомнения точит... Спросил у модели - а ты реально виртуалку подняла для теста? Нет, говорит, не умею я такого. А откуда цифры тогда, дай источник? Нет источника, синтезировала цифры. Вот тебе ссылки, ищи там, результаты неточные (((
Вывод:
а) LLM модели врут
б) очень хотелось бы иметь такого джуна.

Из хорошего - инструмент доступен без VPN и есть бесплатные попытки. Полезен, если для выполнения задачи достаточно поиска. Ещё может с планом исследования помочь. Что интересно: неделю назад было 10 попыток в месяц, сейчас стало 5, кроме того появилось разделение по скорости - одна попытка быстрая, 4 - медленные. Экономика должна быть экономной)

3) OpenRouter - веб-сервис, являющийсф прокси-адаптером к куче LLM моделей с ChatGPT API. Область применения:
а) запуск кода, написанного для OpenAPI, на других моделях
б) динамический выбор модели в зависимости от задачи/цены без необходимости хранить кучу разных credentials у себя
в) отказоустойчивость.
Из хорошего - много моделей и небольшая наценка.
Из плохого - недавно закрыли доступ из России.
Из интересного - вот тут можно глянуть рейтинг моделей, используемых для разработки https://openrouter.ai/rankings?category=programming#categories
Ясно, что он искажён в части доли ChatGPT. Т.к. если тебя полностью устраивает ChatGPT, то ты не будешь использовать прокси. Но все же интересно)

#ai #llm #ai_agents
😁1
Всем привет!

Для IntelliJ IDEA появился новый плагин - Spring Debugger.
Цель создания понятна - мир бинов типичного Spring приложения огромен и запутан. Периодически что-то ломается, возникают вопросы типа такого: "Почему (не)поднялся тот или иной бин"?

Как всегда - статья: https://habr.com/ru/companies/spring_aio/articles/924550/

И кратко то, что меня зацепило:
1) в окне Spring показывает какие из бинов не инстанцированы или заменены моком
2) во время выполнения показывает фактически значения настроек в application.properties(yml) - там где они переопределены или рассчитаны
3) при заходе в метод подсказывает, если он выполняется внутри транзакции и детали транзакции: уровень изоляции, propagation, место начала
4) там же отображает состояние JPA кэша первого уровня в реальном времени
5) REPL для Spring-контекста: в окне Threads&Variables можно искать не только локальные объекты, но и любые Spring бины из контекста, с автодополнением и вызовом методов.
6) там же можно вбить имя настройки и увидеть откуда оно считалось (главное не забыть переключить область поиска с Java на Spring Properties).

Увы, доступен только в Ultimate. Если это не препятствие - рекомендую.

P.S. Вначале создаем Spring приложения с кучей бинов, потом героически преодолеваем сложность)

#idea #ide #debug #dropapp
UUID ключи в PostgreSQL

Я уже писал про версии UUID https://t.me/javaKotlinDevOps/264
Особенно интересной выглядит 7-я версия для использования в БД для построения индексов по двум причинам:
1) позволяет сортировать записи по времени создания
2) значение содержит метку времени, ее можно извлечь
Ну и эффект, наблюдаемый только в БД - записи ложатся последовательно в индексах и, соответственно, partition благодаря тому, что генерируются монотонно возрастающие значения.

Стандарт был принят в мае 2024 года https://datatracker.ietf.org/doc/rfc9562/

И не прошло и полгода (прошел год, но в мире БД это кажется даже быстро) и появляется PostgreSQL 18 c нативной поддержкой UUID v7 (функции uuidv7() и uuid_extract_timestamp) https://habr.com/ru/companies/spring_aio/articles/946168/

P.S. Если вчитаться в стандарт - попадаешь в кроличью нору:
1) для целей безопасности метка времени обрезается до миллисекунд
2) но чтобы получить возрастающие значения используется счетчик
3) счетчик инициализируется случайным числом, во избежание коллизий
4) есть защита от переполнения счетчика - допустимо использовать как счетчик ту часть метки времени, которую мы обнулили ранее, главное не перейти за границы миллисекунды. Если и этого не хватит - вопрос...
5) генератор должен хранить время t0, чтобы при переводе времени продолжать использовать исходное время и значения были уникальными и монотонно возрастающими
...

#postgresql #uuid
👀2
Небольшая заметка.

Мы обсуждаем, как хорошо AI пишет код. Но люди его используют совсем не для этого: https://t-j.ru/news/how-people-use-chatgpt

Это я, к тому, для каких задач его будут оптимизировать.

С другой стороны: да, 4% казалось бы немного. Но если сравнить с обычным поиском, то рост раза в 2. Точных цифр по доле запросов по разработке в поисковом трафике нет, но тот же ChatGPT дает неплохую оценку исходя из числа разработчиков и среднего числа их запросов в день.

#ai
Как быстрее погрузиться в код?

Речь про существующий микросервис и нового разработчика.
Я уже писал, что JavaDoc (KDoc) не является обязательным для каждого метода\поля или класса (как минимум для бизнес-приложения, общие библиотеки - особый кейс), т.к. документацию никто не читает.
А что же тогда будет документацией? Например, тесты. Их конечно тоже новичок не будет читать на 100%, но во-первых их и так нужно писать, а во-вторых - при рефакторинге падающий тест покажет, что забыли поправить, а в целом любой существующий тест изменяемого класса покажет, как он работает.

А недавно я нашел еще один полезный способ задокументировать микросервис так, чтобы этой "документацией" пользовались.
Начну немного издалека. Есть такая ИТ консалтинговая компания как Thoughtworks. Ну есть и есть, где мы и где консалтинг. Но там работает такой небезызвестный человек, как Мартин Фаулер. Главный научным руководителем https://www.thoughtworks.com/profiles/leaders/martin-fowler
А это внушает некий уровень доверия.
Так вот, компания ведет реестр технологий а-ля техрадар.
И в текущей его версии есть такая штука https://www.thoughtworks.com/en-de/radar/techniques/api-request-collection-as-api-product-artifact
как коллекция API запросов как артефакт продукта.
На самом деле мысль лежит на поверхности, я уже достаточно давно практикую прихранивание запросов в формате IDEA api collection вместе с исходниками в тех проектах, над которыми приходилось работать. Да, над форматом стоит подумать отдельно, возможно Insomnia будет по-универсальнее, зависит от команды и организации. Но сама идея мне очень нравится. Такой документацией точно будут пользоваться.

P.S. Кто ее должен делать - разработчики или тестировщики и нужно ли шарить коллекцию между ними - тоже вопрос для обсуждения. В идеале - думаю, что да.

P.P.S. Да, когда я говорю про артефакт продукта - это значит мало ее сделать, ее нужно поддерживать в актуальном состоянии.

#api #onbording #documentation
🔥1