ADG Оставить заявку
Блог Данные и аналитика 4 мин чтения

PostgreSQL 18 Beta: тестируем async I/O на реальной OLTP-нагрузке и смотрим на цифры

Подняли тестовый стенд на PostgreSQL 18 beta: первые замеры async I/O на OLTP-нагрузках дают +15-20% по throughput. Делимся методикой и наблюдениями.

Контекст момента

PostgreSQL 18 Beta 1 - выход первой бета-версии с async I/O и улучшениями parallel query, июль 2025

PostgreSQL Global Development Group выпустила первую бета PostgreSQL 18. Мы не большие любители тестировать беты на production, но несколько раз в год всё-таки поднимаем тестовый стенд на свежем релизе - чтобы не ловить сюрпризы в момент перехода, когда заказчики начнут спрашивать «а мы готовы?». С 18-й решили не тянуть.

Что в этом релизе интересно

Из двух главных вещей, которые гнали нас на стенд, - async I/O и улучшения parallel query.

Async I/O - долгожданная переработка ввода-вывода на уровне ядра Postgres. До 18-й все операции чтения/записи в shared buffers шли синхронно: воркер ждал диска, тред блокировался. Теперь Postgres умеет выдавать несколько I/O-запросов параллельно и продолжать работу пока они не завершились. Это не просто оптимизация конкретного запроса - это изменение в том, как сервер работает с железом под нагрузкой.

Parallel query в 18-й получил ещё несколько улучшений: расширилось число планов, которые могут идти параллельно, появились доработки в cost estimation для параллельных hash join. Для нас это менее горячая тема, чем async I/O, - на OLTP с короткими транзакциями параллельные запросы редко включаются.

Как мы поднимали стенд

Стенд - отдельная виртуальная машина, 16 vCPU, 64 ГБ RAM, NVMe-диск. Не iron-replica production, но достаточно близко к тому, на чём живёт несколько наших клиентов. Установили postgresql18beta1 из официального PGDG-репозитория, рядом поставили 17.4 для контрольного сравнения.

Нагрузку имитировали pgbench с кастомными скриптами под OLTP-профиль: смесь коротких SELECT с point lookup по индексу, UPDATE одной строки, INSERT с sequence. Scale factor подобрали так, чтобы рабочий набор данных не помещался целиком в shared_buffers - иначе диск не задействован и async I/O измерять бессмысленно.

Параметры гнали в двух конфигурациях:

  • Умеренная нагрузка - 32 клиента, примерно 60% от насыщения сервера.
  • Высокая нагрузка - 128 клиентов, сервер в зоне давления по I/O.

Для async I/O в PG18 ключевой параметр io_method. По умолчанию - worker, это фоновые воркеры для асинхронных операций. Есть ещё io_uring для Linux с поддержкой (у нас ядро 6.1, работает). Гоняли оба варианта.

Что намерили

На умеренной нагрузке разница между PG17 и PG18 небольшая - в пределах погрешности, иногда PG18 чуть быстрее, иногда нет. Это ожидаемо: при 32 клиентах диск не является бутылочным горлом, async I/O просто не раскрывается.

На высокой нагрузке картина интереснее. С io_method=worker throughput (транзакций в секунду) вырос примерно на 15-17% по сравнению с PG17 при тех же условиях. С io_method=io_uring - около 18-20%. Latency при этом снизилась заметно больше в хвостах: p99 улучшился сильнее, чем median, - это видно в гистограмме pgbench. Очевидно, что именно I/O-ожидание давало самые длинные хвосты, и async I/O его срезает.

Параллельно посмотрели на pg_stat_io - новый системный вид, появившийся ещё в PG16 и расширенный в 18-й. Там видно читаемые блоки, хиты, операции read/write по backend-типу. При io_uring количество ожиданий на I/O (io_time в pg_stat_activity) у воркеров упало ощутимо - сервер реально меньше торчит в ожидании диска.

Что стоит учитывать

Несколько наблюдений на полях:

  • io_uring не везде одинаков. На нашем стенде с ядром 6.1 работает, но мы знаем среды с более старыми ядрами или ограничениями seccomp, где io_uring отключён системно. В таком случае worker - разумный дефолт, тоже даёт прирост, пусть и чуть меньше.
  • Shared_buffers по-прежнему важен. Async I/O помогает тогда, когда данные реально читаются с диска. Если рабочий набор умещается в кэш - прироста почти нет. Настройка памяти никуда не делась из уравнения.
  • Это бета. Мы видели один необъяснённый краш при стрессовом тесте с io_uring и высоким concurrency - воспроизвести стабильно не смогли, сообщили в трекер. Для production использования пока рано, но это бета и так и задумано.
  • Параметр max_io_concurrency появился в 18-й для ограничения числа параллельных I/O-операций на клиента. По умолчанию 16, на быстрых NVMe можно поднять. Мы попробовали 32 - небольшой дополнительный прирост на нашем стенде, но тут нужно смотреть по железу.

Где мы сейчас

Стенд работает, прогоняем дополнительные сценарии - хотим посмотреть на поведение с WAL под нагрузкой и на maintenance операции (VACUUM, ANALYZE) с async I/O. Результаты по этим сценариям будут позже.

Для заказчиков, которые уже используют PG17 и думают о следующем шаге: 18-я выглядит интересно именно для нагрузок, где диск является ограничением. Если у вас OLTP с активной записью и рабочий набор не влезает в RAM - есть смысл поднять свой тестовый стенд на beta и посмотреть на свои цифры. Методику описали, воспроизвести несложно.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.