Pull to refresh

Comments 15

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

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

Тестировалось на разном железе.

SATA SSD, три типа PCI-E NVME, и даже RAM-disk.

Виртуализация и bare-metal от 1-го до 16-ти ядер

С разными размерами баз, настройками буферов и степенью параллелизма.

Меняются абсолютные показатели, но относительные всегда плюс/минус одинаковые.

Странная статья.

Что такое взрослые нагрузки для Вас? Вы бы хоть в каком-то выражении их описали.

Если Вы хотите показать результаты бенчмарков, то выкладывайте и конфигурацию железа и конфигурацию пг и как проводили тесты. Хотите сравнить с ораклом - ну вперед, все те же данные нужны (железо, конфиги, тесты). Здесь же ничего.

Я тут мимо проходил, что-то написал, каких-то графиков накидал. Зачем?

Сам вопрос "что такое взрослые нагрузки" тянет не на статью, а на диссертацию. Актуальность которой теряется прямо во время написания - выходят новые "фичи", снимаются старые ограничения и т.д.

Я видел и базы 200Гб, которые "умирают" от нагрузки, и 10 Тб, которые живут вполне себе нормально.
Некоторый диапазон, который компании устанавливают для себя приведен в начале статьи: это 1-5 Тб. И эту цифру они выбирают исходя не только из производительности, но и с учетом возможностей инфрастурктуры, возможности восстановления нужных объемов в допусках SLA, резервирования и так далее.

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

Ответьте на один вопрос - а у вас какой размер самой большой базы Postres и под какой нагрузкой? Не вы слышали у кого-то, а именно у вас?

И в статье нет сравнения с Oracle, в статье сравнение ASYNC IO и не-ASYNC IO.

То, что вам не хватило цифр - ок. Но приходится выбирать - публиковать статью со всеми четырьмя тысячами замеров, или популярно и доступно рассказать для не-специалистов в БД, о чем собственно, речь.

Раздел "научпоп" там не просто так поставлен.

Предыдущее нововведение такого масштаба было в Postgres 10 — нативное партиционирование.

Какое-то странное заявление. Нативное партиционирование без автоматического создания партиций - такое себе. Грустно, на самом деле, от такого партиционирования.
С другой стороны партиционирование - это про рукоблудие по-взрослому.
А параллельное сканирование, агрегаты и вот это вот всё, что появилось в 9.6 - это так, мелочи? Никак на производительность не влияют?

Если я ничего не упускаю, все графики/тесты на Postgres 18. ИМХО имеет смысл сравнить производительность с Postgres 17 на том же железе.

Абсолютно верное замечание.

И первой была серия тестов версий 17 и 18 на том же самом железе, чтобы убедиться что 17-ый идентичен 18-му в "классическом" режиме.

так, стоп.. с чего резко такая уверенность, что 1 и тот же запрос на разном сетевом стеке должен выполнятся быстрее или медленнее? 0_о

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

Немного не понял про сетевой стек, он ок.

Почему свеженалитые данные могут вести тебя "не так".

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

Второе - план запроса. Если статистика не актуальна, то планы могут "плыть", но это легко отлавливается.

Третье менее очевидно, но тоже имеет место быть: это отложенная очистка блока. Идея в чем - если транзакция достаточно большая, то она по commit не идет в каждый затронутый блок, не снимает блокировки, не меняет статусы транзакций - это слишком накладно.

За нее это сделает следующий пришедший в страницу select. Но даже такое снятие блокировки со строки - это модификация страницы, а значит - запись в wal со всеми вытекающими. А уже следующий select "чистить" ничего не будет и ведет себя немного иначе.

Мне было бы гораздо интереснее и любопытнее понять почему тяжелый запрос, выбирающий в одной сессии каждую десятую запись из набора (по условиям) и выполняющийся скажем 4секунды, в соседней сессии, выбирающий тоже каждую десятую запись (со смещением n % m) из того же набора выполняется .. а те же самые 4секунды. КЭШа в Постгрес не завезли? Выборка набора идет строго по одному комплекту условий?

Решил ускорить сервис: распараллелил запросы асинхронно .. ан нет. 1 поток выбирает 4сек. и 8 потоков выбирают 35сек.. фантастика. Постгрес 14,15,17.

Классическая ситуация при ручной многопоточной обработке :)

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

Распараллеленивание построчно, например, каким нибудь mod(hash()) - наверное самая неэффективная стратегия. Во-первых, это заставляет каждый поток читать весь объем данных, и вместо чтения огромной таблицы один раз, она читается 10 раз. Во вторых, это заставляет делать вычисления mod(hash()) для каждой строки в каждом потоке. В-третьих - конкуренция. Если потоки идут по близким данным, то достаточно двум сессиям столкнуться на блокировке, и все остальные тоже туда же "налетят", образуя "кучу-малу". Процесс этот лавинообразный - конкуренция порождает конкуренцию -> повышает нагрузку. Если в потоках данные еще и модифицируются, да хотя бы статус "в обработке" меняется, то все это так же лавинообразно встает на блокировках.

Оптимальная стратегия, конечно, зависит от задачи и условий.
Если это переливка больших объемов, то лучше делить таблицу на диапазоны и отдавать свой диапазон каждому потоку. Отдельный уровень "просветления" - делать это не на логическом уровне: значении, например, PK, а прямо на "физическом" - деля на диапазоны прямо пофайлово через ctid. Это самый быстрый способ указать базе на конкретную строку или диапазон. Но нужно хорошо понимать ограничения и подводные камни.

Классический способ "развести" потоки и не читать данные помногу раз - деление на диапазоны по какому нибудь достаточно хорошо распределенному значению, идеальный пример - Primary Key. Если условия позволяют, то делать это можно прямо при старте потоков, не заморачивась каким-либо координатором.

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

Если это какая-то большая очередь для разбора и обработка строки занимает существенно больше времени, чем выбор этой строки, то можно идти и по всем строкам каждому потоку, пропуская уже обрабатываемые "соседом" строки через skip locked.

Бывают ситуации когда обработчик очереди просто нужно "дергать" чаще. Не давать скопиться значительному объему.

Есть и другие способы и стратегии, но для mass process, хорошими практиками будет не читать данные по нескольку раз и развести потоки так, чтобы они не пересекались в одних структурах.

странное у вас понимание async это не про утилизацию СХД - это про утилизацию CPU когда наоборот, СХД отвечает долго и ваш поток (и ядро в какой-то мере) заблокирован без дела, хотя мог бы делать что-то полезное. Так что все наоборот ;) и это кстати отдельная проблема как делать IO в случаи быстрых СХД, которые работают со скоростью RAM например, ведь для чтения и записи в память нет никаких прерываний и асинхронных чтений. А зачем делают async к быстрым СХД - так потому что они условно быстрые, они быстрые за счет широкой шины а не низкой латенси - там через async одним потоком можно сформировать огромный план работ для СХД и он ее переварит за счет своего внутреннего параллелизма. А обычным образом вам для этого нужно было бы потоков раз 30 больше создать. А async для постгреса нужен для облачных сред, где диски могут подтупливать, я в описании фичи видел именно такую мотивацию.

ЗЫ: я не прям эксперт в теме, так интересовался со стороны java разработки

Почему странное, если вы описали тоже самое что в статье, но другими словами? :)

На первой схеме и показано что CPU простаивает пока идет ввод-вывод, и можно его "уплотнить" (больше утилизировать), если не ждать IO. Пусть пока делает что то полезное. :) Это вторая схема.

Так что всё верно - async IO это про утилизацию CPU. И, соответственно, более быструю обработку и, как следствие, более быстрый результат.

Sign up to leave a comment.

Articles