Как настроить одновременный запуск фоновых заданий на одном сервере кластера и избежать блокировок

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При проектировании высоконагруженных систем на платформе 1С:Предприятие 8 часто возникает необходимость параллельной обработки данных. Многопоточность позволяет существенно сократить время выполнения тяжелых регламентных операций, распределяя нагрузку между фоновыми заданиями. Однако при этом разработчики и системные администраторы сталкиваются с рядом сложных вопросов: как гарантировать, что все потоки будут выполняться на определенном сервере кластера, как организовать бесконфликтное логирование и как избежать взаимоблокировок в СУБД. Рассмотрим подробно решение этих задач.

1. Привязка фоновых заданий к конкретному рабочему серверу кластера

По умолчанию кластер серверов 1С распределяет нагрузку динамически. Фоновые задания запускаются на тех рабочих серверах, которые в данный момент наименее нагружены. Если нам необходимо жестко привязать выполнение определенных фоновых заданий к конкретному физическому или виртуальному серверу (например, к выделенному серверу для тяжелых расчетов с именем SRV_JOBS), мы должны использовать механизм требований назначения функциональности.

Разберем по шагам процесс настройки в консоли администрирования кластера серверов:

  1. Откроем консоль администрирования кластера и перейдем в ветку рабочего сервера, на котором должны выполняться фоновые задания (например, SRV_JOBS).
  2. В контекстном меню сервера выберем пункт создания нового требования назначения функциональности.
  3. Зададим параметры для первого правила:
    • Объект требования: Клиентское соединение с ИБ
    • Тип требования: Назначать
    • Дополнительный параметр: BackgroundJob.CommonModule (это правило привяжет фоновые задания, запущенные программно из общих модулей).
  4. Создадим второе аналогичное правило для регламентных заданий, запускаемых по расписанию:
    • Объект требования: Клиентское соединение с ИБ
    • Тип требования: Назначать
    • Дополнительный параметр: BackgroundJob.ScheduledJob.
  5. Для всех остальных серверов в кластере необходимо создать противоположные правила. Для этих же объектов требований и дополнительных параметров установим тип требования "Не назначать".
  6. Применим требования назначения функциональности через свойства кластера.

Важное архитектурное исключение: Платформа 1С использует так называемые системные фоновые задания (например, для компиляции модулей или формирования контекста базы данных при запуске новых процессов rphost). Они имеют внутренний идентификатор SystemBackgroundJob. На них созданные нами требования назначения функциональности не распространяются, и они могут запускаться на любом сервере кластера, где активен рабочий процесс.

2. Особенности выполнения фоновых заданий в файловом режиме

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

Тем не менее, важно понимать ограничение файлового режима: настоящая параллельность в нем отсутствует. Если ваше приложение инициирует запуск нескольких фоновых заданий одновременно, они будут помещены в очередь и выполнены строго последовательно. Настоящая многопоточность доступна исключительно в клиент-серверном варианте работы под управлением СУБД (MS SQL Server, PostgreSQL, IBM DB2, Oracle Database).

3. Организация логирования при многопоточности

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

Выясним особенности работы с различными механизмами логирования:

Вариант А: Использование Журнала регистрации (ЖР)
Метод ЗаписьЖурналаРегистрации() является потокобезопасным на уровне платформы. Однако производительность напрямую зависит от формата вашего ЖР:

Вариант Б: Запись в текстовые файлы логов
Попытка прямой записи из разных потоков в один и тот же текстовый файл на диске приведет к ошибке совместного доступа (файл будет заблокирован первым открывшим его потоком). Для обхода этой проблемы применим эффективную стратегию индивидуальных логов:

  1. При запуске каждого фонового задания сгенерируем уникальный идентификатор (GUID).
  2. Каждое фоновое задание записывает лог в свой персональный файл, например log_e9a12b3c...txt.
  3. После завершения работы всех потоков мастер-процесс считывает данные из всех персональных файлов, объединяет их в единый файл лога по хронологии и удаляет временные файлы потоков.

Вариант В: Логирование через независимый регистр сведений
Этот способ является наиболее гибким. Мы создаем независимый регистр сведений (например, ЛогФоновыхЗаданий). Важно спроектировать структуру его ключевых полей так, чтобы исключить блокировки при одновременной записи. Ключевыми полями должны выступать ИдентификаторЗадачи (уникальный GUID потока) и Период (или НомерСтрокиЛога).

4. Предотвращение блокировок СУБД при параллельной обработке

Основная сложность при многопоточной модификации данных в 1С — это транзакционные блокировки и взаимоблокировки (deadlocks) в СУБД. Если два параллельных потока попытаются обновить пересекающиеся наборы данных, один из них будет ожидать освобождения ресурсов, а при худшем сценарии СУБД аварийно завершит одну из транзакций.

Чтобы избежать этих проблем, применим следующие архитектурные подходы:

Принцип строгого секционирования данных:
Перед запуском потоков разделим весь объем обрабатываемых данных на непересекающиеся порции. Например, по диапазонам уникальных идентификаторов, по кодам филиалов или с помощью деления числовых ID записей по модулю (остаток от деления на количество потоков). Каждый поток должен работать исключительно со своим сегментом данных и не обращаться к чужим.

Использование управляемых блокировок:
В коде фонового задания перед выполнением запросов и записью объектов необходимо накладывать явную управляемую блокировку данных с помощью объекта БлокировкаДанных. Блокировать нужно строго те элементы, которые принадлежат текущему потоку. Это предотвратит эскалацию блокировок СУБД (когда блокируется вся таблица целиком вместо конкретных строк).

Рассмотрим пример кода установки управляемой блокировки в обработчике фонового задания:


Процедура ВыполнитьОбработкуПорции(ПараметрыПотока) Экспорт
    
    ИдентификаторПотока = ПараметрыПотока.ИдентификаторПотока;
    СписокОбъектов = ПараметрыПотока.СписокОбъектов;
    
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ОчередьОбработки");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.ИсточникДанных = СписокОбъектов;
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "Ссылка");
    
    НачатьТранзакцию();
    Попытка
        Блокировка.Заблокировать();
        
        // Здесь выполняется чтение и модификация выделенной порции данных
        // ...
        
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ЗаписатьЛогОшибки(ИнформацияОбОшибке());
        ВызватьИсключение;
    КонецПопытки;
    
КонецПроцедуры

Разделение итогов регистров:
Если ваши фоновые задания записывают движения по регистрам накопления или регистрам бухгалтерии, обязательно включите свойство "Разделение итогов" для этих регистров в конфигураторе. Данная опция позволяет разным транзакциям одновременно проводить документы и делать записи по одним и тем же аналитическим разрезам (измерениям), физически записывая промежуточные итоги в разные строки СУБД. Платформа автоматически объединит их при получении остатков.

5. Использование механизмов БСП для управления потоками

Вместо использования низкоуровневого метода платформы ФоновыеЗадания.Выполнить() крайне рекомендуется задействовать программный интерфейс Библиотеки стандартных подсистем (БСП), а именно общий модуль ДлительныеОперации. Он предоставляет разработчику готовый, проверенный временем каркас для организации параллельных вычислений.

Использование БСП дает следующие преимущества:

Посмотрим на пример организации многопоточного запуска с использованием БСП:


Процедура ЗапуститьПараллельнуюОбработку(МассивПорцийДанных)
    
    МассивЗаданий = Новый Массив;
    
    // Запуск потоков фоновых заданий
    Для Каждого Порция Из МассивПорцийДанных Цикл
        
        ПараметрыВыполнения = Новый Структура;
        ПараметрыВыполнения.Вставить("ПорцияДанных", Порция);
        
        НаименованиеЗадания = "Параллельный поток обработки данных";
        
        Задание = ДлительныеОперации.ЗапуститьВыполнениеВФоне(
            Неопределено, 
            "ОбщийМодульСервер.ВыполнитьОбработкуПорции", 
            ПараметрыВыполнения, 
            НаименованиеЗадания
        );
        
        МассивЗаданий.Добавить(Задание);
        
    КонецЦикла;
    
    // Ожидание завершения всех запущенных фоновых заданий
    ПараметрыОжидания = ДлительныеОперации.ПараметрыОжиданияВыполнения();
    ПараметрыОжидания.ИнтервалПовтора = 2; // Опрашивать раз в 2 секунды
    ПараметрыОжидания.ВызыватьИсключение = Ложь;
    
    РезультатыВыполнения = ДлительныеОперации.ОжидатьВыполнение(МассивЗаданий, ПараметрыОжидания);
    
    // Анализ результатов выполнения
    Для Каждого Результат Из РезультатыВыполнения Цикл
        Если Результат.Статус = "Выполнено" Тогда
            // Обработка успешного завершения потока
        ИначеЕсли Результат.Статус = "Ошибка" Тогда
            // Запись информации об ошибке конкретного потока
            ЗаписьЖурналаРегистрации("МногопоточнаяОбработка.ОшибкаПотока",,,, Результат.КраткоеПредставлениеОшибки);
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Применение рассмотренных архитектурных шаблонов настройки кластера, логирования и управления блокировками позволяет построить высокоэффективную, отказоустойчивую и масштабируемую систему параллельной обработки данных в среде 1С:Предприятие 8.

← На главную