Pull to refresh

Comments 52

Интересно, при каких условиях jit-оптимизация начнет увеличивать производительность?

В документации пишут

JIT-компиляция имеет смысл в первую очередь для длительных запросов, нагружающих процессор. Например, такой характер обычно имеют аналитические запросы. Для быстрых запросов накладные расходы, связанные с выполнением JIT-компиляции, часто будут превышать выигрыш от их ускорения.

по поводу tuple deforming есть интересные результаты

For large number of attributes JIT-ing of deform tuple can improve speed up to two time.

спасибо, по ссылке таблицы с десятком миллионов случайных записей (числа) операции sum ускорились на 30%.... скорее всего чтобы это стало заметно, вычислений нужно действительно много

Интересно, а можно явно указать, чтобы конкретный запрос делался с JIT? А то есть в системе запросы весом по 20 минут... они, конечно, не рилтаймовые, они, конечно, выполняются раз 5 дней и чисто внутренние, но все же.

Можно установить параметр на уровне сессии или транзакции, для этого соответственно выполнить SET jit=on или SET LOCAL jit=on

Отлично! Спасибо большое! Интересно, даст ли прирост. В запросе много вычислений. В теории, должно отлично лечь на JIT.

Для 1С лучше выключать или нет? Что то особо нигде не упоминается jit в рекомендациях

это лучше уточнить у консалтеров по 1С, но думаю что по умолчанию надо выключить

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

Также, интересно проверить, не будет ли воспроизводится пробелема с JITом, но без докера?

JIT
JIT

тормозил постоянно, при повторных запросах тоже.

я проверил на standalone PG 15.5 - JIT не кэшируется, два первых запроса длительностью 3-5 сек, затем JIT выключил и стало менее 30 мс

JIT не кэшируется

интересней было бы изучить эту проблему, а не лечить опухоль на пальце ампутацией руки.

Оффтоп, но при запуске JIT-скомпилированных ML моделей наблюдаются похожие приколы.

А вы вместо лечения каждоый бородавки на пальце начинаете изучать биохимию и генетику, чтобы исправить “проблему на базовом уровне”?

понятно. Да, судя по документации jitа в pg много с настройками не разгуляешься.

Может быть так, что запросы формируются так, что каждый запрос с точки зрения базы уникален? Может их там как-нибудь неаккуратно конкатенацией собирают без использования препаред стейтментов? Вот и приходится базе каждый запрос заново компилировать?

Там проблема в том, что бинарный код после JIT жёстко привязан к адресному пространству и запросу, а потому:
1) каждый новый запрос будет занимать всё новые адреса. Выгружать это всё не получится, так как у кода жёсткая привязка к адресам. То есть выгрузить можно, но если при попытке загрузить из кэша обратно окажется, что по этому адресу уже есть какой-то другой запрос, то что тогда делать? Жонглировать запросами в адресном пространстве СУБД? Так себе идея, особенно учитывая, что обрабатывающих запросы потоков много, а адресное пространство у них общее - что делать если разные потоки захотят исполнять разные запросы, которые были скомпилированы по одному адресу? А ещё (все) ОС и процессор очень не любят динамического изменения кода.
В качестве решения предлагается относительного легковесное исправление всех адресов при извлечении запроса из кэша. Но это достаточного тяжёлая операция. Кроме того при патчинге адресов возникают некоторые конфликты с оптимизацией.
2) генерируемый JIT код очень жёстко оптимизируется под конкретный запрос. Например, у вас там проверка на ноль, какая-нибудь или на константу - этот будет очень круто заоптимизировано при JIT, и если в другом запросе константа другая, то ой - наш старый кэш уже не подходит. Если же мы начнём генерировать универсальный код без оптимизации констант и сравнений, то это сильно снизит степень оптимизации кода и замедлит сложные и длительные запросы, ради которых этот JIT и задумывался. Кроме того, конкретно в PG (но в целом это общая проблема всех СУБД) вся оптимизация завязана на планировщик запросов (что логично), и нужно отключать часть оптимизаций уже на уровне планировщика, а значит потенциально замедлять вообще все запросы вне зависимости от JIT и нашего кэша.

Короче, на данный момент создать эффективный кэш оптимизированного бинарного кода невозможно. Не придумано пока никакого нормального общего решения и всё. А все предполагаемые пути решения проблемы ведут к тому, что нужно с ноля писать планировщик и оптимизатор, которые изначально архитектурно будут рассчитаны на последующую работу JIT и кэша. А это громадная работа и переписывание примерно три всего кода СУБД. Причём, всё равно придётся идти на компромиссы в какие-то моменты. Например, нужно, чтобы планировщик очень точно считал вычислительную сложность запросов, а это само по себе нерешённая пока задача (особенно в PG).

А почему новые запросы должны занимать новые адреса? Разве проверка на то, новый запрос или старый, не по SQL коду выполняется? Ну там, хеш от строчки посчитали и смотрим, есть ли для него скомпилированная версия.

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

Неужели нельзя воздействовать точечно? Неужели все настолько кондовое? Ну ладно может быть не предусмотрено манипуляторов из SQL, но внутри-то самой БД это должно быть? А манипулировать руками -- это все равно нужно только в крайних случаях.

Короче, на данный момент создать эффективный кэш оптимизированного бинарного кода невозможно.

Такое впечатление, что стоит титаническая задача во всех случаях всегда выдавать оптимальный результат. Разве нельзя решить проблему частично? Включать оптимизации точечно, под запросы? Вот администратор БД сказал -- этот запрос компилируй. В конце концов, приложение же не миллионы разных запросов шлет! Ну несколько тысяч наберется, разве нельзя построить статистику и самое тяжелое скомпилировать?

Кроме того, постоянно жалуются, что компилировать медленно. Я не понимаю. Приложение 24x7, ну пусть 10_000 запросов по 10 секунд на компиляцию каждого = 100_000 сек = сутки с четвертью. Всего лишь! Для приложения, которое месяцами работает. Ведь не стоит же задача скомпилировать все и сразу.

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

А вот не надо все что угодно совать в докер

при чем тут собственно докер? Если бы установили на хост со включенным jit было бы то же самое. Наоборот, докер тут может помочь получать воспроизводимый результат

Вот бы автор убрал из заголовка, что проблема в докере, чтобы такие существа как вы не считали, что новая упаковка (вместо привычных deb\rpm\tgz) как то влияет на функционирование систем.

Я просто DBA high load систем. 100 Тб базы, 2тб памяти сервера с правильным пробросом numa (как там у докера с этим?), так что желание завернуть все в докер смешно

Знание красивых слов не делают ваши утверждения инженерно верными. А у контейнеризации с этим никаких проблем нет, ведь упаковка никак не влияет на вкус шоколада, хотя в вашем случае цвет тот же, но это наверное не шоколад.

А корректный проброс numa? С этим даже у VMware проблемы

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

Сюрприз! Некоторые умные процессы (SQL server) так оптимизируют свою деятельность, чтобы threads минимизировали cross-numa interactions (numa aware). Поэтому если для них numa "mispresented", то вы получаете performance penalty

Переведу вашу белиберду на более понятный язык:

Хочу донести до вашего сведения, что программное обеспечение может обладать сложной логикой, которая во время выполнения вносит улучшения (оптимизации) работы, для уменьшения частоты переключения "потоков выполнения" (threads) на другие домены NUMA.

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

Ввиду вашего бреда (отсутствия логической связи), напомню, что по умолчанию контейнеризация не скрывает физические параметры сервера, а так же этого не надо делать вручную для контейнеров и для baremetal инсталляций. И вы этого тоже не делаете для линукс систем, потому что там другие механизмы привязки процессов к NUMA доменам.

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

Благодарю от имени всех, кто не разбирается в вопросе!

Это важное дело - публично опровергать ложные утверждения

Если речь про что-то типа NUMA Affinity или CPU Pinning и т.п., то будет достаточно добавить --cap-add=sys_nice и/или прописать кастомный seccomp, разрешающий numactl в контейнере.
Если docker только про упаковку, и безопасность не парит совсем (равнозначный хосту контейнер), можно дать ему --privileged и забыть про привилегии совсем.

> А корректный проброс numa? С этим даже у VMware проблемы

Ну, vmware - vmware рознь...
Если это про Tanzu и ко (контейнеризация) - никогда не слышал про те "проблемы"... Можно ссыль?
Если же про VMs, то как раз у контейнеризации тут должно быть всё много лучше и проще чем у "настоящей" виртуализации, собственно по определению обеих... Ибо контейнерная технология напрямую использует физические ресурсы ядра операционной хост-системы, а не эмулирует их как виртуальные компоненты для каждого экземпляра гостевой VM.
Т.е. как изоляция, так и противоположное действие много проще там (capabilities, namespaces, control groups, mapping и вот это вот всё на уровне ядра).
Поэтому собственно контейнеры - это больше про упаковку, чем про "безопасное", полностью изолированное от хост-системы и других гостей, окружение (как оно декларируется у виртуализации).
По этой же причине совершенно нормально пускать контейнеры в гостевой VM, при том что наоборот - это скорее исключение (и имеет смысл только в узко-специфических случаях, типа легаси софта виртуализации и т.п.)

Если автор бы убрал из заголовка, статью бы прочитало кратно меньше людей. Но заголовок вроде "в такой-то версии официального Docker-образа постгреса jit-флаг включен по умолчанию, что тормозит какие-то запросы" не привлечет аудиторию.

Поправьте пожалуйста заголовок. Проблема не в docker, а в jit.

ставим PG в конфигурации по умолчанию (т.е. грубо yum install postgresql15-server) - проблемы нет, ставим также докер (docker pull postgres) - проблема есть. По идее образ докера надо также делать без провайдера JIT, и дополнительный образ с JIT кому это действительно необходимо.

У меня такая же нога, но болит. В конфигурации по умолчанию, которая принята в компании "Х" проблема воспроизводится. Как долго вы ошибку выжившего будете предоставлять как аргумент некорректному заголовку статьи у вас?

JIT - встроенный функционал в PostgreSQL, который включен по умолчанию и призван его ускорить. Проблема в том, что он применился там, где это было не нужно. Это проблема PostgreSQL, а не того кто его собирал, тот кто собирает не должен знать и учитывать крайние случаи когда он вредит. И более того, JIT всегда можно отключить в настройках сервера, для этого не нужно делать несколько версий образа.

Также судя по всему, PostgreSQL собирается без LLVM не во всех дистрибутивах (в Debian и некоторых других собирается с ним), следовательно его отсутствие не является стандартной конфигурацией, а лишь решением мейнтейнера пакета, который мог не включить LLVM например в целях избежания конфликтов или притягивания довольно большой зависимости.

его отсутствие не является стандартной конфигурацией, а лишь решением мейнтейнера пакета

В этом и есть проблема, фактический набор функционала PostgreSQL зависит от мейнтейнера пакета/образа.

В пакетах и образах для Debian, Ubuntu, FreeBSD, Docker провайдер JIT включен в основной пакет/образ при установке PG-сервера и таким образом включен по умолчанию.

В Redhat/Centos, SUSE, MacOS, Windows - при установке основного пакета/образа JIT не устанавливается, т.е. выключен.

В пакетах и образах для Debian, Ubuntu, FreeBSD, Docker

Так и перечислили бы в заголовке эти системы. А так вы осознанно указали только Docker, чтобы набрать хайпа.

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

грубо yum install postgresql15-server - проблемы нет

В Redhat/Centos JIT не устанавливается, т.е. выключен.

Но ведь yum - команда из Redhat, где JIT выключен, о результатах проверки в Debian без докера - ни слова.

Тогда максимум проблема в настройках конкретного docker-образа. Так что заголовок всё ещё обманывает.

Проблема решена. Но чтобы она не повторялась, рекомендуем запускать PostgreSQL в Docker с выключенным по умолчанию JIT.

Проблема не решена, к сожалению. Такое поведение PostgreSQL должно расцениваться как ошибка. И я очень удивлен что оно попало в релиз. Надо докопаться до реальной сути проблемы. Вы не пробовали написать в mailing list на эту тему? Если это реальная бага в postgres, то её надо хотя-бы зарепортить. Либо это какая-то ваша мисконфигурация в базе/системе/где-то еще и тогда ее нужно найти и устранить.

Проблема тут только в том, что в официальный докер-образ postgres включён пакет postgresql-llvmjit, а в инструкции по развороту на хосте ничего по postgresql-llvmjit и ни про какого другого провайдера не написано. На хосте, если следовать manам, jit не работает из-за отсутствия либы, а в докере работает.

Бага в документации, имхо.

Ну в любом случае это следует прояснить с разработчиками. Если бага в документации - пусть исправят документацию, если бага в докер-файле - пусть исправят докер-файл.

Но вообще, включение JIT не должно приводить к просадкам. Тем более к ТАКИМ просадкам. Как по мне - это бага где-то глубже. А наличие postgresql-llvmjit просто провоцирует её.

И вообще, come on, если ваша компания занимается разработкой тулинга для postgres, то вы явно должно понимать внутренности postgres лучше других и репортить такие штуки разработчикам самого движка.

Так тут docker не причем, дело в jit. На докер и так много клевещут, поправьте заголовок пожалуйста

Короче - докер не при чем...

Мне кажется или в документации было прямым текстом написано не запускать в docker, если надо быстродействие?

А как контейнеризация влияет на производительность? Старые заблуждения о том что нельзя СУБД упаковывать в контейнеры ошибочно попали в документацию.

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

Если немного нигилистки подойти и сомневаться даже в создателе, то иногда можно найти баги и ошибки у создателя.

Образ postgres не на базе alpine был? Не пробовали воспроизвести на базе другого дистра?

пробовал официальные образы bookworm, bullseye, alpine - во всех jit включен и работает.

Я не про jit, я про производительность.

Была версия что в alpine, из-за использования вместо glib другой библиотеки, может присаживаться производительность из-за менее эффективных аллокаторов что ли ... По крайней мере на похожее жаловались недавно в одном из подкастов php-ники про alpine.

Sign up to leave a comment.