Бенчмарки кэша PostgreSQL

Измерено на Apple M3 Max с PostgreSQL 16. В каждом сравнении для чтения через кэш и обычного SQL используются один и тот же клиент, набор данных и декодированные результаты строк.

Где кэш помог, а где нет

Измерения Node.js используют клиент macOS и сервер Docker; измерения Go и RESP запускают оба компонента внутри виртуальной машины Docker. На каждой странице приведены исходные повторы, точные версии и затраты ресурсов сервера. Эти отдельные конфигурации не позволяют ранжировать языки. Примеры соединений см. в разделах Node.js, Go или RESP.

Запустите одно и то же сравнение для каждого клиента

Из корня репозитория, с Docker, Node.js 20+ и Go 1.25+:

./examples/benchmark.sh all > comparison.json
python3 scripts/benchmark_report.py comparison.json

Запуск собирает временный сервер PostgreSQL и выполняет общую матрицу:

Параметр Все клиенты и пути чтения
Клиенты Node.js с node-postgres / node-redis; Go с pgx / RESP2 из стандартной библиотеки
Пути чтения Подготовленный SQL ANY, SQL mget, RESP MGET
Ключей за запрос 1, 16, 64; одни и те же фиксированные ключи, начиная с 1
Соединения 4, 64, 256; постоянные, по одному незавершённому запросу на соединение
Выборки Три повтора по пять секунд для каждого случая; порядок меняется
Размещение Один отдельный контейнер клиента Linux с общим сетевым пространством имён PostgreSQL
Перед замером Подключение, сравнение декодированных строк, затем прогрев каждого соединения
Контракт результата Полные JSON-строки, порядок входных данных, дубликаты, null, отсутствующие ключи, пустой и полностью null-ввод
Измерения Запросов/с, процентили задержки, CPU клиента, CPU/память сервера, счётчики кэша

По умолчанию выполняется 162 выборки: около 14 минут измерений плюс настройка. Для короткой проверки корректности:

CONNECTIONS=4 BATCHES=1,16,64 REPEATS=1 DURATION_SECONDS=1 \
  ./examples/benchmark.sh all > smoke.json

Используйте node или go вместо all, чтобы выбрать один клиент с теми же значениями по умолчанию. Можно переопределить CONNECTIONS, BATCHES, REPEATS, DURATION_SECONDS и GOMAXPROCS Go. Node.js использует один поток цикла событий; Go по умолчанию использует восемь потоков. SQL mget в Node.js оборачивает возвращённый массив в JSON, а pgx декодирует текстовый массив PostgreSQL. Эти затраты клиентов входят в измерение.

Одинаковые нагрузки не делают протоколы взаимозаменяемыми: воркеры RESP используют настроенную роль базы данных и не присоединяются к SQL-транзакции или снимку вызывающего сеанса. См. контракт RESP. Общее сравнение измеряет прогретые чтения. Диагностика холодного кэша, смешанных чтений и записей и накладных расходов записи остаётся отдельной, в node-workload.

Опубликованные результаты за 14–15 сентября ниже появились до общего запуска. Их исходные окружения и ревизии исходного кода сохранены в данных; это не новые измерения единой матрицы.

Тестовое окружение

Компонент Конфигурация
Хост MacBook Pro Mac15,10, Apple M3 Max: 10 производительных + 4 эффективных ядра, 36 ГиБ RAM
ОС macOS 26.5.2, сборка 25F84, arm64
ВМ Docker Engine 29.7.2, Linux 7.0.12-linuxkit, 14 CPU, 7,65 ГиБ RAM; ограничений CPU или RAM контейнера нет
PostgreSQL 16.15, Debian bookworm; 300 соединений, 128 МиБ shared buffers, 256 МиБ /dev/shm
Данные 4 096 строк, значения по 128 байт; 1 024 записи кэша; данные и WAL в tmpfs

Методика измерений

Клиент и сервер используют CPU Mac вместе с десятью другими контейнерами разработки. Все клиенты кодируют запросы и декодируют полные JSON-строки, сохраняя порядок входных данных, дубликаты и отсутствующие позиции. SQL использует подготовленные операторы; подключения, аутентификация и прогрев не входят в измерение. TLS и конвейерной обработки нет.

CPU сервера берётся из счётчиков cgroup контейнера PostgreSQL. Одно ядро означает одну CPU-секунду за прошедшую секунду; доли загрузки вычисляются от 14. CPU мкс/запрос — это время CPU сервера, разделённое на число завершённых запросов. В окно выборки входят работа мониторинга и короткая пауза формирования отчёта клиента.

Память — это memory.current cgroup, снимаемая каждые 500 мс и в конечных точках. В таблицах указана медиана пиков каждой выборки, включая общую память, tmpfs и кэш страниц; это не RSS процесса. JSON-файлы также содержат блочный ввод-вывод, троттлинг, события памяти и снимки состояния SQL/ожиданий. Сетевые счётчики исключают loopback и поэтому не учитывают трафик клиента внутри ВМ.

Эти короткие запуски с прогретым кэшем на общем ноутбуке не являются оценкой производительности production. Данные и WAL используют tmpfs при включённых fsync, full_page_writes и synchronous_commit; производительность диска не проверялась.

Неудачный запуск завершается с ненулевым кодом и сохраняет завершённые выборки; рендерер Markdown отклоняет частичные результаты. Для точного записанного кода используйте harness_ref и extension_ref каждого JSON. Команды воспроизведения приведены на страницах клиентов; результаты записываются в JSON-файлы, например benchmark.json.

Обновлено .