Как устранить ошибку конфликта блокировок при выгрузке изменений РИБ на сервере MS SQL?

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

При выполнении распределенной синхронизации данных (РИБ) в клиент-серверном варианте работы на базе MS SQL Server разработчики и системные администраторы нередко сталкиваются с ошибкой: «Ошибка при вызове метода контекста (ЗаписатьИзменения): Конфликт блокировок при выполнении транзакции: Превышено максимальное время ожидания предоставления блокировки». При этом чтение входящего файла обмена может проходить успешно, а в файловом варианте информационной базы та же процедура отрабатывает без сбоев.

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

Причины возникновения таймаута блокировок при записи изменений

Проанализируем механику работы метода ЗаписатьИзменения(). В момент формирования исходящего сообщения обмена платформа 1С накладывает блокировки на таблицы регистрации изменений (в СУБД они имеют префикс _ChangeRec*) и считывает накопленные данные для выбранного узла. Ошибка ожидания блокировки возникает в следующих случаях:

  1. Нестабильность или ошибки конкретного релиза платформы 1С: В некоторых версиях платформы (например, в ветке 8.3.9) присутствовали внутренние ошибки управления блокировками и транзакциями при работе с СУБД, вызывающие зависание сеансов или бесконечные ожидания.
  2. Неоптимальные планы запросов и устаревшая статистика СУБД: Таблицы регистрации изменений подвержены регулярным массовым вставкам и очисткам. Без актуальной статистики оптимизатор MS SQL Server переходит от точечного поиска по индексам к полному сканированию таблиц (Table/Index Scan), что приводит к эскалации блокировок со строк на страницы или всю таблицу целиком.
  3. Некорректная настройка параллелизма (MAXDOP) в MS SQL Server: Если для сервера СУБД параметр параллелизма не ограничен единицей, параллельные потоки одного сложного запроса блокируют друг друга (ожидания CXPACKET и Latch), вызывая срыв транзакции по таймауту.
  4. Автоматический режим управления блокировками: Если конфигурация или план обмена используют автоматические блокировки, СУБД удерживает разделяемые блокировки (S-блокировки) до конца транзакции, блокируя параллельные процессы записи.
  5. Огромный объем накопленных изменений: Попытка выгрузить сотни тысяч объектов в рамках одной неделимой транзакции превышает системный таймаут ожидания блокировки (по умолчанию 20 секунд).

Шаг 1. Проверка и обновление версии платформы «1С:Предприятие»

Рассмотрим первое действие, которое часто решает проблему без перенастройки конфигурации. Если на сервере установлена устаревшая платформа с известными багами управления транзакциями (в частности, релизы 8.3.9.хххх):

  1. Выполним резервное копирование информационной базы.
  2. Обновим платформу «1С:Предприятие» на актуальный стабильный релиз ветки 8.3.10 или выше (вплоть до актуальных релизов 8.3.22–8.3.25).
  3. Обновим компоненты сервера 1С и клиентские приложения на всех рабочих станциях.
  4. Проверим повторный запуск выгрузки РИБ.

Шаг 2. Обслуживание таблиц регистрации изменений в MS SQL Server

Разберем регламентные операции на стороне СУБД, позволяющие устранить неоптимальные планы выполнения запросов:

  1. Обновление статистики с полным сканированием: Для всех системных таблиц планов обмена необходимо выполнить обновление статистических данных:
    
    EXEC sp_updatestats;
    -- Или точечно для конкретных таблиц регистрации
    UPDATE STATISTICS _ChangeRecXXXX WITH FULLSCAN;
    
  2. Дефрагментация и перестроение индексов: Регулярное перестроение индексов (Index Rebuild / Reorganize) устраняет фрагментацию таблиц регистрации изменений.
  3. Настройка параметра MAXDOP: Установим в свойствах экземпляра MS SQL Server параметр Max Degree of Parallelism = 1, чтобы исключить паразитные взаимные ожидания потоков в запросах 1С.
  4. Настройка шага авторасширения файлов: Убедимся, что для базы данных и TempDB шаг авторасширения задан в мегабайтах (например, 256–512 МБ), а учетной записи службы SQL Server предоставлены права мгновенной инициализации файлов (Instant File Initialization).

Шаг 3. Диагностика конфликтов через Технологический журнал и DMV

Если обновление платформы и обслуживание СУБД не дали мгновенного результата, выясним точного «виновника» блокировки. Для этого настроим сбор событий технологического журнала 1С.

Создадим файл конфигурации logcfg.xml в каталоге настроек сервера 1С:


<config xmlns="http://v8.1c.ru/v8/tech-log">
    <log location="C:\LOGS\1C_LOCKS" history="24">
        <event>
            <eq property="name" value="TLOCK"/>
        </event>
        <event>
            <eq property="name" value="TTIMEOUT"/>
        </event>
        <event>
            <eq property="name" value="TDEADLOCK"/>
        </event>
        <property name="all"/>
    </log>
</config>

В момент повторения ошибки в логах событий TTIMEOUT и TLOCK найдем поля WaitConnections и Context. Это укажет на номер сеанса, исполняемый контекст кода и таблицу, удерживающую ресурс.

Параллельно в MS SQL Server выполним запрос к динамическим представлениям (DMV) для просмотра дерева блокировок в реальном времени:


SELECT 
    r.session_id AS BlockedSession,
    r.blocking_session_id AS BlockingSession,
    r.wait_type,
    r.wait_time,
    t.text AS SQLText
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id <> 0;

Шаг 4. Очистка неактуальной регистрации и порционная выгрузка

Посмотрим на программные методы обхода длительных блокировок в самой конфигурации 1С:

  1. Удаление устаревшей регистрации: Если узел долго не выходил на связь, накопившийся объем изменений очистим с помощью встроенных инструментов или программно: ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена);
  2. Перевод конфигурации на управляемые блокировки: В свойствах конфигурации и плана обмена установим режим Управляемый вместо Автоматический, что избавит от избыточных разделяемых блокировок страниц на уровне SQL Server.
  3. Выгрузка данных небольшими транзакциями: Вместо монолитного вызова ПланыОбмена.ЗаписатьИзменения() применим поэтапную выгрузку через ПланыОбмена.ВыбратьИзменения() с порционной фиксацией транзакций.

Рассмотрим пример порционной обработки данных:


ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелОбмена, НомерСообщения);
Счетчик = 0;
РазмерПорции = 100;

НачатьТранзакцию();
Пока ВыборкаИзменений.Следующий() Цикл
    Объект = ВыборкаИзменений.Получить();
    // Сериализация и запись объекта в поток сообщения
    ЗаписатьXML(ЗаписьXML, Объект);
    
    Счетчик = Счетчик + 1;
    Если Счетчик % РазмерПорции = 0 Тогда
        ЗафиксироватьТранзакцию();
        НачатьТранзакцию();
    КонецЕсли;
КонецЦикла;

Если ТранзакцияАктивна() Тогда
    ЗафиксироватьТранзакцию();
КонецЕсли;

Такой подход гарантирует минимальное время удержания транзакционных замков в базе данных и полностью предотвращает возникновение ошибок таймаута блокировок.

← На главную