Пятница, 16:40. В бухгалтерии — конец квартала. Двенадцать человек одновременно проводят документы реализации. Через минуту звонок: «1С зависла, документы не проводятся, на экране крутится колёсико». Ещё через три минуты — второй звонок. Через пять — массовый исход из 1С с перезапуском компьютеров.
Знакомая картина. В 90% таких случаев причина — блокировки. Не ошибка в коде, не перегрузка сервера, а конкурентный доступ к одним и тем же данным. Разберём, как это работает, как диагностировать и что с этим делать.
Два типа блокировок: управляемые и SQL
В 1С:Предприятии параллельно работают два механизма блокировок. Первый — управляемые блокировки платформы 1С (объектные, на уровне менеджера блокировок). Второй — блокировки SQL Server (СУБД-уровень).
Когда используется автоматический режим управления блокировками, платформа ставит блокировки на уровне SQL Server. Это грубые, табличные блокировки. Один документ может заблокировать всю таблицу регистра.
При управляемом режиме платформа использует собственный менеджер блокировок — более гранулярный. Блокируются конкретные записи, а не таблицы. Но и здесь есть подводные камни.
Как выглядит взаимоблокировка
Транзакция А захватила ресурс 1 и хочет ресурс 2. Транзакция Б захватила ресурс 2 и хочет ресурс 1. Обе ждут друг друга бесконечно. SQL Server обнаруживает deadlock через несколько секунд и принудительно откатывает одну из транзакций — «жертву». Пользователь видит ошибку: «Конфликт блокировок при выполнении транзакции».
В технологическом журнале 1С это событие TDEADLOCK. В SQL Server — можно поймать через Extended Events или трассировку deadlock graph.
Пять главных причин
Повышение уровня блокировки внутри транзакции. Типичный сценарий: транзакция читает данные (shared lock), затем хочет их изменить (exclusive lock). Если две транзакции делают это одновременно — deadlock. Решение: сразу захватывать exclusive lock через БлокировкаДанных в начале транзакции.
Захват ресурсов в разном порядке. Документ «Реализация» сначала пишет в регистр «Продажи», потом в «Взаиморасчёты». Документ «Оплата» — наоборот. При одновременном проведении — deadlock. Решение: унифицировать порядок записи в регистры.
Долгие транзакции. Чем дольше транзакция держит блокировку, тем выше вероятность конфликта. Мы видели транзакцию при проведении документа, которая выполнялась 45 секунд из-за запроса в цикле. После оптимизации запроса — 0.3 секунды. Блокировки исчезли.
Эскалация блокировок SQL Server. Когда количество заблокированных строк превышает порог (обычно ~5000), SQL Server эскалирует блокировку на всю таблицу. Один документ с 6000 строками блокирует таблицу для всех.
Неоптимальные запросы. Запрос без подходящего индекса сканирует всю таблицу, блокируя каждую прочитанную строку. Добавление индекса может сократить количество блокировок с тысяч до единиц.
На одном проекте мы столкнулись с ситуацией, когда блокировки возникали только по пятницам. Причина оказалась прозаичной: по пятницам запускался отчёт «Дебиторская задолженность» по всем контрагентам, который читал данные из регистра взаиморасчётов 40 секунд. В это же время менеджеры проводили оплаты, которые писали в тот же регистр. Shared lock от отчёта конфликтовал с exclusive lock от проведения. Решение: вынесли формирование отчёта на реплику базы (всё равно данные нужны были за вчерашний день). Блокировки исчезли.
Другой типичный сценарий — фоновые задания. Регламентное задание пересчитывает себестоимость в фоне, блокируя регистры на минуты. Пользователи в это время не могут провести документы. Расписание фоновых заданий нужно согласовывать с пиковой нагрузкой — запускать пересчёты ночью или в обеденный перерыв.
Диагностика: технологический журнал
Главный инструмент — технологический журнал 1С. Для ловли блокировок нужны события TLOCK, TTIMEOUT, TDEADLOCK.
Минимальная настройка logcfg.xml:
<log location="C:\1C_Logs\" history="4">
<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>
TLOCK — факт установки блокировки. TTIMEOUT — таймаут ожидания (пользователь ждал и не дождался). TDEADLOCK — взаимоблокировка. В реальности достаточно мониторить TTIMEOUT и TDEADLOCK — это проблемные ситуации.
Ключевые поля в записи: WaitConnections — кто кого ждёт, Regions — какие данные заблокированы, Context — в каком месте кода произошла блокировка.
Кейс: дедлок HTTP-сервиса при деплое
Реальная история из проекта для торговой сети. Настроили CI/CD: пайплайн обновляет конфигурацию 1С автоматически. Для этого нужно заблокировать базу и отключить пользователей. Реализовали через HTTP-сервис внутри самой 1С: пайплайн отправляет POST-запрос, HTTP-сервис ставит блокировку базы.
Проблема проявилась через неделю. Пайплайн отправляет запрос на блокировку базы. HTTP-сервис получает запрос, ставит блокировку. Но HTTP-сервис сам работает через сеанс 1С — а значит, его обрабатывает планировщик заданий платформы. Планировщик при установленной блокировке не может создать новый сеанс. Возникает deadlock: блокировка базы установлена, но команду на снятие блокировки выполнить некому.
Решение оказалось элегантным: отказались от HTTP-сервиса в пользу утилиты rac.exe. Она обращается напрямую к менеджеру кластера 1С через RAS (порт 1545), минуя планировщик заданий. Дедлок невозможен.
# Блокировка сеансов через rac
rac session list --cluster=$CLUSTER --infobase=$IB \
| grep session-id | awk '{print $NF}' \
| xargs -I {} rac session terminate --cluster=$CLUSTER \
--session={} --infobase=$IB
Управляемые блокировки: ловушка без транзакции
Распространённая ошибка: разработчик ставит управляемую блокировку БлокировкаДанных, но забывает обернуть код в явную транзакцию. Что происходит: блокировка фактически не работает. Платформа 1С не выбрасывает ошибку — код выполняется, но без реальной защиты от конкурентного доступа.
// НЕПРАВИЛЬНО — блокировка без транзакции
Блокировка = Новый БлокировкаДанных;
Элемент = Блокировка.Добавить("Справочник.Номенклатура");
Элемент.УстановитьЗначение("Ссылка", НоменклатураСсылка);
Блокировка.Заблокировать(); // не работает!
// ... операции ...
// ПРАВИЛЬНО
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
Элемент = Блокировка.Добавить("Справочник.Номенклатура");
Элемент.УстановитьЗначение("Ссылка", НоменклатураСсылка);
Блокировка.Заблокировать();
// ... операции ...
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
В одном проекте из-за этой ошибки генерация промокодов выдавала дубли. Блокировка от дублей стояла — но без транзакции она была декоративной. Под нагрузкой два запроса одновременно генерировали одинаковый код.
Эскалация блокировок: невидимый враг
SQL Server начинает с блокировки отдельных строк. Когда количество заблокированных строк в одной таблице превышает порог, происходит эскалация — блокируется вся таблица. Порог зависит от версии SQL Server, но обычно это около 5000 строк.
Как это выглядит на практике. Документ «Инвентаризация» с 6000 строками проводится. SQL Server блокирует строки одну за одной, доходит до порога и эскалирует блокировку на всю таблицу регистра. Все пользователи, работающие с этим регистром, встают в очередь.
Что делать:
- Разбивать документы с большим количеством строк на порции (если бизнес-логика позволяет)
- Отключить эскалацию для конкретных таблиц:
ALTER TABLE ... SET (LOCK_ESCALATION = DISABLE)— но осторожно, это увеличивает потребление памяти на блокировки - Оптимизировать длительность транзакции — чем быстрее она завершится, тем меньше строк окажется заблокировано одновременно
RCSI: как убрать блокировки при чтении
Read Committed Snapshot Isolation (RCSI) — режим работы SQL Server, при котором читающие запросы не ставят shared-блокировки. Вместо этого SQL Server использует версионирование строк: читатель получает последнюю зафиксированную версию данных из TempDB, а не ждёт, пока писатель завершит транзакцию.
Для 1С это означает, что отчёт, формирующийся 30 секунд, больше не блокирует проведение документов. И наоборот — массовое проведение документов не мешает формированию отчётов. Читатели не мешают писателям, писатели не мешают читателям.
Включение RCSI:
ALTER DATABASE [your_1c_db] SET READ_COMMITTED_SNAPSHOT ON;
Важно: для выполнения этой команды нужен монопольный доступ к базе. SQL Server ждёт, пока все транзакции завершатся, затем переключает режим. Планируйте на нерабочее время.
Побочный эффект: возрастает нагрузка на TempDB — туда складываются версии строк. Если TempDB на медленном диске или неправильно настроена (1 файл, процентный autogrow) — эффект может быть обратным. Поэтому сначала настройте TempDB (см. нашу статью о настройке SQL Server), затем включайте RCSI.
В одном проекте для торговой сети RCSI убрал 80% жалоб на «зависания» 1С. Кассиры пробивали чеки, а бухгалтерия формировала реестр продаж — раньше они друг друга блокировали, после RCSI работают параллельно.
Есть нюанс: RCSI не спасает от deadlock между двумя писателями. Если две транзакции одновременно пишут в одну и ту же запись — блокировка всё равно будет. Но количество конфликтов сокращается драматически, потому что основная масса блокировок в 1С — именно «читатель ждёт писателя».
Мониторинг блокировок в реальном времени
Ждать жалоб пользователей — плохая стратегия. Настройте мониторинг, который покажет блокировки до того, как они станут проблемой.
Базовый запрос для отслеживания текущих блокировок в SQL Server:
SELECT
r.session_id,
r.blocking_session_id,
r.wait_type,
r.wait_time / 1000 AS wait_sec,
t.text AS query_text,
r.status
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id > 0
ORDER BY r.wait_time DESC;
Этот запрос показывает все сеансы, которые прямо сейчас кого-то ждут: кто ждёт, кого ждёт, как долго, какой запрос выполняет. Настройте SQL Agent Job, который выполняет этот запрос каждые 30 секунд и записывает результат в служебную таблицу — получите историю блокировок с детальностью 30 секунд.
Ещё один полезный инструмент — Extended Events. Настройте сессию, которая ловит события blocked_process_report при ожидании дольше 5 секунд:
-- Порог блокировки для отчёта (в секундах)
EXEC sp_configure 'blocked process threshold', 5;
RECONFIGURE;
После этого SQL Server будет генерировать событие каждый раз, когда какой-то процесс ждёт дольше 5 секунд. Вы увидите проблему не после звонка бухгалтерии, а в момент возникновения.
Чек-лист: что делать при жалобах на «1С зависла»
- Открыть консоль администрирования (rac session list) — посмотреть, кто кого блокирует
- Включить ТЖ с событиями TLOCK, TTIMEOUT, TDEADLOCK — собрать данные за 30-60 минут
- Проанализировать WaitConnections — определить, какие операции конфликтуют
- Посмотреть Context — найти конкретное место в коде
- Проверить длительность транзакций — долгие транзакции = частые блокировки
- Проверить наличие индексов для запросов внутри транзакций
- Проверить режим управления блокировками (управляемый vs автоматический)
Блокировки — не баг, а штатный механизм. Проблема возникает, когда они длятся слишком долго или захватывают слишком много ресурсов. Системная диагностика через ТЖ и rac даёт конкретные ответы вместо догадок.


