Рекомендации по настройке производительности

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

Размещение PostgreSQL

  • По возможности выносите PostgreSQL на отдельный сервер. Совмещение с узлами Закрома.Хранение и ZDS приводит к конкуренции за CPU, память (page cache) и диски.
  • Для промышленной эксплуатации используйте HA-кластер PostgreSQL (например, роль postgresql-ha из поставки).
  • Размещайте PostgreSQL в той же сети (L2-сегменте), что и узлы Закрома.Хранение: каждая операция с объектом выполняет несколько запросов к БД, и сетевая задержка складывается.

Где задаются параметры PostgreSQL

Расположение параметров зависит от способа установки PostgreSQL.

Способ установки PostgreSQLГде задаются параметрыКак применить
Собственный экземпляр PostgreSQLpostgresql.conf или отдельный файл в conf.d/ (в Debian/Ubuntu — /etc/postgresql/<версия>/main/conf.d/), либо ALTER SYSTEM SET ... (записывается в postgresql.auto.conf в каталоге данных)SELECT pg_reload_conf(); или перезапуск — см. столбец «Перезапуск» в таблицах ниже
Роль postgresql-ha из поставки (Patroni)Переменная postgresql_ha_postgresql_parameters в group_vars инвентаря роли (примеры — roles/postgresql-ha/examples/<пример>/group_vars/all.yml). Параметры хранятся в etcd и применяются ко всему кластеруПовторный прогон роли. postgresql.conf вручную не редактируйте — Patroni перезапишет его

Пример для роли postgresql-ha (сервер 16 ГБ RAM, SSD):

1postgresql_ha_postgresql_parameters: 2 max_connections: 500 3 shared_buffers: 4GB 4 effective_cache_size: 8GB 5 work_mem: 32MB 6 maintenance_work_mem: 512MB 7 max_wal_size: 4GB 8 min_wal_size: 1GB 9 wal_compression: zstd 10 random_page_cost: 1.1 11 effective_io_concurrency: 200 12 huge_pages: try
Перезапуск при Patroni

Роль postgresql-ha не перезапускает PostgreSQL. Параметры, требующие перезапуска (shared_buffers, max_connections, huge_pages, wal_buffers), переводят узлы в состояние pending_restart. Перезапускайте сначала реплики, затем выполните patronictl switchover и перезапустите бывшего лидера.

Проверка действующих значений:

1SELECT name, setting, unit, source, sourcefile, pending_restart 2FROM pg_settings 3WHERE name IN ('shared_buffers','effective_cache_size','work_mem','maintenance_work_mem', 4 'max_connections','max_wal_size','wal_compression','huge_pages', 5 'random_page_cost','effective_io_concurrency','synchronous_commit');

Столбец sourcefile показывает, из какого файла взято значение, pending_restart = true — что значение изменено, но ещё не применено.

Параметры PostgreSQL

Память

ПараметрРекомендацияПерезапускНазначение
shared_buffers25% RAM сервера БД (не более 32 ГБ)даСобственный кэш страниц PostgreSQL. Значение по умолчанию (128 МБ) мало для любой промышленной нагрузки
effective_cache_size50–75% RAMнетОценка суммарного кэша (shared_buffers + page cache ОС) для планировщика. Память не выделяет, влияет только на выбор индексных планов
work_mem32MBнетПамять на одну операцию сортировки или хеширования в каждом запросе. При большом max_connections суммарное потребление может достигать work_mem × число операций × число соединений, поэтому не завышайте значение
maintenance_work_mem512MB–1GBнетПамять для VACUUM, CREATE INDEX. Ускоряет обслуживание больших таблиц метаданных

WAL и контрольные точки

ПараметрРекомендацияПерезапускНазначение
max_wal_size4GB и больше (должен вмещать WAL, генерируемый за checkpoint_timeout)нетОбъём WAL, после которого запускается внеплановая контрольная точка. Малое значение вызывает частые checkpoint и всплески записи
min_wal_size1GBнетОбъём переиспользуемых сегментов WAL
checkpoint_timeout15minнетИнтервал плановых контрольных точек
checkpoint_completion_target0.9 (значение по умолчанию с PostgreSQL 14)нетРастягивает запись грязных страниц на 90% интервала
wal_compressionzstd (PostgreSQL 15+) или onнетСжатие полных образов страниц в WAL: меньше объём записи и сетевого трафика репликации ценой небольшой нагрузки на CPU
Результат теста

На транзакционной нагрузке настройка WAL и контрольных точек дала +164% TPS — больше, чем любая другая оптимизация после памяти. Каждая первая модификация страницы после контрольной точки записывает в WAL её полный образ (8 КБ), поэтому редкие контрольные точки и сжатие WAL кратно сокращают объём записи. Наибольший эффект — на дисках с ограниченной пропускной способностью.

Проверить, вызываются ли контрольные точки по объёму WAL (а не по таймеру), можно включив log_checkpoints = on или через pg_stat_checkpointer (PostgreSQL 17+) / pg_stat_bgwriter (до 16): большое num_requested / checkpoints_req по сравнению с плановыми означает, что max_wal_size мал.

Не отключайте fsync и full_page_writes Отключение приводит к повреждению базы при сбое питания или ОС. synchronous_commit = off не повреждает базу, но при сбое теряются последние подтверждённые транзакции (до 3 × wal_writer_delay), то есть метаданные уже загруженных объектов. На тестовом стенде synchronous_commit = off дал +67% TPS на транзакционной нагрузке — меньше, чем корректная настройка WAL и контрольных точек (см. Результаты тестирования), которая не жертвует надёжностью. Не используйте этот параметр для базы Закрома.Хранение.

Планировщик для SSD/NVMe

ПараметрРекомендацияПерезапускНазначение
random_page_cost1.1нетСтоимость случайного чтения относительно последовательного. Значение по умолчанию (4) рассчитано на HDD и заставляет планировщик чаще выбирать последовательное сканирование
effective_io_concurrency200нетЧисло параллельных запросов предвыборки для bitmap heap scan
maintenance_io_concurrency200нетТо же для операций обслуживания

Количество подключений

Установите max_connections по инструкции по расчёту с запасом 20–30%. Каждое соединение — отдельный процесс PostgreSQL, потребляющий память, поэтому не задавайте значение «с большим запасом».

Подключения Закрома.Хранение к PostgreSQL

Пулы подключений компонентов настраиваются в inventories/<вариант установки>/group_vars/zakroma-storage.yml архива поставки.

ПеременнаяЗначение по умолчаниюОписание
zakroma_storage_postgresql_max_open_conns10Максимальное число открытых подключений к БД. Глобальное значение, наследуется всеми компонентами
zakroma_storage_postgresql_max_idle_conns5Максимальное число неактивных подключений, удерживаемых в пуле
zakroma_storage_workers[].postgresql_max_open_conns{{ zakroma_storage_postgresql_max_open_conns }}Переопределение для конкретного worker (шарда)
zakroma_storage_workers[].postgresql_max_idle_conns{{ zakroma_storage_postgresql_max_idle_conns }}То же для неактивных подключений

Рекомендации для нагрузки с высокой параллельностью:

  • Увеличьте у worker max_open_conns до 40 и max_idle_conns до 40. Точное значение зависит от размера объектов и параллельности клиентской нагрузки.
  • Выдерживайте соотношение max_open_conns × <количество узлов Закрома.Хранение> > <concurrency>, где concurrency — число одновременных S3-запросов клиентов ко всему кластеру. Иначе запросы будут ждать свободного соединения в пуле.
  • Задавайте max_idle_conns = max_open_conns, чтобы при всплесках нагрузки соединения не закрывались и не открывались заново: установка соединения с PostgreSQL занимает единицы миллисекунд и порождает новый процесс на сервере БД.

Пример — увеличение подключений только для worker, без изменения остальных компонентов:

1zakroma_storage_workers: 2 - postgresql_host: "{{ zakroma_storage_postgresql_host }}" 3 postgresql_port: "{{ zakroma_storage_postgresql_port }}" 4 postgresql_username: "{{ zakroma_storage_postgresql_username }}" 5 postgresql_password: "{{ zakroma_storage_postgresql_password }}" 6 postgresql_dbname: "{{ zakroma_storage_postgresql_dbname }}" 7 postgresql_schema_name: worker0 8 postgresql_sslmode: "{{ zakroma_storage_postgresql_sslmode }}" 9 postgresql_max_open_conns: 40 10 postgresql_max_idle_conns: 40 11 # остальные параметры worker оставьте без изменений

После увеличения пулов пересчитайте max_connections PostgreSQL по формуле: подключения worker умножаются на число шардов и узлов.

Шарды метаданных

Метаданные объектов распределяются между шардами — схемами или базами данных, каждую из которых обслуживает свой worker. Увеличение числа шардов распараллеливает запись и чтение метаданных.

  • Используйте от 2 до 10 шардов. Количество шардов определяется совместно с технической поддержкой по требованиям к RPS и планируемому количеству объектов.
  • При большой параллельности клиентов увеличение числа шардов может давать кратный рост RPS записи и чтения мелких объектов (4–256 КБ) — при условии, что дисковая подсистема ZDS не является узким местом.
  • Шард добавляется новым элементом списка zakroma_storage_workers со своей схемой (worker1, worker2, …) или базой данных. Порядок добавления без остановки обслуживания описан в статье Масштабирование объёма хранения.
  • По возможности размещайте шарды в разных базах данных и на разных дисках с помощью отдельных TABLESPACE — так шарды не конкурируют за IOPS одного тома.

Пример создания шарда на отдельном диске (/pgdata2 смонтирован на отдельный том):

1-- от суперпользователя 2CREATE TABLESPACE ts_worker1 OWNER zakroma_user LOCATION '/pgdata2/ts_worker1'; 3CREATE DATABASE zakroma_worker1 WITH OWNER zakroma_user TABLESPACE ts_worker1; 4\c zakroma_worker1 5CREATE SCHEMA worker1 AUTHORIZATION zakroma_user;

Каталог LOCATION должен существовать, быть пустым и принадлежать пользователю postgres. Для кластера Patroni каталог tablespace должен быть создан на всех узлах.

Операционная система: память и page cache

Параметры ядра задавайте в отдельном файле, например /etc/sysctl.d/90-postgresql.conf, и применяйте командой sudo sysctl --system.

Huge pages

При больших shared_buffers таблицы страниц каждого процесса PostgreSQL занимают значительный объём памяти, а промахи TLB увеличивают нагрузку на CPU. Huge pages (2 МБ вместо 4 КБ) снимают обе проблемы.

  1. Узнайте требуемое количество страниц (PostgreSQL 15+, значение рассчитывается по текущим shared_buffers):

    1SHOW shared_memory_size_in_huge_pages;
  2. Зарезервируйте страницы с небольшим запасом в /etc/sysctl.d/90-postgresql.conf:

    1vm.nr_hugepages = <значение из п.1 + 2–3%>
  3. Задайте huge_pages = on (PostgreSQL не запустится, если страниц не хватает) или try (молча использует обычные страницы) и перезапустите PostgreSQL.

  4. Проверьте использование: в /proc/meminfo значение HugePages_Rsvd или разница HugePages_Total − HugePages_Free должна соответствовать shared_buffers.

Зарезервированные huge pages недоступны остальным процессам, поэтому пересчитывайте vm.nr_hugepages при каждом изменении shared_buffers.

Резервируйте huge pages при загрузке

Ядро выделяет huge pages только из непрерывных блоков памяти по 2 МБ. На работающем сервере память фрагментирована page cache, и sysctl -w vm.nr_hugepages=N может выделить меньше страниц, чем запрошено, без сообщения об ошибке. На тестовом стенде из 547 запрошенных страниц было выделено 467, и PostgreSQL с huge_pages = on не запустился с ошибкой could not map anonymous shared memory.

  • Задавайте vm.nr_hugepages в /etc/sysctl.d/ — параметр применится при загрузке, пока память не фрагментирована.
  • После изменения без перезагрузки проверяйте фактическое значение HugePages_Total в /proc/meminfo. При нехватке освободите page cache и уплотните память: sync; echo 3 > /proc/sys/vm/drop_caches; echo 1 > /proc/sys/vm/compact_memory — и повторите установку.
  • Значение huge_pages = try не остановит запуск PostgreSQL при нехватке страниц, но PostgreSQL молча будет работать без них — проверяйте HugePages_Rsvd после перезапуска.
Результат теста

Huge pages при shared_buffers = 1GB: +8,6% TPS на нагрузке метаданных из памяти, на прочих нагрузках — в пределах погрешности. Эффект растёт с размером shared_buffers и числом соединений.

Transparent Huge Pages

Отключите Transparent Huge Pages (THP) в режиме always: дефрагментация памяти ядром вызывает непредсказуемые задержки. Режим madvise (значение по умолчанию в Ubuntu 24.04) безопасен — PostgreSQL не запрашивает THP.

1cat /sys/kernel/mm/transparent_hugepage/enabled # [madvise] или [never] — допустимо

Для постоянного отключения добавьте transparent_hugepage=never в параметры ядра (GRUB_CMDLINE_LINUX) или используйте профиль tuned.

Сброс грязных страниц

По умолчанию ядро начинает фоновую запись при vm.dirty_background_ratio = 10% и блокирует процессы при vm.dirty_ratio = 20% от доступной памяти. На сервере с 128 ГБ RAM это 12 и 25 ГБ несброшенных данных: во время контрольной точки или fsync они записываются одним всплеском, и задержки запросов резко растут. Задайте пороги в абсолютных значениях, соизмеримых с производительностью дисков:

1# /etc/sysctl.d/90-postgresql.conf 2vm.dirty_background_bytes = 67108864 # 64 МБ 3vm.dirty_bytes = 268435456 # 256 МБ (для быстрых NVMe — до 1 ГБ)

Параметры *_bytes и *_ratio взаимоисключающие: установка одного обнуляет другой.

Результат теста

На стенде с 4 ГБ RAM изменение порогов не дало устойчивого эффекта: 0…+0,5% на транзакционной нагрузке и от −1,8% до +6,2% на нагрузке метаданных в двух сериях — в пределах погрешности. При малом объёме памяти пороги по умолчанию (400/800 МБ) и так невелики. Параметр важен на серверах с большим объёмом RAM, где он сглаживает всплески задержек во время контрольных точек.

Swap и overcommit

1# /etc/sysctl.d/90-postgresql.conf 2vm.swappiness = 1 3vm.overcommit_memory = 2 4vm.overcommit_ratio = 80 # подберите так, чтобы CommitLimit ≈ RAM − резерв ОС
  • vm.swappiness = 1 — ядро вытесняет в swap только при реальной нехватке памяти, а не вместо освобождения page cache. Полностью отключать swap не рекомендуется: при нехватке памяти вместо замедления сработает OOM killer.
  • vm.overcommit_memory = 2 запрещает выделять больше памяти, чем CommitLimit (swap + (RAM − huge pages) × overcommit_ratio / 100, см. /proc/meminfo). Процесс PostgreSQL получит ошибку выделения памяти вместо того, чтобы OOM killer завершил процесс и PostgreSQL перезапустил весь экземпляр. Зарезервированные huge pages вычитаются из RAM при расчёте CommitLimit, поэтому после их включения проверьте CommitLimit и при необходимости увеличьте overcommit_ratio.

Эти параметры влияют на стабильность под нагрузкой, а не на пиковую производительность, поэтому в A/B-тестах не измерялись.

NUMA

На многопроцессорных серверах отключите vm.zone_reclaim_mode (значение 0 по умолчанию в современных ядрах): при значении 1 ядро предпочитает освобождать page cache локального узла NUMA вместо использования памяти соседнего, и эффективный размер кэша падает.

1sysctl vm.zone_reclaim_mode # должно быть 0 2numactl --hardware # количество узлов NUMA

Диски

Размещение данных и WAL

  • Используйте SSD/NVMe. Метаданные — это случайный ввод-вывод мелкими блоками (8 КБ), и задержка диска напрямую определяет задержку операций S3.
  • Вынесите WAL (pg_wal) на отдельный том. Запись WAL — последовательная с fsync на каждую фиксацию транзакции; на общем томе она конкурирует со случайным чтением и записью данных.
  • Шарды метаданных размещайте на разных томах через TABLESPACE (см. Шарды метаданных).
  • Оцените задержку fsync тома с WAL утилитой pg_test_fsync из состава PostgreSQL: число операций в секунду для метода fdatasync — верхняя граница числа фиксаций одного соединения в секунду.
1/usr/lib/postgresql/16/bin/pg_test_fsync -f /var/lib/postgresql/16/main/pg_wal/fsync.test

Файловая система и опции монтирования

Используйте XFS или ext4. Монтируйте тома с данными с опцией noatime, чтобы чтение файлов не порождало запись времени доступа:

1# /etc/fstab 2UUID=<uuid> /var/lib/postgresql xfs defaults,noatime 0 0
1sudo mount -o remount,noatime /var/lib/postgresql # применить без перезагрузки 2findmnt -no OPTIONS /var/lib/postgresql # проверить
Результат теста

noatime вместо relatime — без устойчивого эффекта: +1…+2% на транзакционной нагрузке, от −7% до 0% на нагрузке метаданных в двух сериях (в пределах погрешности этой нагрузки). relatime уже обновляет время доступа не чаще раза в сутки. Опцию можно применять как стандартную, но прироста от неё ждать не стоит.

Планировщик ввода-вывода и read-ahead

  • Для NVMe и SSD (а также виртуальных дисков, за которыми стоит СХД) используйте планировщик none или mq-deadline; bfq даёт заметные накладные расходы на CPU.
  • read_ahead_kb влияет на последовательное чтение (VACUUM, последовательное сканирование, резервное копирование, pg_basebackup). На случайное чтение по индексам read-ahead практически не влияет.

Проверка и постоянная настройка через udev:

1cat /sys/block/<диск>/queue/scheduler /sys/block/<диск>/queue/read_ahead_kb
1# /etc/udev/rules.d/60-postgresql-io.rules 2# NVMe и SSD 3ACTION=="add|change", KERNEL=="nvme[0-9]*n[0-9]*|sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none", ATTR{queue/read_ahead_kb}="128" 4# виртуальные диски virtio 5ACTION=="add|change", KERNEL=="vd[a-z]", ATTR{queue/scheduler}="none", ATTR{queue/read_ahead_kb}="128"

Виртуальные диски часто сообщают rotational = 1 (cat /sys/block/<диск>/queue/rotational), даже если за ними SSD-хранилище, поэтому условие по rotational к ним не применяется.

1sudo udevadm control --reload && sudo udevadm trigger --subsystem-match=block
Результат теста

На виртуальном диске mq-deadline вместо none дал от −3,4% до +0,8% (в среднем −1,5%), а read_ahead_kb = 4096 вместо 128 — −2% на случайном чтении во всех четырёх парах прогонов. Для виртуальных и NVMe-дисков оставляйте none и read_ahead_kb по умолчанию; увеличенный read-ahead имеет смысл только для томов, где преобладает последовательное чтение.

Проверка дисковой подсистемы

Перед вводом в эксплуатацию измерьте фактическую производительность тома утилитой fio, имитируя профиль PostgreSQL:

1# случайное чтение/запись страницами 8 КБ (файлы данных) 2fio --name=data --filename=/pgdata/fio.test --size=4G --direct=1 --ioengine=libaio \ 3 --rw=randrw --rwmixread=70 --bs=8k --iodepth=32 --runtime=60 --time_based --group_reporting 4# последовательная запись с fdatasync (WAL) 5fio --name=wal --filename=/pgwal/fio.test --size=1G --direct=1 --ioengine=libaio \ 6 --rw=write --bs=8k --iodepth=1 --fdatasync=1 --runtime=60 --time_based

Во время нагрузки контролируйте утилизацию и задержку дисков командой iostat -x 1 (столбцы r_await, w_await, %util). Удалите тестовые файлы после проверки.

Сеть

Каждая операция S3 выполняет несколько коротких запросов к PostgreSQL, поэтому для метаданных важнее задержка сети, чем её пропускная способность. Пропускная способность важна для репликации, резервного копирования (pg_basebackup) и трафика ZDS.

Очереди подключений и буферы TCP

1# /etc/sysctl.d/90-postgresql.conf 2# очередь входящих подключений: всплески подключений пулов worker после рестарта 3net.core.somaxconn = 4096 4net.ipv4.tcp_max_syn_backlog = 8192 5# буферы сокетов: репликация и резервное копирование по сети с RTT > 1 мс 6net.core.rmem_max = 16777216 7net.core.wmem_max = 16777216 8net.ipv4.tcp_rmem = 4096 131072 16777216 9net.ipv4.tcp_wmem = 4096 16384 16777216
  • somaxconn и tcp_max_syn_backlog защищают от отказов в подключении при одновременном старте всех пулов Закрома.Хранение. Переполнение очереди видно в счётчике ListenOverflows команды nstat -az TcpExtListenOverflows.
  • Увеличение буферов TCP имеет смысл, если произведение пропускной способности на задержку (BDP) превышает размер буфера по умолчанию — например, при репликации между площадками. В пределах одного ЦОД с RTT < 0,5 мс эффекта, как правило, нет.
Результат теста

В одной подсети (RTT ~0,4 мс) увеличение буферов TCP до 16 МБ в двух сериях не изменило ни пропускную способность iperf3 (±1,5%), ни TPS запросов по сети (±3%). Буферы по умолчанию уже покрывают BDP такой сети.

Обнаружение разорванных соединений

Соединения пулов Закрома.Хранение долгоживущие. Если между узлами есть межсетевой экран, NAT или балансировщик с тайм-аутом неактивных сессий, «зависшее» соединение обнаружится только при следующем запросе — по тайм-ауту TCP, через несколько минут. Включите keepalive на стороне PostgreSQL с интервалом меньше тайм-аута сетевого оборудования:

ПараметрРекомендацияПерезапуск
tcp_keepalives_idle60нет
tcp_keepalives_interval10нет
tcp_keepalives_count6нет
tcp_user_timeout60000 (мс)нет

Прерывания и очереди сетевой карты

  • Убедитесь, что включён irqbalance или прерывания сетевой карты распределены по ядрам вручную: grep <интерфейс> /proc/interrupts.
  • Используйте все аппаратные очереди карты (ethtool -l <интерфейс>, ethtool -L <интерфейс> combined <N>) и максимальный размер кольцевых буферов при потерях пакетов (ethtool -g/-G, счётчики ethtool -S <интерфейс> | grep -i drop).
  • Перегрузку CPU обработкой сети видно по столбцу %soft в выводе mpstat -P ALL 1.

Jumbo frames

Jumbo frames (MTU больше 1500, обычно 9000) уменьшают число пакетов и прерываний на единицу переданных данных. Эффект проявляется на потоковом трафике — репликация, pg_basebackup, выгрузки, передача частей объектов ZDS. На коротких запросах метаданных, которые укладываются в один пакет, выигрыша нет.

MTU должен совпадать на всём пути

Jumbo frames должны быть включены на всех узлах сегмента, на коммутаторах, в VLAN, bond-интерфейсах и overlay-сетях. Если какой-то участок пропускает меньший размер кадра, крупные пакеты молча отбрасываются (PMTU blackhole): подключение устанавливается, короткие запросы работают, а крупные ответы и передача данных «зависают». Такую проблему сложно диагностировать — включайте jumbo frames только после проверки пути.

Порядок включения:

  1. Узнайте максимальный MTU сети у сетевых инженеров или провайдера облака. В облачных сетях он часто меньше 9000.

  2. Задайте MTU на интерфейсе в конфигурации сети (пример для netplan):

    1network: 2 version: 2 3 ethernets: 4 eth0: 5 mtu: 9000
  3. Проверьте путь между каждой парой узлов (PostgreSQL ↔ Закрома.Хранение, PostgreSQL ↔ реплики) пакетами с запретом фрагментации. Размер данных = MTU − 28 байт (заголовки IP и ICMP):

    1ping -c 3 -M do -s 8972 <адрес узла> # для MTU 9000

    Пакеты должны доходить без ошибок и потерь. Сообщение message too long означает, что MTU локального интерфейса меньше; 100% потерь — что пакет теряется по пути.

Не полагайтесь на tracepath Определяйте реальный предел ping -M do, последовательно уменьшая размер пакета. При этом TCP-соединения могут работать и при MTU 9000 — то есть при неверном MTU приложения могут выглядеть исправными, а теряться будет только часть трафика.

Если jumbo frames поддерживаются только внутри сегмента, а путь в другие сети (шлюз по умолчанию) — нет, ограничьте MTU маршрута по умолчанию:

1ip route change default via <шлюз> dev eth0 mtu 1500
Результат теста

MTU 8900 вместо 1500 между узлом PostgreSQL и клиентом (две серии, во второй узлы поменялись ролями клиента и сервера):

  • потоковая передача (iperf3) — с 4,7–5,6 до 13–14,5 Гбит/с (+133…209%);
  • короткие запросы метаданных — без изменений (−1…+5%, в пределах погрешности);
  • выгрузка таблицы 640 МБ через \copy — без устойчивого эффекта (−18…+15% в разных сериях): скорость ~200 МБ/с ограничена CPU сервера БД, а не сетью.

Одновременно число повторных передач TCP при 4 параллельных потоках выросло примерно с 300–1200 до 14 000–16 000 за 15 секунд: сеть облака теряла часть крупных кадров под нагрузкой. Пропускная способность при этом выросла, но при включении jumbo frames контролируйте счётчик nstat -az TcpRetransSegs.

Вывод: включайте jumbo frames для сегментов с потоковым трафиком — репликация, резервное копирование, ZDS. Для подключений Закрома.Хранение к PostgreSQL заметного выигрыша нет.

Чек-лист

PostgreSQL:

  • PostgreSQL размещён на отдельном сервере в одной сети с узлами Закрома.Хранение.
  • shared_buffers ≈ 25% RAM, effective_cache_size 50–75% RAM, work_mem 32MB, maintenance_work_mem 512MB–1GB.
  • max_wal_size ≥ 4GB, wal_compression включён, контрольные точки запускаются по таймеру, а не по объёму WAL.
  • Для SSD: random_page_cost = 1.1, effective_io_concurrency = 200.
  • max_connections рассчитан по формуле с запасом 20–30%.
  • Включены tcp_keepalives_*, если между узлами есть межсетевой экран или NAT.

Закрома.Хранение:

  • Пулы worker: max_open_conns × узлы > concurrency клиентов, max_idle_conns = max_open_conns.
  • Количество шардов согласовано с технической поддержкой; шарды по возможности размещены на разных томах.

ОС узла PostgreSQL:

  • Huge pages зарезервированы под shared_buffers, THP не в режиме always.
  • vm.dirty_background_bytes / vm.dirty_bytes заданы в абсолютных значениях.
  • vm.swappiness = 1, vm.overcommit_memory = 2 с проверенным CommitLimit.
  • Данные на SSD/NVMe, WAL на отдельном томе, noatime, планировщик none/mq-deadline.
  • Jumbo frames включены только после проверки ping -M do между всеми узлами.
  • Настройки сохранены в sysctl.d, udev-правилах, fstab и конфигурации сети и переживают перезагрузку.