Всем привет, меня зовут Максим, я работаю инженером по тестированию железа в Selectel Lab.

Ранее мы протестили железо (наши конфиги в Селектел) на производительность в разных БД, тестирование было первым и теперь мы пошли дальше, так скажем углубились в исследование производительности БД на разных аппаратных платформах а также доработали существующие тесты БД.

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

Как вы уже можете посмотреть эти данные уже работают и помогают нашим клиентам выбирать сервера по лучшей цене: https://selectel.ru/services/benchmarks/

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

Все так же наш фаворит АРМ сервер с одним сокетом который по результатам прошлых тестов очень хорошо конкурирует с двухсокетными системами.

Можно увидеть в таблице RAM DDR4 одного вендора, такая же история с дисками все работают по протоколу NVMe по линиям PCIe gen 4.

ОС и виды тестов

Использовали Ubuntu 22.04 LTS.
Ранее я заметил и описал что: “выбор на 14 версию пал из за повышенной производительности, с дефолтными настройками постгреса в некоторых тестах в сравнении с 12 й версией производительность примерно возросла аж в 2 раза.” По этому в этот раз мы будем сравнивать свежие версии PSQL энтерпрайз и обычные версии 15-16.

Почему именно PSQL? — это одна из самых популярных БД среди наших пользователей.

Подготовка системы и БД

BIOS и ОС настроены в performance режиме:

BIOS:

Для анализа настроек BIOS для серверных платформ на базе процессоров Intel, AMD и Ampere рассмотрим ключевые настройки, которые могут влиять на максимальную производительность сервера. Здесь я указываю самые распространенные настройки.

Intel

Hyper-Threading(включен):

Описание: Технология Hyper-Threading позволяет каждому ядру процессора обрабатывать два потока выполнения одновременно, тем самым увеличивая количество одновременно обрабатываемых задач и улучшая эффективность использования ресурсов процессора.

Влияние на производительность: Включение Hyper-Threading может значительно улучшить производительность в многопоточных приложениях и средах, где одновременно выполняется множество задач, например, в серверах виртуализации.

Turbo Boost(включен):

Описание: Intel Turbo Boost Technology динамически увеличивает частоту работы ядер процессора выше их базовой тактовой частоты, если условия теплового пакета и энергопотребления позволяют.

Влияние на производительность: Это может значительно улучшить производительность для кратковременных высоконагруженных задач, обеспечивая при этом эффективное энергопотребление в периоды простоя.

VT-x/VT-d (Virtualization Technology)(включен):

Описание: VT-x улучшает поддержку виртуализации на уровне процессора, а VT-d добавляет поддержку аппаратной виртуализации ввода-вывода, что позволяет гостевым операционным системам более эффективно использовать аппаратные ресурсы.

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

Power Management (C-States, P-States)(включен P0):

Описание: C-States позволяют процессору переходить в состояния пониженного энергопотребления при простое, в то время как P-States регулируют производительность процессора, изменяя его частоту и напряжение в зависимости от текущей нагрузки.

Влияние на производительность: Правильная конфигурация этих состояний может помочь достичь оптимального баланса между производительностью и энергоэффективностью, особенно в средах с переменной нагрузкой.

Memory Configuration(включена максимальная частота и двухканальный режим):

Описание: Включает настройки, такие как выбор режима работы памяти (например, single, dual, quad channel) и ручная конфигурация времен задержек памяти.

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

AMD

SMT (Simultaneous Multithreading)(включен):

Описание и влияние: Аналогично Hyper-Threading у Intel, SMT увеличивает количество потоков, которые может обрабатывать каждое ядро, улучшая тем самым общую производительность системы в многопоточных приложениях.

Core Performance Boost(включен):

Описание: Технология, аналогичная Intel Turbo Boost, которая позволяет процессорам AMD повышать свою частоту выше базовой в зависимости от условий тепловыделения и энергопотребления.

Влияние на производительность: Это обеспечивает дополнительную производительность для задач, требующих высокой вычислительной мощности, при этом поддерживая энергоэффективность в менее интенсивных режимах.

AMD-V (Virtualization)(включен):

Описание и влияние: Улучшает производительность виртуализированных приложений за счет аппаратной поддержки виртуализации, аналогично технологиям VT-x/VT-d от Intel.

Power Management (Cool'n'Quiet, Global C-state Control)(отключен):

Описание: Эти настройки помогают управлять энергопотреблением процессора, регулируя его частоту и напряжение в зависимости от текущей нагрузки.

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

Memory Interleaving(включен):

Описание: Настройка, позволяющая оптимизировать доступ к памяти, распределяя обращения к данным по различным каналам памяти.

Влияние на производительность: Это может значительно улучшить пропускную способность и время доступа к памяти, что особенно важно для приложений, интенсивно использующих память.

Ampere (ARM серверные процессоры)

Frequency Scaling(включен max_perfomance):

Описание: Настройка позволяет динамически изменять частоту процессора в зависимости от текущей рабочей нагрузки, оптимизируя тем самым энергопотребление и производительность.

Влияние на производительность: Это обеспечивает баланс между необходимой вычислительной мощностью и энергоэффективностью, адаптируясь к изменениям в рабочей нагрузке.

Memory Configuration(включена максимальная частота памяти):

Описание: Включает настройки таймингов памяти и конфигурации, направленные на оптимизацию скорости и пропускной способности памяти.

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

Energy Efficiency Modes(отключен):

Описание: Настройки режимов энергоэффективности позволяют выбирать оптимальный баланс между производительностью и потреблением энергии.

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

Общие настройки для всех платформ

Memory Timing: Настройки таймингов памяти влияют на скорость обработки данных. Меньшие значения задержек (CAS Latency, tRCD, tRP, tRAS) могут улучшить производительность.

PCIe Settings: Конфигурация скорости и режима работы PCIe слотов может влиять на производительность подключенных устройств.

NUMA (Non-Uniform Memory Access) Configuration: Настройка оптимального использования памяти в системах с несколькими процессорами может существенно улучшить производительность приложений, чувствительных к задержкам доступа к памяти.

I/O Virtualization (SR-IOV, IOMMU): Настройки виртуализации ввода-вывода помогают улучшить производительность виртуализированных систем за счет более эффективной передачи данных между виртуальными машинами и физическими устройствами.

Специфические настройки для Intel

SpeedStep/EIST (Enhanced Intel SpeedStep Technology): Технология, позволяющая изменять частоту процессора в зависимости от нагрузки, для оптимизации потребления энергии и производительности.

Intel UPI Link Configuration: Настройка скорости и протоколов Intel Ultra Path Interconnect, соединяющего процессоры в многосокетных системах, может влиять на производительность памяти и общую производительность системы.

Intel VMD (Volume Management Device): Настройка, позволяющая управлять NVMe SSD дисками на уровне BIOS, может улучшить производительность и управляемость хранилища.

Специфические настройки для AMD

Precision Boost Overdrive (PBO): Функция, позволяющая превысить заводские ограничения процессора для достижения более высокой производительности при достаточном охлаждении.

Memory Access Mode: Настройка режима доступа к памяти (Distributed vs Local) для оптимизации производительности в зависимости от характера рабочей нагрузки.

Специфические настройки для Ampere

Core Frequency Scaling: Динамическая настройка частоты ядер в зависимости от нагрузки для баланса между производительностью и энергопотреблением.

Configurable TDP (Thermal Design Power): Настройка максимальной мощности, которую может потреблять процессор, позволяет управлять балансом между производительностью и тепловым режимом.

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

ОС:

При настройке ОС отключаем политики энергосбережения и включаем режим перфоманс (ubuntu 22.04)

bash
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

В тестах используем максимальные рабочие частоты процессоров, максимальную частоту памяти, для двухсокетных систем, NUMA настроена на равномерное распределение памяти между CPU, охлаждение на максимум. В остальном сами настройки БД PSQL мы не трогаем за исключением количества подключений (MAX connection) и адреса где расположена БД (в данном случае локально, для прозрачности тестирования, исключения дополнительной точки отказа и сетевых задержек).

Дефолтные настройки PSQL мы используем по причине того что мы не знаем профиль нагрузки пользователя на систему и нам нужна точка отсчета производительности.

Выбор режима тестирования:

Используем уже известный нам бенчмарк pgbench который является дефолтным и встроенным в PostgreSQL.

Выбрали ключи(режимы) тестирования:

config
pgbench -T (смешаные запросы)
pgbench -S -T (SELECT ONLY)
pgbench -N -T (UPDATE)

Автоматизация теста pgbench

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

Смысловая часть кода:

config
CORES=$((CPU_THREADS))
HOST="127.0.0.1"
TIME="600"
# Создаем базу данных генерим таблицы
pgbench —username=root -h "${HOST}" test -i -s 10000
# Считаем кол-во потоков и подключенных пользователей
THREADS=(1 2 $(echo "scale=0; $CORES * 20 / 100" | bc -l) \
$(echo "scale=0; $CORES * 40 / 100" | bc -l) \
$(echo "scale=0; $CORES * 60 / 100" | bc -l) \
$(echo "scale=0; $CORES * 80 / 100" | bc -l) \
$(echo "scale=0; $CORES * 99.9 / 100" | bc -l))
echo "pgbench —username=root -h ${HOST} test ${PARAM} -T ${TIME}" >> "${FILE}"
pgbench —username=root -h "${HOST}" test ${PARAM} -T "${TIME}" >> "${FILE}"
echo "pgbench —username=root -h ${HOST} test ${PARAM} -S -T ${TIME}" >> "${FILE}"
pgbench —username=root -h "${HOST}" test ${PARAM} -S -T "${TIME}" >> "${FILE}"
echo "pgbench —username=root -h ${HOST} test ${PARAM} -N -T ${TIME}" >> "${FILE}"
pgbench —username=root -h "${HOST}" test ${PARAM} -N -T "${TIME}" >> "${FILE}"
done

В данном коде получаем кол-во ядер и рассчитываем кол-во потоков в конкретной системе, далее указываем HOST что БД будет располагаться локально на машине, TIME — указываем время тестирования в секундах, после создаем БД “ test” и строки в данном тестировании создавался 1 миллиард строк что примерно 250GB по объему.

Как вы можете видеть в pgbench тесте используется 3 ключа для тестирования “-”, “-S ”, “-N”.

- — Смешанные SQL-запросы (Select, Update)

-S -T — упорядоченная последовательность SQL-запросов (Select only)

-N -T — режим простых SQL запросов запросы (Update only)

В конце тестирования получаем данные в виде текстового файла:
pgbench —username=admin -h 127.0.0.1 test -c 52 -j 26 -T 600

output
pgbench (14.6 (Ubuntu 14.6-0ubuntu0.22.04.1))
starting vacuum…end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10000
query mode: simple
number of clients: 52
number of threads: 26
duration: 600 s
number of transactions actually processed: 22881325
latency average = 1.363 ms
initial connection time = 235.470 ms
tps = 38150.347817 (without initial connection time)

Парсинг результатов в гугл таблицу.

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

awk
#!/usr/bin/awk -f
BEGIN {
# Параметры таблицы, выравнивание
client_width = 10
thread_width = 12
tps_width = 20
trans_width = 20
latency_width = 20
init_conn_width = 25
# Вывод столбцов
printf "%-s%-s%-s%-s%-s%-s\n", "Num Clients", "Num Threads", "TPS", "Num Transactions", "Latency Average", "Initial Connection Time"
}
# Извлечение нужных значений из строки запуска pgbench
match($0, /-j\s+([0-9]+)/, arr) {
num_clients = arr[1]
}
match($0, /-c\s+([0-9]+)/, arr) {
num_threads = arr[1]
}
# Поиск по строкам нужных значений
/number of transactions actually processed:/ {
num_transactions = $NF
}
/latency average/ {
latency_average = $(NF-1) " " $NF
}
/initial connection time.*[0-9]+\.[0-9]+/ {
# Извлечение только числовых значений
for (i = 1; i <= NF; i++) {
if ($i ~ /^[0-9]+\.[0-9]+$/) {
init_conn_time = $i " " $(i+1)
break
}
}
}
/tps/ {
# Извлечение всех знаков (if present)
for (i = 1; i <= NF; i++) {
if ($i == "tps") {
tps = $(i+2)
gsub(/[()]/, "", tps) # Удаление TPS знач
break
}
}
# Вывод
printf "%-*s%-*s%-*s%-*s%-*s%-*s\n", client_width, num_clients, thread_width, num_threads, tps_width, tps, trans_width, num_transactions, latency_width, latency_average, init_conn_width, init_conn_time
}

в результате выполнения скрипта нам выдаются колонки в терминале с нужными данными оставалось только CTRL-C, CTRL-V.

Результаты тестирования:

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

На каждую версию PSQL мы генерили такой график:

График PGBENCH PSQL 15 по разным серверным платформам и режимам нагрузки
График PGBENCH PSQL 16-PRO по разным серверным платформам

Для оценки производительности в многопоточном режиме, а так же такой график:

Для оценки производительности в одном и двух потоках чтобы оценить (производительность на ядро)

Здесь сразу можно увидеть что процессоры 2го поколения выигрывают у процессоров 3го поколения в производительности на ядро.

главная задача стояла оценить общую производительность PSQL разных версий, об этом графики ниже:

Сравнение суммарных TPS SELECT, UPDATE и MIX для PostgreSQL 15 и 16

Мы посчитали операции в секунду по каждой платформе и сравнили 15 версию PSQL и 16 версию PSQL (не энтерпрайз)

Получили разницу в производительности от 2 до 7%, значительный разрыв по SELECT ONLY.

Дальше сравниваем PSQL 15-16 PRO:

Сравнение суммарных TPS SELECT, UPDATE и MIX для PostgreSQL 15 PRO и 16 PRO

Тут в процентном соотношении результат похож на предыдущий но кол-во операций в секунду здесь гораздо больше чем в обычных версиях PSQL, далее смотрим график с общим сравнением обычных версий и энтерпрайз:

Общее сравнение TPS для PSQL 15, 16, 15 PRO и 16 PRO

Здесь мы видим значительную разницу между обычной и ПРО версией, одной из причин является автоконфигурирование PSQL в энтерпрайз версиях, которая немного тюнит БД для лучшей производительности (для нас это все равно дефолт, так как из коробки мы ничего не делаем)

Конечно скорее всего под капотом еще много оптимизаций которых мы не видим как обычные пользователи БД.

Далее мы задались вопросом что будет если выжать из железа максимум и настроить БД и конфиг на максимальную производительность и вот что получили:

Тест тюнинга конфига PSQL 16-PRO: сравнение дефолтных настроек и performance-режима

Сверху 4 теста PSQL в дефолтном режиме, самый нижний тест в перфоманс режиме с одними изз возможных максимальных настроек PSQL для производительности, вот что было настроено:

Huge Pages эффективно управляет большим объемом памяти

BG Writer оптимизирует фоновую запись данных на диск

Prefetching улучшение производительности при сканировании данных

Вынесение каталога pg_stat_tmp в RAM (tmpfs)

Autovacuum автоматическая очистка

Write-Ahead Logging — запись перед чтением, увеличивает размер журнала, что позволяет редко выполнять контрольные точки

bash
#Определить количество HugePages. Обычно их размер равен 2MB. Например, нам нужно 3100 страниц.
#Прописать в /etc/sysctl.conf настройку число больших страниц:
systemctl stop psotgresql
#Проверка сколько Huge page надо
sudo -u postgres/opt/pgpro/ent-15/bin/postgres —shared-buffers=2GB -D /var/lib/pgpro/ent-15/data/ -C shared_memory_size_in_huge_pages
systemctl start psotgresql
echo 3100 | sudo tee /proc/sys/vm/nr_hugepages
#Проверяем настройку:
cat /proc/meminfo
#Число HugePages должно быть ненулевое, а общее должно равняться 3100.
#Выключаем настройку THP:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
#Устанавливаем группу для Huge Pages
pg_group_id=$(id -g postgres)
echo "$pg_group_id" | sudo tee /proc/sys/vm/hugetlb_shm_group
sudo sed -i 's/huge_pages = try/huge_pages = on/' /var/lib/pgpro/ent-16/data/postgresql.conf
systemctl restart psotgresql
sudo sed -i "s/^#bgwriter_delay =.*/bgwriter_delay = '10ms'/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#bgwriter_flush_after =.*/bgwriter_flush_after = 0/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#bgwriter_lru_maxpages =.*/bgwriter_lru_maxpages = 4000/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#bgwriter_lru_multiplier =.*/bgwriter_lru_multiplier = 10/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#checkpoint_completion_target =.*/checkpoint_completion_target = 0.9/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#checkpoint_timeout =.*/checkpoint_timeout = '30min'/" /var/lib/pgpro/ent-16/data/postgresql.conf
sudo sed -i "s/^#max_wal_size =.*/max_wal_size = '32GB'/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#wal_compression =.*/wal_compression = 'lz4'/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#default_toast_compression =.*/default_toast_compression = 'lz4'/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#lwlock_shared_limit =.*/lwlock_shared_limit = 16/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#log2_num_lock_partitions =.*/log2_num_lock_partitions = 8/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#slru_buffers_size_factor =.*/slru_buffers_size_factor = 6/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#default_statistics_target =.*/default_statistics_target = 1000/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#autoprepare_threshold =.*/autoprepare_threshold = 2/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#autoprepare_for_protocol =.*/autoprepare_for_protocol = 'simple'/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#generic_plan_fuzz_factor =.*/generic_plan_fuzz_factor = 0.9/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#effective_io_concurrency =.*/effective_io_concurrency = 100/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#autovacuum_naptime =.*/autovacuum_naptime = '1s'/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#autovacuum_max_workers =.*/autovacuum_max_workers = 6/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#vacuum_cost_limit =.*/vacuum_cost_limit = 2000/" /var/lib/pgpro/ent-16/data/postgresql.conf && \
sudo sed -i "s/^#autovacuum_work_mem =.*/autovacuum_work_mem = '1GB'/" /var/lib/pgpro/ent-16/data/postgresql.conf

Скрипт для переноса каталога pg_stat_tmp в RAM-диск

bash
#!/bin/bash
# Путь к RAM-диску
RAMDISK_PATH="/mnt/ramdisk"
# Размер RAM-диска (1GB)
RAMDISK_SIZE="1G"
# Путь к каталогу pg_stat_tmp
PG_STAT_TMP_PATH="/var/lib/pgpro/ent-16/data/pg_stat_tmp"
# Переменная для резервного копирования оригинального каталога
PG_STAT_TMP_BACKUP_PATH="/var/lib/pgpro/ent-16/data/pg_stat_tmp_backup"
# Создание каталога RAM-диска
sudo mkdir $RAMDISK_PATH
# Примонтирование RAM-диска
sudo mount -t tmpfs -o size=$RAMDISK_SIZE tmpfs $RAMDISK_PATH
# Копирование данных из pg_stat_tmp в RAM-диск
sudo cp -r $PG_STAT_TMP_PATH/. $RAMDISK_PATH/
# Создание символической ссылки
sudo mv $PG_STAT_TMP_PATH $PG_STAT_TMP_BACKUP_PATH
sudo ln -s $RAMDISK_PATH $PG_STAT_TMP_PATH
# Проверка создания символической ссылки
ls -l $PG_STAT_TMP_PATH

Итоги

В данном тестирования мы подтвердили для себя что всегда лучше обновиться на новую версию PSQL будь то обычная версия или PRO версия, если мы хотим большей производительности то это PRO версия с тюнингом БД.

Обязательно требуется настраивать BIOS, ОС, и саму БД можно воспользоваться нашими подсказками.