В исследовании сравнивались реализация lock-free списка с традиционным списком на блокировках, и оба варианта использовали dsa для аллокации отдельных элементов.
...
Тот факт, что dsa внутри себя использует блокировки, был известен и принят как часть прототипа.
Я могу вам посоветовать только не делать так и уволить серьезно поговорить с тем, кто придумывал такую архитектуру прототипа))
Эта функция же обертка над gettimeofday, которая не умеет монотонное время (у нее может идти время и назад). Кажется, для замеров около миллисекунды ее использовать просто нельзя.
В таком виде синхронизация бекендов не требовалась
А как вы гарантировали, что запросы, отправленные из нескольких бекендов, дождутся друг друга и начнут одновременно менять список в общей памяти?
Я забыл, что у вас у списка же один писатель и один читатель.
В нашем случае память выделяется (с помощью dsa_allocate) под каждый элемент списка индивидуально при вставке элемента.
Получилось тогда очень забавно: вы создали "lock-free" структуру, у которой при создании каждого элемента вызывается блокировка (dsa_allocate и alloc_object везде используют LWLockAquire). Не говоря о том, что вызывать dsa_allocate на каждый элемент - это очень дорого с точки зрения скорости.
Расскажите, как вы измеряли производительность очередей через параллельный запуск запросов с собственной функцией? Вы как-то синхронизировали через общую память начало выполнения всех бекендов? Где вы измеряли время теста: в функции через тики процессора или смотрели на системное время в psql? Если это собственная реализация, не хотите ей поделиться с сообществом или ванильным pg?
Исходя из статьи, список в общей памяти у вас не является кольцевым буфером. И когда выделенный кусок памяти заканчивался, вы создаете новый, как-то переносите данные в него и возвращаете старую память ОС? Поэтому вы и используете динамическую общую память с относительными адресами, вместо фиксированного куска общей памяти с абсолютными адресами на старте.
При логическом удалении вы проходите весь непрочитанный хвост списка за O(n) и в нужном элементе проставляете бит удаления?
Кажется, что если это так, то алгоритм не очень эффективный, чем и объясняется небольшое отличие между версии на атомиках с блокирующейся очередью. Думали ли вы в сторону кольцевого lock free буфера в обычной общей памяти с какими-нибудь tombstone записями для удаления?
Кстати, а по опыту - откуда приходят запросы таких 99% пользователей? Это ORMы, или это реально аналитики, которые не очень понимают, что они пишут на SQL?
Тот SQL который вы напишете недоопределен - там порядок джоинов фиксирован, но не выбраны алгоритмы и access paths (способы доступа к данным). Поэтому все аналитические СУБД используют стоимостные оптимизаторы.
А я наброшу. Кажется, что для решения этих проблем стоимостный оптимизатор не обязателен:
Алгоритмы можно выбирать по простым правилам, например: merge при совпадении сортировок, nested loop для кореллированных соединений, а в остальных случаях - hash.
Методы доступа к данным (т.е. выбор индексов) выбираются по предикатам в фильтрах. По принципу «видим подходящий индекс для фильтра - используем, не видим - используем обычную таблицу).
То есть технически можно пойти по пути sqlite и не использовать стоимостную модель. И дальше все в руках авторов запросов, так как правила очень простые. И если автор захочет где-то материализацию и новую сортировку, то он сделает руками нужный cte (а не планировщик будет пытаться переписать суть плана за человека).
Мой опыт говорит, что когда ты пишешь сложные запросы, ты борешься с планировщиком и пытаешься его хакнуть через хинты или разные конструкции в sql. И самый главный страх, что на новой статистике план изменится, планировщик построит ерунду и запрос начнет исполняться очень долго.
Просто поразительно. Я пришел прочитать статью по ссылке из телеги и украсть пару идей для нашей документации. Прошелся по ссылкам, не нашел команд (а мне хотелось посмотреть, как это сделано у вас), подсветил проблему, которой уже года четыре как минимум. В результате получил порцию токсичности от тебя на ровном месте. В общем, так себе опыт.
Дима, я действительно хочу подсветить проблему. Просто вспомни, что произошло с конверсией сайта документации PostgresPro, когда они завершили перевод PostgreSQL - им никакой СЕО не нужен после этого. Ну и став первыми с русской документацией вы автоматически становитесь стандартом и определяете терминологическую базу во всей русскоговорящей среде. Да, кстати, если будете делать, я рекомендую посмотреть на пример SQLite с их railroad диаграммами синтаксиса.
Подскажите, а когда у вас появится для ADB список SQL команд? Пока есть только ссылка на документацию VMware в загадочном разделе «список команд SQL, не поддерживаемых в ADB».
И все же, какого ресурса вам не хватает (ЦПУ, диск, память)?
Количество сегментов обычно увеличивают, если недостаточно утилизирован ЦПУ. В вашем же случае (ETL и пользователи), вряд ли вы недостаточно его утилизируете. Вообще единственная причина, почему на одном хосте более одного сегмента в GP - это отсутствие хорошо работающего параллельного сканирования в рамках одного сегмента. В PG для этого поднимаются фоновые процессы, GP использует пул соединений от координатора к сегменту. Если научить GP хорошо утилизировать ЦПУ при сканировании, получится уйти от кучи сегментов на хосте. Но повторюсь, недостаточная утилизация - явно не ваш случай.
Поэтому и вопрос - что вам мешает настроить ресурсные группы и разложить ETL и пользователям по разным коробкам? Там же куча возможностей для этого, вплоть до резервирования конкретных ядер ЦПУ под конкретную группу. Вместо этого два кластер - почему?
А за какие ресурсы идет конкуренция, что приходится делать два кластера и экспортировать из ETL в пользовательский кластер? На первый взгляд, если это ЦПУ, то есть ресурсные группы. Если диск, то вы можете разносить схемы сырых данных и витрин по разным табличным пространствам на разные диски. Память тоже делится через менеджер памяти (настраивается через те же ресурсные группы). Нехватка соединений решается пулером.
Я просто сильно удивился фразе «что на GreenPlum считалось часами, мы могли уже считать на потоке с помощью Flink, еще и в режиме near-realtime». У меня возникло подозрение, что причина была именно заливке данных через координатор, которая крайне медленно работает и сильно утилизирует ресурсы кластера. Я правильно понимаю, что вы добавили Flink и свертку данных на нем, чтобы координатор не захлебывался (меньше льем)? И так вам было сделать проще, чем научить сегменты забирать данные из Кафки?
А вы из Flink льете в S3 и оттуда забираете через CH и GP? Или одной рукой льете в S3 для CH, а второй вставляете в GP? Если второе, то в GP у вас вставка через координатор, или вы написали свой коннектор под GP для вставки через сегменты?
Без S3 Select (при том желательно с поддержкой SIMD/SSE для фильтрации) вы не построите эффективное разделение слоя хранения (S3) и слоя вычислителей (Greenplum). И все данные будете лить через PXF и фильтровать их узлами Greenplum, что неэффективно.
Я могу вам посоветовать только не делать так и
уволитьсерьезно поговорить с тем, кто придумывал такую архитектуру прототипа))Эта функция же обертка над gettimeofday, которая не умеет монотонное время (у нее может идти время и назад). Кажется, для замеров около миллисекунды ее использовать просто нельзя.
А как вы гарантировали, что запросы, отправленные из нескольких бекендов, дождутся друг друга и начнут одновременно менять список в общей памяти?Я забыл, что у вас у списка же один писатель и один читатель.
Получилось тогда очень забавно: вы создали "lock-free" структуру, у которой при создании каждого элемента вызывается блокировка (dsa_allocate и alloc_object везде используют LWLockAquire). Не говоря о том, что вызывать dsa_allocate на каждый элемент - это очень дорого с точки зрения скорости.
Расскажите, как вы измеряли производительность очередей через параллельный запуск запросов с собственной функцией? Вы как-то синхронизировали через общую память начало выполнения всех бекендов? Где вы измеряли время теста: в функции через тики процессора или смотрели на системное время в psql? Если это собственная реализация, не хотите ей поделиться с сообществом или ванильным pg?
Правильно ли я понял:
Исходя из статьи, список в общей памяти у вас не является кольцевым буфером. И когда выделенный кусок памяти заканчивался, вы создаете новый, как-то переносите данные в него и возвращаете старую память ОС? Поэтому вы и используете динамическую общую память с относительными адресами, вместо фиксированного куска общей памяти с абсолютными адресами на старте.
При логическом удалении вы проходите весь непрочитанный хвост списка за O(n) и в нужном элементе проставляете бит удаления?
Кажется, что если это так, то алгоритм не очень эффективный, чем и объясняется небольшое отличие между версии на атомиках с блокирующейся очередью. Думали ли вы в сторону кольцевого lock free буфера в обычной общей памяти с какими-нибудь tombstone записями для удаления?
Кстати, а по опыту - откуда приходят запросы таких 99% пользователей? Это ORMы, или это реально аналитики, которые не очень понимают, что они пишут на SQL?
А я наброшу. Кажется, что для решения этих проблем стоимостный оптимизатор не обязателен:
Алгоритмы можно выбирать по простым правилам, например: merge при совпадении сортировок, nested loop для кореллированных соединений, а в остальных случаях - hash.
Методы доступа к данным (т.е. выбор индексов) выбираются по предикатам в фильтрах. По принципу «видим подходящий индекс для фильтра - используем, не видим - используем обычную таблицу).
То есть технически можно пойти по пути sqlite и не использовать стоимостную модель. И дальше все в руках авторов запросов, так как правила очень простые. И если автор захочет где-то материализацию и новую сортировку, то он сделает руками нужный cte (а не планировщик будет пытаться переписать суть плана за человека).
Мой опыт говорит, что когда ты пишешь сложные запросы, ты борешься с планировщиком и пытаешься его хакнуть через хинты или разные конструкции в sql. И самый главный страх, что на новой статистике план изменится, планировщик построит ерунду и запрос начнет исполняться очень долго.
А вы сравнивали скорость чтения из АОС таблиц с BRIN индексом против Parquet файлов с bloom фильтрами (через FDW)?
Просто поразительно. Я пришел прочитать статью по ссылке из телеги и украсть пару идей для нашей документации. Прошелся по ссылкам, не нашел команд (а мне хотелось посмотреть, как это сделано у вас), подсветил проблему, которой уже года четыре как минимум. В результате получил порцию токсичности от тебя на ровном месте. В общем, так себе опыт.
Дима, я действительно хочу подсветить проблему. Просто вспомни, что произошло с конверсией сайта документации PostgresPro, когда они завершили перевод PostgreSQL - им никакой СЕО не нужен после этого. Ну и став первыми с русской документацией вы автоматически становитесь стандартом и определяете терминологическую базу во всей русскоговорящей среде. Да, кстати, если будете делать, я рекомендую посмотреть на пример SQLite с их railroad диаграммами синтаксиса.
P.S. Будь менее токсичным, пожалуйста.
Подскажите, а когда у вас появится для ADB список SQL команд? Пока есть только ссылка на документацию VMware в загадочном разделе «список команд SQL, не поддерживаемых в ADB».
А проводилось сравнение по скорости и компрессии между плагином dd boost и встроенными zstd/gzip в gpbackup? Можете рассказать про результаты?
На самом деле исправление было сразу портировано во все стабильные версии pg. Вот, например, коммит для 9.6.
И все же, какого ресурса вам не хватает (ЦПУ, диск, память)?
Количество сегментов обычно увеличивают, если недостаточно утилизирован ЦПУ. В вашем же случае (ETL и пользователи), вряд ли вы недостаточно его утилизируете. Вообще единственная причина, почему на одном хосте более одного сегмента в GP - это отсутствие хорошо работающего параллельного сканирования в рамках одного сегмента. В PG для этого поднимаются фоновые процессы, GP использует пул соединений от координатора к сегменту. Если научить GP хорошо утилизировать ЦПУ при сканировании, получится уйти от кучи сегментов на хосте. Но повторюсь, недостаточная утилизация - явно не ваш случай.
Поэтому и вопрос - что вам мешает настроить ресурсные группы и разложить ETL и пользователям по разным коробкам? Там же куча возможностей для этого, вплоть до резервирования конкретных ядер ЦПУ под конкретную группу. Вместо этого два кластер - почему?
А за какие ресурсы идет конкуренция, что приходится делать два кластера и экспортировать из ETL в пользовательский кластер? На первый взгляд, если это ЦПУ, то есть ресурсные группы. Если диск, то вы можете разносить схемы сырых данных и витрин по разным табличным пространствам на разные диски. Память тоже делится через менеджер памяти (настраивается через те же ресурсные группы). Нехватка соединений решается пулером.
Я просто сильно удивился фразе «что на GreenPlum считалось часами, мы могли уже считать на потоке с помощью Flink, еще и в режиме near-realtime». У меня возникло подозрение, что причина была именно заливке данных через координатор, которая крайне медленно работает и сильно утилизирует ресурсы кластера. Я правильно понимаю, что вы добавили Flink и свертку данных на нем, чтобы координатор не захлебывался (меньше льем)? И так вам было сделать проще, чем научить сегменты забирать данные из Кафки?
А вы из Flink льете в S3 и оттуда забираете через CH и GP? Или одной рукой льете в S3 для CH, а второй вставляете в GP? Если второе, то в GP у вас вставка через координатор, или вы написали свой коннектор под GP для вставки через сегменты?
Без S3 Select (при том желательно с поддержкой SIMD/SSE для фильтрации) вы не построите эффективное разделение слоя хранения (S3) и слоя вычислителей (Greenplum). И все данные будете лить через PXF и фильтровать их узлами Greenplum, что неэффективно.
А реализация S3-совместимого хранилища в облаке КРОК поддерживает S3 Select? И, если не секрет, какое вы используете решение для хранения в S3?