Кто блокирует базу 1С: найти виновника сейчас и восстановить, кто держал ночью
Иван Недомолков · Chop etilgan:
Когда база встаёт, вопрос всегда один и тот же: кто её держит. У вопроса два времени, и отвечают на них по-разному. “Кто блокирует прямо сейчас” - смотрится живым снимком за пять минут. “Кто держал базу ночью, когда встал обмен” - живым снимком не смотрится вообще: к утру от ночного замка не осталось следов.
Разберём оба. Сначала три способа снять текущий снимок, у каждого своя слепая зона. Потом - что делать со вторым вопросом, потому что в реальных разборах он встречается чаще первого.
Способ 1: консоль кластера
Откройте консоль администрирования кластера, список сеансов базы. Отсортируйте по колонке ожиданий и найдите сеансы, у которых заполнен номер блокирующего сеанса. Дальше по этому номеру находится строка держателя: пользователь, компьютер, приложение.
Слепых зон две. Первая: консоль показывает момент, а конфликт короткий - пока вы дошли до нужной колонки, картинка сменилась. Вторая: платформа различает блокировку на стороне СУБД и блокировку своего сервиса управляемых блокировок, и это два разных поля. Сеанс, чистый по одному полю, может стоять в очереди по второму. Смотреть надо оба.
Способ 2: rac из командной строки
То же самое без мыши, годится для скрипта и для сервера без графики:
rac session list --cluster=<uuid кластера> --infobase=<uuid базы>
В выводе по каждому сеансу есть поля blocked-by-dbms и blocked-by-ls - номер сеанса, который держит этот на уровне СУБД и на уровне сервиса блокировок. Ноль означает, что сеанс никто не держит. Ненулевое значение - номер держателя, и его строка в том же выводе даёт user-name, host и app-id.
Одна тонкость, которая стоит получаса: rac должен быть той же версии, что и работающий агент кластера. После обновлений платформы на сервере обычно живёт несколько версий, и запуск свежего rac против старого агента отвечает ошибкой про различие версий клиента и сервера. Берите rac.exe из каталога той платформы, чей агент запущен.
Способ 3: спросить саму СУБД
Когда конфликт сидит на уровне SQL Server, быстрее всего его видно оттуда:
SELECT r.session_id AS жертва,
r.blocking_session_id AS держатель,
r.wait_type,
r.wait_time / 1000 AS ждёт_сек,
s.login_name, s.host_name, s.program_name
FROM sys.dm_exec_requests AS r
JOIN sys.dm_exec_sessions AS s
ON s.session_id = r.blocking_session_id
WHERE r.blocking_session_id <> 0
ORDER BY r.wait_time DESC;
Запрос отдаёт пары жертва-держатель с именем логина и машины держателя. Для серверной базы 1С логин будет техническим, и от него ещё предстоит дойти до сеанса платформы - по номеру соединения из консоли кластера. Зато этот путь видит и то, что платформенным приборам недоступно: чужие процессы на том же сервере, обслуживание, репликацию.
У способа есть и своя слепая зона, противоположная блокировкам: сеанс, который ничего не ждёт и никого не держит, но сидит со спящей открытой транзакцией. В список ожиданий он не попадает по построению - никто никого не ждёт. При этом он останавливает усечение журнала и версионного хранилища. Такие сеансы ищутся отдельным запросом по соединению sys.dm_exec_sessions с sys.dm_tran_session_transactions со статусом sleeping - подробный разбор одного такого случая, где спящую транзакцию четверо суток держал сам мониторинг, есть в статье про четыре способа, которыми диагностика врёт.
Почему снимок почти всегда опаздывает
Теперь честно про главное ограничение всех трёх способов. Пока проблема воспроизводится у вас на глазах, любой из них называет держателя за минуту. Но жалоба почти никогда не приходит в момент проблемы. “Вчера с обеда всё висело”. “Ночью не прошёл обмен”. “Утром касса стояла десять минут”. К этому моменту замок давно отпущен, сеанс закрыт, и снимок текущего состояния показывает идеальную базу.
Ответ на вопрос в прошедшем времени требует истории: кто-то должен был снимать состояние сеансов регулярно и сохранять снимки. Причём сохранять обе стороны конфликта. Если в снимок попадают только ждущие сеансы, утром вы увидите список пострадавших и ни одного виновника - номер держателя без его строки останется номером.
Собрать такую историю можно по-разному: складывать вывод rac в файлы по расписанию, писать выборку из СУБД в служебную таблицу, поднять внешний мониторинг. Рабочий минимум - периодичность в несколько минут, хранение держателя вместе с жертвами и ротация, чтобы история не съела диск.
История без внешнего стека
Если внешнего мониторинга нет и заводить его ради одного вопроса не хочется, есть штатный путь: с версии 8.3.14 платформа отдаёт состояние кластера из встроенного языка, объектом администрирования сервера. Оттуда видно всё то же, что в консоли: сеансы, соединения, вызовы, память, блокирующие номера. Регламентное задание раз в несколько минут снимает состояние, складывает снимок, форма потом отвечает на вопрос “кто держал базу в этот период” готовой диаграммой по держателям.
Мы собрали этот контур в обработку Анализ нагрузки кластера 1С: кто блокировал базу, кто грузил сервер. Она работает в любой конфигурации, потому что к прикладным объектам не обращается вовсе: определяет свою базу и кластер сама, пишет историю регламентным заданием и отвечает на вопросы списком - кто блокировал, кто грузил процессор, кто ел память, что было ночью. Ответ выглядит как полосы по людям за период, а самая длинная полоса и есть тот, кого вы ищете. Со стороны SQL Server ту же историю пишет Чёрный ящик SQL Server под 1С: блокировки, tempdb и долгие транзакции раз в минуту, с именем пользователя 1С у соединения, и снимки переживают перезагрузку сервера.
Два предупреждения из опыта её внедрения пригодятся и тем, кто соберёт такой сбор сам. На кластере из нескольких рабочих серверов файловая история обязана лежать в сетевом каталоге, доступном всем узлам: регламентное задание выполняется на свободном узле, и локальные каталоги двух машин молча копят две разные половины истории. И настройки сбора должны читаться из места, которое видно и интерактивному пользователю, и служебной учётке регламентного задания, иначе форма настроена, а сбор работает по умолчаниям.
Держатель найден - что дальше
Имя держателя - это середина разбора, дальше вопрос “почему он держит”. Типовые продолжения такие.
Держит длинная транзакция отчёта или обработки - смотрите разбор длинных транзакций: там про то, как найти долгие транзакции и что в них обычно сидит.
Держат друг друга два потока проведения, и в журнале появляются взаимоблокировки - это отдельный жанр, и разбирать один случай там почти бесполезно: работает подсчёт частот по накопленным отчётам о дедлоках.
А если виновника по прибору видно, но данные при этом ведут себя так, будто блокировок нет вовсе - проверьте, ставятся ли ваши замки вообще: управляемая блокировка умеет не ставиться молча, и код при этом выглядит правильным.
Если базу держат регулярно, а разбираться некому - напишите нам. Поставим сбор истории, разберём накопленное и назовём виновников поимённо, начинаем с экспресс-аудита.