Разгон PostgreSQL под 1С: optimize_for_1c, производительность, нагрузочное тестирование ~2400 сессий

05.10.26

База данных - HighLoad оптимизация

Кейс адаптации PostgreSQL (Platform V Pangolin) под 1С:Предприятие 8.3: флаг optimize_for_1c, роль без superuser, postgresql.conf и нагрузочный прогон с ~2400 одновременными сессиями. Разберём стенд, метрики тест-центра, диагностику от pg_profile до flame graph и первый симптом конкуренции за блокировки на 1С:Управление холдингом.

PostgreSQL под 1С:Предприятие 8.3 тянет отдельный список требований платформы: права роли, локаль кластера, патчи поведения и профиль нагрузки. На тысячах сеансов дефолтный кластер обычно упирается в блокировки и память на соединение; мы гоняли это на стенде СберТеха на Platform V Pangolin. Ниже, что меняли в конфигурации (optimize_for_1c, отказ от superuser, postgresql.conf) и что показал восьмичасовой прогон с порядка 2400 одновременных сессий.

1. Задача и контекст: корпоративный PostgreSQL для экосистемы 1С

Структура каталогов: PostgreSQL, кластер 1С, тест-центр

К 2022 году в Platform V Pangolin появилась линия поддержки 1С:Предприятие: формальные проверки совместимости, подтверждение от вендора 1С, попадание PostgreSQL из системных требований платформы 8 в перечень допустимых СУБД. Для администратора на практике это сводится к тому, что в ИТС фиксируют одобренные сборки и патчи под 8.3, а в проекте нельзя подставить «любой» PostgreSQL с Docker Hub и ждать штатного поведения платформы.

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

Когда включили длительные прогоны, «ванильное» ядро и конфиг по умолчанию перестали совпадать с тем, как 1С держит транзакции, временные таблицы и блокировки. После каждого прогона меняли conf и патчи и фиксировали отдельный id прогона в тест-центре; обзор альтернативных СУБД здесь не тема.

1.1. Зачем отделять патчи 1С от «обычного» PostgreSQL

1С годами публикует патчи к PostgreSQL: операторы сравнения, типы данных, поведение планировщика. Смешать это с основной веткой без переключателя значит рисковать другими workload на том же дистрибутиве. Изменения под платформу собраны в режиме optimize_for_1c: включённый GUC подтягивает патчи и параметры, согласованные с платформой 8.3, выключенный оставляет кластер ближе к классическому PostgreSQL.

На «ванильном» PostgreSQL одноимённого GUC может не быть. Те же классы проблем (локаль, plantuner в сборках из системных требований 1С и Postgres Pro, лимиты блокировок) смотрите теми же инструментами. Если в вашем контуре нет optimize_for_1c, берите PostgreSQL из системных требований 1С или Postgres Pro, plantuner и тот же набор GUC из материалов ИТС; вместо Kintsugi обычно хватает pg_profile, log_lock_waits и технологического журнала 1С на стороне платформы.

1.2. Роль без superuser и типичная ловушка прав

Платформа исторически ожидала широкие права. Мы выделили роль с минимально необходимым набором по материалам администрирования 1С для PostgreSQL: право создавать базы (CREATEDB), работа с объектами внутри информационных баз, без прав суперпользователя на уровень кластера (изменение pg_hba, pg_reload_conf от имени postgres и тому подобное). Если после миграции с «postgres с паролем администратора» пропадает создание информационной базы, первым делом смотрим grants и membership, а не перезапускаем кластер вслепую. На открытом PostgreSQL ту же картину собираем запросом к pg_roles и системным каталогам.

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

SELECT
    sa.pid,
    sa.usename,
    sa.application_name,
    sa.state,
    sa.wait_event_type,
    sa.wait_event,
    left(sa.query, 120) AS query_preview
FROM pg_stat_activity AS sa
WHERE sa.datname = current_database()
  AND sa.pid <> pg_backend_pid()
ORDER BY sa.state, sa.pid;

В колонках wait_event_type и wait_event ищем Lock, LWLock, IO. ShareLock on transaction в тексте log_lock_waits относится к блокировкам транзакций (MVCC), а не к lightweight lock LockManager; при высокой конкуренции оба слоя могут всплывать рядом. На первом прогоне доминировал transaction lock; LWLock:lock_manager смотрели отдельно там, где он был в wait_event или на flame graph. LockManager в тексте оставляем, если виден LWLock:lock_manager, а не по одной строке лога без сверки с pg_stat_activity.

Если при штатном входе пользователя state долго idle in transaction, а query_preview обрывается на системном запросе платформы, чаще виноваты блокировки или неудачный план, а не «медленный диск».

2. Нагрузочный стенд и как мы измеряли результат

Тест-центр отдаёт APDEX и сырые агрегаты по операциям. На диаграмме видно, как контур «запрос сценария, ответ с метриками» стыкуется с тем, как мы сравнивали среднее время операций и ops/sec, а не только пороги APDEX.

Контекст: 2. Нагрузочный стенд и как мы измеряли результат

Контекст: 2. Нагрузочный стенд и как мы измеряли результат

Запуск сценария и ответ с метриками операций

У каждого прогона свой идентификатор. Без него сравнение правок postgresql.conf теряет смысл.

Стенд собирала команда стенда вместе с нами: физический сервер СУБД на мощной машине в облачном контуре, ферма из восьми серверов кластера публикации 1С и терминальные серверы. Терминалы и rphost крутились в виртуализации, PostgreSQL остался на «железе», чтобы отделить узкие места СУБД от шума гипервизора на стороне приложения.

2.1. Сценарий через тест-центр 1С

На прикладном уровне взяли тест-центр из поставки одного из пакетов 1С, тот же инструмент, что у внедренцев. Он гоняет типовые пользовательские цепочки, фиксирует длительности и даёт сводку в терминах APDEX. APDEX удобен для SLA, но сильно завязан на ожидаемое время отклика в профиле.

Для сравнения до и после тюнинга postgresql.conf и ядра мы опирались на среднее время операций и среднее число операций в единицу времени. Эти величины не зависят от субъективных порогов и лучше показывают, сдвинулась ли производительность после правок work_mem или после разбора блокировок.

2.2. max_connections и архитектура публикации 1С

На стенде подняли max_connections до 2500, осознанное отклонение от типовых рекомендаций «около 1000». Увеличение max_connections не отменяет модель «один rphost, свои подключения к СУБД»: каждый рабочий процесс держит свои сессии, число сеансов платформы умножается на фоновые и служебные запросы.

Больший лимит в PostgreSQL снимает только искусственный потолок. Без балансировки сеансов по серверам кластера можно упереться в CPU на стороне 1С раньше, чем в память postmaster. Сверяем три числа: лимит max_connections, пик pg_stat_activity и настройки кластера 1С (число процессов, блокировка сеансов, распределение по узлам). Плюс лимиты ОС: ulimit на процессы, kernel.sem. Postmaster поднимает отдельный backend на соединение, overhead растёт быстрее, чем кажется по одной строке в конфиге; idle in transaction на сотнях сессий тоже съедает RAM.

3. Инструменты диагностики: от pg_profile до flame graph

Цикл: прогон, pg_profile, правка, повтор

Контекст: 3. Инструменты диагностики: от pg_profile до flame graph

Контекст: 3. Инструменты диагностики: от pg_profile до flame graph

Окно pg_profile подбираем под пик тест-центра, а не под календарь DBA. Сначала фиксируем id прогона в тест-центре, потом снимаем pg_profile на тот же интервал; иначе сравнение conf бессмысленно.

По загрузке CPU не отличить блокировки от плохого плана, нужен стек от тест-центра до wait events и SQL. На уровне PostgreSQL базой стал pg_profile (при необходимости со своими отчётами): срезы по wait events, топ SQL, сравнение интервалов нагрузки. В контуре Pangolin для сессий в реальном времени использовали корпоративный мониторинг (в документации контура он может называться Performance Insights); на открытом PostgreSQL тот же класс задач частично закрывают pg_stat_statements плюс дашборды в Grafana или Zabbix по pg_stat_activity.

Параллельно для трассировки сессий PostgreSQL на стенде опрашивали pg_stat_activity с фиксированным интервалом (порядка секунды в пик), сохраняли pid, application_name, wait_event и метку времени и стыковали с интервалами операций тест-центра по часам прогона. log_min_duration_statement включали точечно, чтобы не утопить диск логами: порог ставили так, чтобы в выборку попадали только запросы, которые реально мешают SLA тест-центра.

Когда подозрение падает на блокировки, на «ванильном» PostgreSQL без Kintsugi смотрим pg_locks в связке с pg_stat_activity и при необходимости подключаем расширение pg_wait_sampling, если оно есть в сборке. auto_explain с log_nested_statements помогает поймать внезапный nested loop на временных таблицах 1С после смены статистики.

Картина блокировок в момент регламентной операции (закрытие периода, массовое проведение):

SELECT
    bl.pid AS blocked_pid,
    ka.query AS blocking_query,
    a.query AS blocked_query,
    bl.mode AS blocked_mode,
    kl.mode AS blocking_mode
FROM pg_locks AS bl
JOIN pg_stat_activity AS a ON a.pid = bl.pid
JOIN pg_locks AS kl
    ON kl.locktype = bl.locktype
   AND kl.database IS NOT DISTINCT FROM bl.database
   AND kl.relation IS NOT DISTINCT FROM bl.relation
   AND kl.page IS NOT DISTINCT FROM bl.page
   AND kl.tuple IS NOT DISTINCT FROM bl.tuple
   AND kl.virtualxid IS NOT DISTINCT FROM bl.virtualxid
   AND kl.transactionid IS NOT DISTINCT FROM bl.transactionid
   AND kl.classid IS NOT DISTINCT FROM bl.classid
   AND kl.objid IS NOT DISTINCT FROM bl.objid
   AND kl.objsubid IS NOT DISTINCT FROM bl.objsubid
   AND kl.pid <> bl.pid
JOIN pg_stat_activity AS ka ON ka.pid = kl.pid
WHERE NOT bl.granted;

В пике тяжёлый join по pg_locks лучше не гонять постоянно: снимайте через pg_wait_sampling или консоль Kintsugi, ad-hoc запрос делайте на копии или коротким окном.

Если blocked_mode и blocking_mode указывают на RowExclusive и ShareLock одновременно на одних и тех же relation, а blocked_query содержит шаблон платформенного UPDATE регистра, дальше копаем длительность транзакций и параллелизм регламентов, а не индексы конфигурации. Для transaction lock сверяем locktype и mode в pg_locks с wait_event_type Lock в pg_stat_activity.

На нижнем уровне perf record и flame graph показывали, где в ядре застревает время: lock менеджер, буферный менеджер, сортировки под work_mem. Участки стека, которые повторялись от прогона к прогону, становились аргументом за точечный патч, а не за очередное увеличение shared_buffers.

4. Platform V Kintsugi в сопровождении высокой нагрузки

Kintsugi, графическая консоль сопровождения Platform V: нагрузка по кластерам, ожидания, фильтры по сессиям, блокировкам, хостам. В пик теста с ~2400 сессиями она сокращала путь от «тормозит проведение» до конкретного wait event: меньше ручного перебора pid.

Контекст: 4. Platform V Kintsugi в сопровождении высокой нагрузки

Контекст: 4. Platform V Kintsugi в сопровождении высокой нагрузки

Если Kintsugi недоступна, тот же класс задач закрываем связкой pg_stat_activity с частым опросом, pg_profile или pg_stat_statements, логи PostgreSQL с log_lock_waits на время расследования и технологический журнал 1С на стороне платформы. Сводите метки тест-центра с pg_stat_activity по времени; без этого не поймёте, какая операция сценария села на Lock.

5. Первые шаги адаптации: optimize_for_1c, роли, локаль, postgresql.conf

В дистрибутиве с optimize_for_1c патчи поведения не смешиваются с прочими нагрузками. Чаще всего забывают локаль при initdb, роль без superuser и перезапуск с plantuner в shared_preload_libraries.

Контекст: 5. Первые шаги адаптации: optimize_for_1c, роли, локаль, postgresql.conf

Контекст: 5. Первые шаги адаптации: optimize_for_1c, роли, локаль, postgresql.conf

5.1. Локаль ru_RU.UTF-8 на этапе initdb

Прикладное создание информационной базы локаль кластера не задаёт. Если initdb прошёл с C или en_US, сортировки и сравнения строк для русскоязычных данных могут вести себя иначе, чем ожидает платформа. Кластер инициализируем с ru_RU.UTF-8 явно.

У Postgres Pro в материалах для 1С встречается профиль tune при initdb; смысл один: зафиксировать локаль до первой базы 1С.

5.2. pg_hba.conf и password_encryption

Цепочка «платформа, ODBC или драйвер PostgreSQL, pg_hba.conf» до сих пор встречается с MD5 в настройке password_encryption. Мы сознательно оставляем md5 там, где стек аутентификации платформы ещё не переведён на SCRAM; в дорожной карте внедрения заложите переход на scram-sha-256 и проверку драйвера до смены алгоритма в бою.

При миграции на scram-sha-256 проверяем метод в pg_hba (scram-sha-256), версию платформы 8.3, сборку драйвера и пересоздание пароля роли после смены алгоритма. Смешение md5 в hba и scram в postgresql.conf даёт отказ входа без понятной ошибки на стороне 1С. Актуальную связку «платформа + драйвер + СУБД» на дату внедрения сверяйте с ИТС и release notes; номера релизов здесь не фиксируем.

5.3. Блок параметров postgresql.conf по рекомендациям 1С

Актуальный перечень для сборок PostgreSQL из системных требований 1С к платформе 8 и в материалах по администрированию; для Postgres Pro отдельно описаны plantuner и plantuner.fix_empty_table для пустых таблиц, которые 1С создаёт пачками при работе с временными данными. Строки с plantuner и optimize_for_1c относятся только к совместимым сборкам, которые публикует 1С; на чистом PostgreSQL без модуля plantuner их копировать нельзя, начните с проверки списка СУБД в ИТС.

Рабочий фрагмент, который накатываем после включения optimize_for_1c и перезапуска с shared_preload_libraries:

# фрагмент postgresql.conf под 1С:Предприятие 8.3
# plantuner и optimize_for_1c — только в сборках из системных требований 1С
optimize_for_1c = on
shared_preload_libraries = 'plantuner'
plantuner.fix_empty_table = on

temp_buffers = 256MB
work_mem = 64MB
max_locks_per_transaction = 256
random_page_cost = 1.1
geqo = on
geqo_threshold = 12
collapse_limit = 8
standard_conforming_strings = off
escape_string_warning = off
row_security = off

password_encryption = md5
max_connections = 2500

Память. temp_buffers задаётся на backend (на сессию), не на весь кластер. Значение 256 MB с нашего стенда, не универсальная константа. Оценку RAM для пика считаем грубо так: число одновременно активных backend умножаем на work_mem, добавляем запас на temp (temp_buffers у активных сессий с временными таблицами) и shared_buffers; умножать 256 MB на все 2500 соединений нельзя, но и игнорировать сотни параллельных сортировок с work_mem 64 MB нельзя. temp_buffers и work_mem подбираем под RAM и пиковое число активных запросов: 1С активно использует temporary tables, урезание work_mem бьёт по сортировкам в отчётах.

Планировщик. random_page_cost около 1,1 как в рекомендациях 1С для SSD; на массивах с кэшем СХД и на медленных SATA уточняйте по планам и соотношению seq/idx scan на вашем железе. От geqo снизили collapse_limit при geqo_threshold 12 (см. фрагмент конфига): при наших профилях запросов планы на широких JOIN стали предсказуемее.

Блокировки и совместимость. max_locks_per_transaction на 256 связан с большим числом объектов метаданных в типовых конфигурациях; занижение даёт ошибки при обновлении конфигурации или реструктуризации. row_security отключают: RLS на уровне PostgreSQL 1С не использует как основной механизм разграничения.

После рестарта СУБД делаем смоке-тест сеанса и связки платформа, PostgreSQL: минимальный запрос из той же информационной базы, что участвует в прогоне (у нас 1С:Управление холдингом). Полная приёмка plantuner, восстановление dt и блокировки при регламентных операциях, в чек-листе 5.4.

Фрагмент для регламентного задания или одноразовой проверки после рестарта:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|   1 КАК ПроверкаСоединения";

Попытка
    Результат = Запрос.Выполнить();
    Если Результат.Пустой() Тогда
        ВызватьИсключение "После рестарта PostgreSQL нет ответа от информационной базы";
    КонецЕсли;
Исключение
    ВызватьИсключение "После рестарта PostgreSQL: " + ОписаниеОшибки();
КонецПопытки;

Если запрос падает по таймауту, а pg_stat_activity показывает Lock на системных таблицах, возвращаемся к чек-листу приёмки, а не к настройкам кластера 1С.

5.4. Чек-лист приёмки после изменений

После правок postgresql.conf задачу не закрываем, пока не пройден короткий чек-лист. Перезапуск с проверкой, что plantuner поднялся (в логе postmaster нет ошибки загрузки shared_preload_libraries).

Дальше: создать пустую информационную базу, восстановить из dt, зайти тонким клиентом. Контрольный прогон регламентной операции в копии базы с мониторингом pg_locks. Сравнение conf годится только когда время операций тест-центра ложится на те же минуты, что срез pg_profile; иначе результат прогона врёт.

6. Тест 1С:Управление холдингом (~2400 сессий): что показала нагрузка

 

Первый длинный сценарий выбрали на 1С:Управление холдингом: около восьми часов непрерывного прогона, порядка 2400 одновременных сессий по данным стенда. Тест-центр шёл параллельно с мониторингом СУБД; APDEX смотрели, но решения принимали по среднему времени операций и по числу операций в единицу времени.

В материалах кейса стартовый симптом называли конкуренцией в LockManager; по wait_event и pg_locks на первом прогоне ведущим был transaction lock (ShareLock on transaction), LWLock:lock_manager там, где зафиксирован в мониторинге. Диск и rphost запас были; упёрлись в очереди ShareLock on transaction после включения optimize_for_1c и базового postgresql.conf: те же строки в log_lock_waits, конкурирующие transactionid в pg_locks, у части баскенд-процессов wait_event_type Lock в pg_stat_activity.

Kintsugi группировал такие сессии по интервалам тест-центра; flame graph показывал заметную долю времени в lock-related стеках. На этом прогоне главным был transaction lock; LWLock:lock_manager не подменяем им в отчётах без факта в wait_event.

Фрагмент лога ниже обезличенный и с синтетическими числами. Он иллюстрирует тип log_lock_waits и длинный UPDATE регистра нагрузочной конфигурации; это не дословная выписка одного прогона и не отчёт с замерами «до/после».

<дата> <время> MSK [<pid>] <роль>@<база> LOG:  duration: 8423.117 ms  statement:
        UPDATE _AccRgXXXX SET _FldYYYY = $1 WHERE _IDRRef = $2
<дата> <время> MSK [<pid>] <роль>@<база> LOG:  process <pid> still waiting for ShareLock on transaction <txid> after 1000.042 ms
<дата> <время> MSK [<pid>] <роль>@<база> LOG:  process <pid> acquired ShareLock on transaction <txid> after 1667.901 ms

Дальше в том же цикле меняли по одному слою и снова гоняли сценарий тест-центра: точечные изменения в ядре под профиль 1С, уточнение postgresql.conf, повторные прогоны. «Тест 2» и последующие цифры здесь не публикуем, их не было в согласованной основе кейса.

На «ванильном» PostgreSQL без корпоративных патчей те же transaction lock всплывают при тысячах сессий. Отличие Pangolin в том, что optimize_for_1c и последующие правки ядра нацелены на сочетание паттернов блокировок 1С и MVCC PostgreSQL; флаг в Pangolin по смыслу близок связке патчей 1С и plantuner в сборках из ИТС. На открытом PostgreSQL разумный порядок тот же: воспроизвести нагрузку тест-центром или регламентным сценарием, включить log_lock_waits, снять pg_profile за окно пика и только потом трогать work_mem «на глаз».

Что вынести из кейса

Первый длинный прогон на ~2400 сессиях показал, что без optimize_for_1c и согласованного postgresql.conf платформа упирается в блокировки транзакций раньше, чем в «нехватку железа». Без роли без superuser и локали ru_RU.UTF-8 при initdb типовые ошибки создания ИБ останутся; один рост max_connections этого не компенсирует.

APDEX для SLA оставьте, а тюнинг postgresql.conf оценивайте по среднему времени операций и wait_event на том же id прогона. После правки конфигурации СУБД пройдите чек-лист из раздела 5.4, без него сравнение «до/после» некорректно.

Вступайте в нашу телеграмм-группу Инфостарт

PostgreSQL 1С:Предприятие 8.3 Администрирование Производительность Нагрузочное тестирование Platform V Pangolin optimize_for_1c PostgreSQL 1С 8.3 разгон производительности нагрузочное тестирование postgresql.conf plantuner LockManager pg_profile

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

HighLoad оптимизация Разработчик 1С 8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

Использование оператора «В» для полей или данных составного типа (например, Регистратор) может приводить к неочевидным проблемам.

10.11.2025    15919    ivanov660    48    

58

HighLoad оптимизация Разработчик 1С:Предприятие 8 1C:ERP Бесплатно (free)

Приведем примеры использования различных в динамических списках и посмотрим, почему это плохо.

18.02.2025    16501    ivanov660    39    

62

HighLoad оптимизация Разработчик Россия Бесплатно (free)

А вы знали, что сервер 1С при соединении с базой на сервере PostgreSQL самостоятельно устанавливает некоторые параметры? Это важно знать при настройке сервера и отладке долгих запросов. Предлагаю разобраться.

27.08.2024    10417    soulner    10    

41

HighLoad оптимизация Технологический журнал Системный администратор Разработчик Бесплатно (free)

Обсудим поиск и разбор причин длительных серверных вызовов CALL, SCALL.

24.06.2024    19154    ivanov660    13    

64

HighLoad оптимизация Разработчик 1С:Предприятие 8 Бесплатно (free)

Метод очень медленно работает, когда параметр приемник содержит намного меньше свойств, чем источник.

06.06.2024    24996    Evg-Lylyk    73    

46

HighLoad оптимизация Разработчик 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    14639    spyke    29    

54
Для отправки сообщения требуется регистрация/авторизация