Горизонтальное масштабирование 1С: переносим отчеты на реплику без потери производительности

02.02.26

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

В статье рассматриваются текущие возможности горизонтального масштабирования СУБД для 1С, а также какое решение предлагает Tantor Postgres.

 

Горизонтальное масштабирование и текущие ограничения 1С

Горизонтальное масштабирование — это подход к увеличению производительности системы путем добавления новых серверов вместо наращивания мощностей существующих. Это позволяет распределять нагрузку между множеством узлов и практически неограниченно расширять вычислительные ресурсы. В 1С этот подход реализован только лишь частично: платформа 1С поддерживает кластеризацию серверов приложений, что позволяет запускать несколько серверов 1С:Предприятие для параллельной обработки запросов пользователей и выполнения бизнес-логики. Например, на отдельные серверы приложений часто выносят отчеты и тяжелые регламентные операции, чтобы они не влияли на основную работу пользователей. Это помогает справляться с возросшей нагрузкой: когда одновременно работают тысячи пользователей, задачи распределяются между серверами кластера, и система остаётся отзывчивой.

Однако критическое ограничение состоит в том, что все серверы приложений 1С работают с единой базой данных, которая и становится узким местом всей системы. СУБД — будь то MS SQL Server или PostgreSQL — остаётся единой точкой входа для всех операций чтения и записи, и именно здесь при росте нагрузки происходит основное замедление. Реляционные базы данных по своей природе горизонтально масштабируются сложно из-за необходимости поддержания целостности данных, управления распределёнными транзакциями и координации блокировок между узлами. В результате — сколько бы серверов приложений вы ни добавили в кластер 1С, все они будут конкурировать за доступ к одной и той же базе данных, конкурируя за ее ресурсы. Таким образом, горизонтальное масштабирование в 1С работает лишь на уровне прикладной логики, но не решает фундаментальную проблему масштабирования слоя хранения данных.

 

 

 

Механизм копий баз данных

Начиная с версии 8.3.14, в платформе 1С появился механизм копий баз данных. Он позволяет распределять нагрузку на чтение между несколькими экземплярами базы данных, где одна база выступает главной (принимает все операции записи), а остальные являются её репликами и могут обслуживать часть запросов на чтение. Платформа поддерживает два типа репликации: стандартную и внешнюю. Стандартная репликация реализуется средствами самой платформы 1С — сервер приложений самостоятельно отслеживает изменения в главной базе и периодически синхронизирует данные с копиями, что даёт платформе полный контроль над процессом, но требует дополнительных ресурсов сервера 1С и вызывает некоторую задержку в актуальности данных. Внешняя репликация, напротив, полностью полагается на встроенные механизмы репликации СУБД — для PostgreSQL это streaming replication, для MS SQL Server — Always On или Log Shipping, а платформа 1С лишь использует готовые реплики, направляя на них операции чтения. 

По сути тип репликации "стандартный" — это логическая репликация, а "внешний" — физическая. Преимущество внешней репликации заключается в том, что она работает на уровне блоков данных или журнала транзакций СУБД, обеспечивая практически мгновенную синхронизацию с минимальной задержкой, в то время как стандартная репликация 1С работает на уровне прикладных данных и синхронизирует изменения дискретно с заметными интервалами. Кроме того, внешняя репликация не нагружает сервер приложений 1С дополнительной работой по отслеживанию и переносу изменений: вся тяжесть ложится на СУБД, которая оптимизирована именно для этой задачи. У компаний, которым этот функционал может быть полезен, всегда есть реплики, и использование внешней репликации для них наиболее оптимально, ведь нет необходимости поднимать логические копии базы данных, обслуживать их, поддерживать в актуальном состоянии и т.д. К тому же мощности серверов, где находятся реплики, как правило, простаивают, так почему бы не утилизировать ради столь благих намерений? Однако использование внешней репликации PostgreSQL накладывает существенное ограничение: на read-only реплике PostgreSQL невозможно создавать временные таблицы, а платформа 1С активно использует их для выполнения сложных запросов, построения отчётов и обработки данных.

Это означает, что при внешней репликации PostgreSQL часть запросов, требующих создания временных структур, не сможет быть выполнена на копии и будет автоматически перенаправлена на главную базу, а это снизит эффективность распределения нагрузки и, по сути, сделает механизм нерабочим, поскольку большая часть запросов 1С будет использовать временные таблицы. MS SQL Server в этом плане более гибок — его реплики Always On позволяют создавать временные объекты в tempdb, что делает внешнюю репликацию на SQL Server более привлекательным вариантом для 1С.

 

 

При этом на реплике могут быть выполнены не все запросы, а только те, которые удовлетворяют таким условиям:

  1. Запрос выполняется с помощью объекта Запрос или при работе с системой компоновки данных;
  2. Запрос выполняется вне транзакции;
  3. В объекте Запрос не используется менеджер временных таблиц.

 

Проблема и ее решение в Tantor Postgres

Давайте посмотрим, в чем заключается проблема с выполнением запросов на реплике Read Only. Если выполнить на ней запрос создания временной таблицы (а 1С постоянно создает временные таблицы) и индекса к этой таблице...

drop table if exists tt1 cascade;create temporary table tt1 (_Q_001_F_000RRef bytea) without oids;
drop index if exists tmpind_0; create index tmpind_0 on pg_temp.tt1(_Q_001_F_000RRef );

...то мы получим ошибку:

ERROR: cannot execute DROP TABLE in a read-only transaction SQL state: 25006

 

PostgreSQL запрещает выполнение DDL-команд на реплике, в том числе и команды, связанные с созданием временных таблиц. Казалось бы, временная таблица существует недолго  и на данные в самой базе никак не влияет, так почему бы не разрешить ее создание, удаление? Все дело в том, что создание временных объектов (таблиц, индексов) затрагивает 13 таблиц системного каталога. Посмотрим, что произошло в основных из них при выполнении вышеприведенной команды:

  • pg_class — хранит информацию о названии всех таблиц, а также их внутренних идентификаторах (oid). В нашем случае была бы добавлена информация о таблице "tt1";
  • pg_attribute — хранит информацию о всех полях таблиц. В нашем случае была бы добавлена информация о поле "_q_001_f_000rref" таблицы "tt1";
  • pg_type — хранит информацию о типах полей таблиц. В нашем случае была бы добавлена информация, что поле "_q_001_f_000rref" имеет тип "bytea";
  • pg_index — хранит информацию о созданных индексах. В нашем случае была бы добавлена информация об индексе "tmpind_0";
  • pg_depend — хранит информацию о зависимостях между объектами БД. В нашем случае была бы добавлена информация о том, что индекс "tmpind_0" относится к таблице "tt1";
  • ...и т.д.

То есть, создание временных объектов изменяет данные! Если бы PostgreSQL разрешил изменять таблицы системного каталога на реплике при создании временных объектов, это привело бы к следующим проблемам:

  1. Разница в данных между мастером и репликой. Системный каталог на реплике содержал бы записи о временных объектах, которых нет на мастере, что нарушило бы фундаментальный принцип репликации: реплика должна быть точной копией мастера;
  2. Конфликты при применении WAL-записей. Механизм streaming replication последовательно применяет WAL-записи с мастера на реплику, и если реплика генерирует собственные изменения в системном каталоге, это создаёт конфликты при применении входящих изменений, делая невозможным гарантировать консистентность данных;
  3. Коллизии внутренних идентификаторов объектов (OID). Если бы реплика начала создавать свои объекты с собственными OID, возник бы риск коллизий с объектами, создаваемыми на мастере и реплицируемыми позже;
  4. Блокировки критических страниц системных таблиц. Временные объекты на реплике могли бы заблокировать страницы системных таблиц (pg_class, pg_attribute и других), из-за чего реплика не смогла бы применить изменения из WAL мастера, и репликация остановилась бы с ошибкой конфликта.

Начиная с версии 17.5, в СУБД Tantor Postgres появился параметр enable_temp_memory_catalog, который позволяет создавать временные объекты без изменения таблиц системного каталога. При включении этого параметра информация о метаданных временных объектов хранится в локальной памяти каждого соединения к СУБД, а не в общем системном каталоге. Это меняет подход к работе с временными объектами и помогает решить как проблемы, описанные выше, так и улучшить вообще производительность системы (более подробно можно прочесть здесь). 

Мы проектировали данную функциональность с прицелом на будущее, понимая возможности, которые откроет реализация. Давайте посмотрим, как это работает!

 

Настраиваем копию базы данных

Для начала нужно настроить копию баз данных в 1С. Делается это через пункт меню "Функции для технического специалиста" – "Стандартные" – "Управление копиями базы данных". Создаем новый элемент и заполняем его следующим образом:

 

В блоке 1 вводим название элемента, путь к базе на реплике и параметры аутентификации. Галку "Встроенный дата акселлератор" не ставим, т.к. используем существующую базу данных.

В блоке 2 выделяем все метаданные, а в блоке 3 не трогаем ничего, оставляем все по умолчанию. 

Нажимаем "ОК" и получаем вопрос:

 

 

Здесь нужно нажать "Сохранить как есть". После этого элемент запишется и в форме списка у него будет Состояние = Включена:

 

Копия баз данных со стороны 1С готова к использованию!

!Предупреждение о размещении копии

Выше при сохранении элемента копии БД мы получили предупреждение: БД уже используется информационной базой.

В платформе 8.3.26 в этом случае использование копии БД было невозможным, поскольку она сразу после записи переходила в состояние "Отключена", и обойти эту проверку было невозможным. Даже если создать новую базу на стороне СУБД, о которой сервер приложений 1С ничего не знает, ошибка все равно будет возникать. А вот в платформе 8.3.27 предупреждение выдается, но после записи использование копии БД возможно, поскольку она не отключается.

Также необходимо установить дополнительные параметры на реплике Tantor Postgres:

enable_temp_table_on_replica = 'on'

hot_standby_feedback = 'on'

max_standby_streaming_delay = 300s

Разберем, что значат эти настройки, и как они влияют на работу 1С.

Параметр enable_temp_table_on_replica снимает ограничение на создание временных таблиц и индексов на реплике. Работает совместно с рассмотренным выше параметром enable_temp_memory_catalog.

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

40001: ERROR: canceling statement due to conflict with recovery

DETAIL: User query might have needed to see row versions that must be removed.

 

Параметр max_standby_streaming_delay определяет время, на которое реплика может задержать применение WAL-записей, если их применение вызовет конфликт с выполняющимися на реплике запросами на чтение. Например, в записях WAL пришло удаление строки в таблице, которое конфликтует с активным запросом на чтение из этой таблицы. Если за 300 секунд данный активный запрос не выполнится, то он вызовет упомянутую выше ошибку.

 

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

 

Нагрузочное тестирование

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

 

Кластер серверов 1С состоял из одного центрального и двух рабочих серверов. Отдельно был поднят сервер лицензирования 1С: все клиентские и серверные лицензии вынесены на него. Кластер СУБД состоял из двух серверов: один – под мастер, другой – под реплику. Ресурсы на реплике — скромнее по сравнению с мастером.

 

СУБД Tantor Postgres для 1C была настроена согласно нашим рекомендациям. Для нагрузочных тестов были выбраны две конфигурации: Документооборот и ERP. Рассмотрим характеристики этих баз, профиль нагрузки и результаты тестов более подробно.

 

Нагрузочный тест Документооборот

Конфигурация – Документооборот 2.1, размер базы — 210 Гб. Эмулируется работа 1000 пользователей, длительность теста – 3 часа, за это время пользователи выполняют 80 тысяч ключевых операций.

Профиль нагрузки — смешанный:

  • 50% — открытие форм списков и документов, проведение документов, запись справочников;

  • 30% — формирование отчетов;

  • 20% — работа с обработками.

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

 

 

(Графики утилизации RAM и диска не приводим, т.к. они коррелируют с графиком CPU, и для демонстрации распределения нагрузки достаточно только графика по CPU)

Теперь настроим копию БД и запустим тест еще раз. Нагрузка распределится следующим образом.

Мастер:

 

Реплика:

 

Почему почти вся нагрузка ушла на реплику? Дело в том, что у всех отчетов на СКД по умолчанию стоит "Использование копий базы данных = Авто":

 

 

В этом случае платформа 1С будет все такие отчеты выполнять на работающих копиях БД при соблюдении требуемой актуальности данных. А для внешнего типа репликации платформа 1С считает, что данные в такой копии всегда актуальны. Поэтому все наши отчеты и выполнялись на реплике. И несмотря на то, что в профиле нагрузки только 30% операций были связаны с отчетами, получается, они в основном и нагружают СУБД в данном нагрузочном тесте.

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

Мастер:

 

Реплика:

В этом случае распределение нагрузки между серверами получилось более равномерное. По итогам нагрузочного теста APDEX при использовании копии БД стал лучше на 1%, т.е. был в пределах погрешности. Таким образом, способ разнесения нагрузки работает. Давайте теперь проверим, как он себя покажет на тесте ERP.

 

Нагрузочный тест ERP

Данный нагрузочный тест идет в комплекте типовой конфигурации ERP, и его можно скачать с сайта фирмы "1С".

Конфигурация – ERP2.5, размер базы — 1273 Гб. Эмулируется работа 2000 пользователей, длительность теста – 10 часов, т.е. эмулируем полноценный рабочий день. За это время пользователи выполняют 847 тысяч ключевых операций.

Профиль нагрузки — смешанный:

  • 60% — открытие форм списков и документов, проведение документов, запись справочников;

  • 5% — формирование отчетов;

  • 35% — работа с обработками, различные расчеты.

В этом тесте также запускается процедура закрытия месяца.

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

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

В отличие от теста на базе Документооборот, на этом тесте при использовании механизма копий БД мы столкнулись с несколькими проблемами в связи с более интенсивной OLTP-нагрузкой. Например, выполнение запроса на реплике приводило к ошибке:

2025-10-06 19:50:28.816 MSK [419706:280/127] [erp12k] 192.168.5.221(54070) [unknown] ERROR:  canceling statement due to lock timeout
2025-10-06 19:50:28.816 MSK [419706:280/127] [erp12k] 192.168.5.221(54070) [unknown] STATEMENT:  drop table if exists pg_temp.tt8 cascade;create temporary table tt8 (_Q_001_F_000RRef bytea, _Q_001_F_001RRef bytea, _Q_001_F_002_TYPE bytea, _Q_001_F_002_S mvarchar(200), _Q_001_F_002_RTRef bytea, _Q_001_F_002_RRRef bytea, _Q_001_F_003 mvarchar(256), _Q_001_F_004RRef bytea, _Q_001_F_005RRef bytea, _Q_001_F_006_TYPE bytea, _Q_001_F_006_RTRef bytea, _Q_001_F_006_RRRef bytea, _Q_001_F_007_00 bytea, _Q_001_F_008 mvarchar(32), _Q_001_F_009 mvarchar(32), _Q_001_F_010 mvarchar(256), _Q_001_F_011 boolean, _Q_001_F_012_TYPE bytea, _Q_001_F_012_RRRef bytea, _Q_001_F_013 boolean, _Q_001_F_014_00 bytea, _Q_001_F_014_01 numeric(1, 0), _Q_001_F_015 boolean, _Q_001_F_016 mvarchar, _Q_001_F_017 mvarchar, _Q_001_F_018 mvarchar, _Q_001_F_019 mvarchar, _Q_001_F_020 mvarchar, _Q_001_F_021 mvarchar, _Q_001_F_022 boolean, _Q_001_F_023 boolean, _Q_001_F_024 boolean, _Q_001_F_025 boolean, _Q_001_F_026 boolean, _Q_001_F_027 boolean, _Q_001_F_028_TYPE bytea, _Q_001_F_028_RTRef bytea, _Q_001_F_028_RRRef bytea, _Q_001_F_029_TYPE bytea, _Q_001_F_029_RTRef bytea, _Q_001_F_029_RRRef bytea, _Q_001_F_030_TYPE bytea, _Q_001_F_030_RTRef bytea, _Q_001_F_030_RRRef bytea, _Q_001_F_031_TYPE bytea, _Q_001_F_031_RTRef bytea, _Q_001_F_031_RRRef bytea, _Q_001_F_032_TYPE bytea, _Q_001_F_032_RTRef bytea, _Q_001_F_032_RRRef bytea, _Q_001_F_033_TYPE bytea, _Q_001_F_033_RTRef bytea, _Q_001_F_033_RRRef bytea, _Q_001_F_034RRef bytea, _Q_001_F_035RRef bytea, _Q_001_F_036 numeric(5, 0), _Q_001_F_037 timestamp, _Q_001_F_038 timestamp ) without oids
2025-10-06 19:50:28.818 MSK [419706:280/129] [erp12k] 192.168.5.221(54070) [unknown] WARNING:  there is no transaction in progress


Что получит пользователь при выполнении отчета, запрос которого привел к такой ошибке? Если в отчете стоит "Использование копий базы данных = Авто", отчет автоматически будет переформирован на мастере, и пользователь ничего не заметит. Если  "Использование копий базы данных = Использовать только копии", отчет сформирован не будет, и пользователю будет выведена ошибка.

При этом сама копия БД при возникновении ошибки выполнения запроса на реплике будет отключена:

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

После того, как возникшие ошибки были исправлены разработчиком СУБД, мы снова запустили тест, и он завершился успешно. Давайте посмотрим, как распределилась нагрузка.

Мастер:

Реплика:

По графикам видно, что в данном нагрузочном тесте нагрузка, создаваемая отчетами, не так велика, как в предыдущем тесте. Но было важно проверить, что при сильно возросшей OLTP-нагрузке механизм тоже будет работать корректно.

По итогам нагрузочного теста APDEX при использовании копии БД остался на том же уровне, как и без ее использования. То есть основная задача выполняется на отлично: нагрузка разносится без потери производительности.

 

Особенности использования копии БД

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

  1. Копия базы данных с типом репликации "Внешняя" всегда считается актуальной платформой 1С, но по факту реплика может получать данные от мастера с задержкой, и из-за этого при выполнении на мастере и реплике данные отчетов могут отличаться. В наших тестах задержка репликации была не более нескольких мегабайт, контролировать ее удобно с помощью раздела Репликация Платформы Tantor;
  2. По умолчанию во всех отчетах стоит режим, который будет использовать копию БД, и все эти отчеты на СКД будут выполняться на реплике. Но с учетом п.1 нужно обдуманно подходить к выбору отчетов, которые можно выполнять на реплике с учетом требуемой актуальности данных в отчетах;
  3. Если во время выполнения запроса на копии БД возникнет ошибка, то такая копия будет отключена, и выполнение запросов продолжится на мастере;
  4. Отчеты, в запросах которых используются метаданные, измененные в расширении (например, по таблице документа _document1293 создана таблица _document1293x1), не могут быть выполнены на копии БД. Это ограничение платформы 1С. Надеемся, это ограничение будет снято, т.к. для логической репликации (стандартный тип репликации механизма копий БД) оно, быть может, и имеет смысл, но для физический репликации (внешний вид репликации) – не имеет, поскольку DDL-команды создания новых таблиц успешно реплицируются механизмом потоковой репликации;
  5. В версии 8.3.27 появился новый метод платформы ПолучитьИнформациюОКопии(), который позволяет получить дополнительную информацию об используемой копии БД, например, ОшибкаПричиныОтключения. В ходе отладки механизма нагрузочными тестами нам это помогало быстро выяснить причину, по которой копия БД отключалась.

 

Заключение

Рассмотренный механизм действительно позволяет разносить нагрузку без каких-либо дополнительных накладных расходов, что дает возможность вместо вертикального масштабирования использовать горизонтальное и экономить ресурсы компании. Функциональность станет доступна в релизе Tantor Postgres 18. В ходе тестирования мы столкнулись и успешно решили несколько проблем, которые мешали механизму работать так, как показано выше в результатах нагрузочных тестов. При выпуске новых релизов мы всегда проводим целый ряд нагрузочных тестов на типовых конфигурациях 1С, чтобы убедиться, что производительность наших решений находится на высоком уровне и в логике работы СУБД нет ошибок. 

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

PostgreSQL горизонтальное масштабирование репликация Tantor Postgres производительность СУБД копии баз данных временные таблицы read-only реплика

См. также

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

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

18.02.2025    8837    ivanov660    39    

61

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

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

24.06.2024    11273    ivanov660    13    

64

Администрирование СУБД 1С:Предприятие 8 1C:Бухгалтерия Россия Бесплатно (free)

При хранении файлов в томах на диске они иногда исчезают. Разбираемся, почему.

23.05.2024    18031    human_new    22    

60

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

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

13.03.2024    8608    spyke    29    

54

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист 1С:Предприятие 8 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

5 стартмани

15.02.2024    20375    357    ZAOSTG    104    

125

Администрирование СУБД Системный администратор Программист Бесплатно (free)

Казалось бы, базовое знание: «индексы надо обслуживать, чтобы запросы выполнялись быстро». Но обслуживание индексов выполняется долго и может мешать работе пользователей. Кроме того, в последнее время популярны разговоры о том, что индексы можно вообще не обслуживать – насколько это оправданно? Рассмотрим: на что влияет обслуживание индексов, когда надо и когда не надо его выполнять, и если надо – как это сделать так, чтобы никому не помешать?

16.01.2024    27791    Филин    17    

59
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. paulwist 03.02.26 09:16 Сейчас в теме
Статья отличная!

Но, есть вопрос:

При этом на реплике могут быть выполнены не все запросы, а только те, которые удовлетворяют таким условиям:
...
Запрос выполняется вне транзакции;


Поясните, как запрос в БД (PG, MSSQL etr) может выполняться вне транзакции (можно репро-кодом)??
2. Tantor 179 03.02.26 11:58 Сейчас в теме
(1) Спасибо!
Я имел ввиду, что вне транзакции в 1С. Вот выдержка с ИТС:
Запрос не может быть исполнен на копии базы данных, если в момент исполнения запроса выполняется любое из следующих условий:

● В текущем сеансе имеется открытая транзакция.
3. paulwist 03.02.26 13:04 Сейчас в теме
(2)
Я имел ввиду


А-а-а, в этом смысле, тогда вопрос снимается, важное уточнение :)
Для отправки сообщения требуется регистрация/авторизация