Приветствую тебя, мой юный 1С-ник. Ты, как и я, не любишь 1С и стараешься как можно быстрее и качественнее отвязаться от задач, связанных с этим продуктом, чтобы больше никогда к ним не возвращаться? Настроил — и забыл, это наш подход!
1С тормозит. Корову можно кормить топовыми процессорами, SSD и немеряным количеством оперативки, но гепардом она всё равно не станет. Этому есть несколько причин:
- Транзакционная модель, от этого в финансах не уйти. Транзакция сидит на транзакции и транзакцией погоняет. Опять же, транзакции подразумевают блокировки, пока блокировка не будет снята, объект не станет доступным другим пользователям.
- Доступность среды разработки. Куча разработчиков сидят, что-то там программируют. Бесконечные циклы, утечки памяти, перерасход ресурсов, кривые руки и непонимание того, что они делают. Ладно бы это делалось централизованно, но сколько 1С серверов, столько и разработчиков. Одну и ту же задачу можно решить разными способами, зачастую решение задачи оказывается не самым оптимальным. В итоге мы слышим: "Это железо тормозит!" "Это база тормозит!"
- Временные таблицы. Весь 1С построен на временных таблицах. На каждый чих создаётся временная таблица, с которой проводятся операции, на них даже индексы строятся. И если БД не может правильно обрабатывать временные таблицы, то успеха не будет. Table Scan — не самая быстрая операция.
- Неправильные настройки сервера БД. Кривые настройки — такой же результат.
Сегодня будем настраивать PostgreSQL 11.9 на сервере Windows Server 2019.
Что лучше: MSSQL или PostgreSQL?
Сложно сказать. С одной стороны, крутые исследователи заявляют о том, что правильно настроенный PostgreSQL выигрывает у MSSQL:
https://infostart.ru/1c/articles/962876/
И тут я такой: "А если поднять у MSSQL tempdb в RAM диск?" И снова становится непонятно. Но понятно одно, MSSQL стоит денег, а PostgreSQL бесплатный.
Итак, тестовый стенд (или правильнее сказать, реальный?):
- Сервер, виртуальный, операционная система Windows Server 2019 Standard, триальная.
- CPU: 16 ядер
- ОЗУ: 64 ГБ
- Диск SSD, отдельный для БД.
- Размер базы: 50 Гб
- 1С 8.3 и PostgreSQL 11.9-1.1C вместе на одном сервере
- 50 аккаунтов пользователей 1С в настоящее время
По хорошему, мух следует отделять от котлет. И разносить 1С и БД на разные серверы. Однако, на практике, часто бывает иначе. Сервер имеется один, на нём размещают и базу и сервер 1С. И это не просто предположение, вчера привезли новый сервер и поставили задачу: установить Windows, MSSQL и 1С. Всё на одну машину. Но это немного другая история, не связанная с текущей.
Как разделить ресурсы между 1С и PostgreSQL?
Очень просто. 50 пользователей 1С работают в разное время, создают 3-4 рабочих процесса и забирают примерно 8-12 Гб ОЗУ. Оперативку я мысленно разделил так: 75% (48 Гб) отдаём PostgreSQL, 25% (16 Гб) отдаём 1С.
Следовательно, для настроек PostgreSQL я исхожу из цифр:
- CPU: 16 ядер
- ОЗУ: 48 ГБ
- Диск: SSD
- Количество пользователей 1С: 100 (с расчётом на будущее)
Далее RAM — это 48 Гб, которые выделены для PostgreSQL.
Полезные ссылки
https://infostart.ru/public/554213/
http://www.gilev.ru/postgresql/
Настройка PostgreSQL 11.9
Основной файл настроек PostgreSQL — postgresql.conf. Приступим.
Сеть
max_connections = 100
Максимальное количество одновременных подключений к БД. Я просто установил в два раза больше, чем текущее количество 1С пользователей. К базе ещё подключается пользователь для мониторинга и администраторы. Если будет не хватать, то можно потом изменить параметры.
Память
shared_buffers = 12GB
Количество памяти, выделенное для кэша страниц. Рекомендуется от 1/8 до 1/4 RAM. Вычисляю: 48 Гб / 4 = 12 Гб.
maintenance_work_mem = 2024MB
Лимит памяти для внутренних обслуживающих задач. Рекомендуется 1/4 RAM. Однако, при увеличении больше 2024MB служба PostgreSQL не запускается.
effective_cache_size = 36GB
Кэш файловой системы. Планировщик исходя из этого параметра принимает решение об использовании больших индексов (IndexScan), и это хорошо. Рекомендуется RAM - shared_buffers. Вычисляю: 48 Гб - 12 Гб = 36 Гб.
work_mem = 2024MB
Лимит памяти для обработки одного запроса. При превышении этого объёма сервер начинает использовать временные файлы на диске. Рекомендуется от 1/32 до 1/16 RAM. Однако, при увеличении больше 2024MB служба PostgreSQL не запускается.
temp_buffers = 2024MB
Буфер под временные объекты, например, для временных таблиц. Рекомендуется 1/20 RAM. Однако, при увеличении больше 2024MB служба PostgreSQL не запускается.
Процессор
max_worker_processes = 16
Максимальное число фоновых процессов. Зависит от количества выделенных для PostgreSQL ядер CPU. По калькулятору.
max_parallel_workers = 8
Задаёт максимальное число рабочих процессов, которое система сможет поддерживать для параллельных запросов. Рекомендуют равным max_worker_processes, однако в этом случае какой-то "толстый" запрос может сожрать все потоки и другим не достанется. Использую половину процессоров.
max_parallel_workers_per_gather = 8
Задаёт максимальное число рабочих процессов, которые могут запускаться одним узлом Gather илиGather Merge. Не более max_parallel_workers, задал по максимуму.
max_parallel_maintenance_workers = 4
Задаёт максимальное число рабочих процессов, которые могут запускаться одной служебной командой. По калькулятору.
max_files_per_process = 1000
Задаёт максимальное число файлов, которые могут быть одновременно открыты каждым процессом. Значение по умолчанию — 1000 файлов.
autovacuum_max_workers = 4
Задаёт максимальное число процессов автоочистки (не считая процесс, запускающий автоочистку), которые могут выполняться одновременно. Чем больше запросов записи, тем больше процессов. Если база только для чтения, то достаточно одного процесса.
Диск
fsync = on
Если параметр fsync включён, то при выполнении операции COMMIT данные сразу переписываются из кэша операционной системы на диск, тем самым гарантируется целостность данных при возможном аппаратном сбое. При этом снижается производительность операций записи на диск, поскольку при этом не используются возможности отложенной записи данных операционной системы. Данный параметр можно отключать только при наличие аппаратного RAID контроллера с кэшем в режиме write-back и батарейкой для гарантированной записи данных при отключении питания.
#effective_io_concurrency = 2
Задаёт допустимое число параллельных операций ввода/вывода, которое говорит PostgreSQL о том, сколько операций ввода/вывода могут быть выполнены одновременно. Для магнитных носителей хорошим начальным значением этого параметра будет число отдельных дисков, составляющих массив RAID 0 или RAID 1, в котором размещена база данных. Для RAID 5 следует исключить один диск (как диск с чётностью). У меня один диск, поэтому у меня данный параметр закомментирован.
wal_sync_method = open_datasync
Метод, который используется для принудительной записи данных на диск. Возможные значения:
- open_datasync – запись данных методом open() с параметром O_DSYNC,
- fdatasync – вызов метода fdatasync() после каждого commit,
- fsync_writethrough – вызывать fsync() после каждого commit игнорирую паралельные процессы,
- fsync – вызов fsync() после каждого commit,
- open_sync – запись данных методом open() с параметром O_SYNC.
Выбор метода зависит от операционной системы под управлением, которой работает PostgreSQL. Для Windows рекомендуется open_datasync. Для Linux — fdatasync.
#checkpoint_segments = 32
В версии PostgreSQL 11.9 не используется, поэтому у меня данный параметр закомментирован. Данный параметр определяет количество сегментов (каждый по 16 МБ) лога транзакций между контрольными точками. В зависимости от объема данных установите этот параметр в диапазоне от 12 до 256 сегментов и, если в логе появляются предупреждения (warning) о том, что контрольные точки происходят слишком часто, постепенно увеличивайте его. Можно установить в 32 (если у вас PostgreSQL поддерживает этот параметр) и дальше смотреть предупреждения в логе.
checkpoint_completion_target = 0.9
Часть интервала контрольной точки. Рекомендуется максимальное значение 0.9.
wal_buffers = 16MB
PostgreSQL сначала пишет в буферы, а затем эти буферы сбрасываются в WAL файлы на диск. По молчанию 16MB.
min_wal_size = 4GB
Минимальный размер WAL файла. Установил чуть больше, чем предложил калькулятор.
max_wal_size = 16GB
Максимальный размер WAL файла. Рекомендуется от 2 * min_wal_size до 4 * min_wal_size.
autovacuum = on
Включение автоочистки.
bgwriter_delay = 20ms
Время сна между циклами записи на диск фонового процесса записи. Данный процесс ответственен за синхронизацию страниц, расположенных в shared_buffers с диском. Слишком большое значение этого параметра приведет к возрастанию нагрузки на checkpoint процесс и процессы, обслуживающие сессии (backend). Малое значение приведет к полной загрузке одного из ядер.
bgwriter_lru_multiplier = 4.0 bgwriter_lru_maxpages = 400
Параметры, управляющие интенсивностью записи фонового процесса записи. За один цикл bgwriter записывает не больше, чем было записано в прошлый цикл, умноженное на bgwriter_lru_multiplier, но не больше чем gwriter_lru_maxpages.
Параметры, управляющие интенсивностью записи фонового процесса записи.
synchronous_commit = off
Отключаем синхронизацию с диском в момент коммита. Есть риск потери последних нескольких транзакций, но гарантируется целостность базы данных. Значительно увеличивает производительность.
commit_delay = 1000
Пауза в микросекундах перед собственно выполнением сохранения WAL.
commit_siblings = 5
Минимальное число одновременно открытых транзакций, при котором будет добавляться задержка commit_delay.
Оптимизатор запросов
default_statistics_target = 300
Количество записей, просматриваемых при сборе статистики по таблицам. Рекомендуется для 1С от 1000 до 10000. Я поставил 300, если будут зависания, параметр можно увеличить.
from_collapse_limit = 20
Задаёт максимальное число элементов в списке FROM, до которого планировщик будет объединять вложенные запросы с внешним запросом. При меньших значениях сокращается время планирования, но план запроса может стать менее эффективным.
join_collapse_limit = 6
Задаёт максимальное количество элементов в списке FROM, до достижения которого планировщик будет сносить в него явные конструкции JOIN (за исключением FULL JOIN). Рекомендуется 1, но сложные запросы с большим количеством соединений и источников данных станут надолго зависать. Поэтому ставлю чуть меньше значения по умолчанию — 6.
seq_page_cost = 0.1
Задаёт приблизительную стоимость последовательного чтения одной страницы с диска. Для NVMe дисков рекомендуется 0.1. Для HDD 1.5 - 2.0. Для SSD 1.1 - 1.3. Можно посмотреть характеристики ваших дисков.
random_page_cost = 0.4
Задаёт приблизительную стоимость случайного чтения одной страницы с диска. Рекомендуется ставить чуть больше чем seq_page_cost.
cpu_operator_cost = 0.00025
Задаёт приблизительную стоимость обработки оператора или функции при выполнении запроса. Рекомендуется 0.00025.
online_analyze.table_type = 'temporary'
Типы таблиц, для которых выполняется немедленный анализ:
- all (все),
- persistent (постоянные),
- temporary (временные),
- none (никакие).
При возникновении проблем с производительностью выполнения регламентных операций можно включить сбор статистики для всех таблиц: all.
online_analyze.threshold = 50
Минимальное число изменений строк, после которого может начаться немедленный анализ.
online_analyze.scale_factor = 0.1
Процент от размера таблицы, при котором начинается немедленный анализ.
online_analyze.min_interval = 10000
Минимальный интервал времени между вызовами ANALYZE для отдельной таблицы (в миллисекундах).
online_analyze.verbose = off
Отключаем подробные сообщения расширения online_analyze.
online_analyze.local_tracking = off
online_analyze использует для временных таблиц системную статистику по умолчанию.
plantuner.fix_empty_table = on
plantuner будет обнулять число страниц/кортежей в таблице, которая не содержит никаких блоков в файле.
enable_nestloop = off
Отключает использование планов соединения с вложенными циклами.
enable_mergejoin = off
Отключает использование планов соединения слиянием.
Сбор статистики
track_counts = on
Включает сбор статистики активности в базе данных. Этот параметр по умолчанию включён, так как собранная информация требуется автоочистке.
1С
standard_conforming_strings = off
Разрешить использовать символ "\" для экранирования.
escape_string_warning = off
Не выдавать предупреждение об использовании символа "\" для экранирования.
shared_preload_libraries = 'online_analyze, plantuner'
Библиотеки, которые будут загружаться при запуске сервера.
online_analyze.enable = on
Анализ статистики временных таблиц.
PostgreSQL
max_locks_per_transaction = 256
Этот параметр управляет средним числом блокировок объектов, выделяемым для каждой транзакции.
ssl = off
Шифрование. Если сеть защищена, то отключаем. Если 1С и PostgreSQL находятся на одном сервере — тем более отключаем.
Прошёл месяц
Сначала были какие-то ошибки в логах postgresql, но они были связаны с процессом разработки. Месяц — полёт нормальный.