При работе с базами данных 1С:Предприятие, развернутыми на СУБД Microsoft SQL Server, администраторы и разработчики часто сталкиваются с ситуацией, когда пользователи не могут войти в информационную базу. При этом система выдает критическую ошибку СУБД: Microsoft SQL Server Native Client 11.0: The transaction log for database 'Base_Name' is full due to 'LOG_BACKUP'. Эта ошибка означает, что файл лога транзакций (LDF) базы данных переполнен, и SQL Server заблокировал любые операции записи в базу до тех пор, пока не будет выполнен бэкап этого лога.
Попытки быстро решить проблему стандартными средствами СУБД (например, через попытку сжатия файла лога транзакций или перевода базы данных в простую модель восстановления Simple) часто натыкаются на еще одну неприятную ошибку: «Backup, file manipulation operations (such as ALTER DATABASE ADD FILE) and encryption changes on a database must be serialized. Reissue the statement after the current backup or file manipulation operation is completed» (Microsoft SQL Server, Error: 3023).
В этой статье мы подробно разберем, почему возникают эти взаимосвязанные ошибки, как безопасно вывести базу из этого состояния без жесткого перезапуска всего сервера, а также рассмотрим долгосрочные методы предотвращения подобных ситуаций.
Для начала проанализируем природу ошибки 3023. Ее текст прямо говорит о том, что операции резервного копирования и манипуляции с файлами базы данных должны выполняться последовательно (сериализованно). SQL Server накладывает жесткие внутренние блокировки при выполнении определенных процессов. Мы не можем одновременно выполнять:
BACKUP DATABASE);BACKUP LOG);ALTER DATABASE ADD/REMOVE FILE);DBCC SHRINKFILE или DBCC SHRINKDATABASE);FULL в SIMPLE).В ситуации, с которой столкнулся автор темы на форуме, в фоновом режиме СУБД уже выполнялся (или завис) процесс резервного копирования лога транзакций. Поскольку лог-файл был физически переполнен, этот процесс бэкапа либо не мог завершиться из-за нехватки места, либо заблокировал сам себя. Любая последующая попытка администратора перевести базу в модель восстановления Simple или выполнить сжатие лога вручную вызывала ошибку 3023, так как СУБД ожидала завершения текущей фоновой операции бэкапа.
В ходе обсуждения на форуме автор применил радикальный метод — перезапуск службы Microsoft SQL Server с помощью командной строки:
net stop mssqlserver
net start mssqlserver
Рассмотрим, почему этот метод сработал и какие риски он в себе несет. Принудительная остановка службы СУБД сбрасывает все активные фоновые процессы, включая зависший бэкап лога транзакций. После запуска службы база переходит в состояние восстановления (In Recovery), SQL Server накатывает незавершенные транзакции и откатывает те, что не были зафиксированы. После этого блокировка фонового бэкапа снимается, что позволяет на короткое время войти в базу и выполнить административные действия.
Внимание! Использовать этот метод на "живой" рабочей базе крайне не рекомендуется по следующим причинам:
Вместо перезапуска всего сервера СУБД мы можем точечно выявить зависший процесс бэкапа и остановить только его. Давайте разберем этот процесс по шагам.
Шаг 1. Выявим идентификатор сессии (SPID), которая выполняет блокирующую операцию резервного копирования. Для этого запустим следующий SQL-запрос в SQL Server Management Studio (SSMS):
SELECT
r.session_id AS [SPID],
r.command,
t.text AS [Query],
r.start_time,
r.percent_complete,
DATEADD(second, r.estimated_completion_time/1000, GETDATE()) AS [Estimated_Completion_Time]
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.command IN ('BACKUP DATABASE', 'BACKUP LOG', 'RESTORE DATABASE', 'RESTORE LOG');
Этот запрос вернет список всех текущих процессов резервного копирования и восстановления с указанием их SPID (идентификатора сессии), текста запроса и процента выполнения.
Шаг 2. Завершим зависший процесс бэкапа. Допустим, запрос показал, что бэкап лога выполняется под сессией номер 65. Выполним команду принудительного завершения именно этой сессии:
KILL 65;
Эта команда безопасно отменит только зависшую операцию бэкапа, не затрагивая других пользователей и службы SQL Server. Блокировка файлов будет снята, и ошибка 3023 исчезнет.
Просто снять блокировку — это лишь половина дела. Нам необходимо выяснить, почему файл лога транзакций LDF переполняется и почему SQL Server не может использовать его пространство повторно. Для этого выполним следующий диагностический запрос:
SELECT name, recovery_model_desc, log_reuse_wait_desc FROM sys.databases;
Особое внимание обратим на колонку log_reuse_wait_desc для нашей базы данных. Она указывает на причину, по которой лог не очищается автоматически. Разберем основные сценарии:
FULL). SQL Server хранит все транзакции в лог-файле до тех пор, пока не будет сделан бэкап лога (BACKUP LOG). Если бэкапы лога не настроены или ломаются, файл LDF будет расти бесконечно, пока не займет весь диск.DBCC OPENTRAN.Если диск полностью переполнен, и у нас нет свободного места даже для того, чтобы записать стандартный бэкап лога, мы столкнемся с тупиковой ситуацией. В этом случае мы можем применить административный прием — выполнить резервное копирование лога на фиктивное устройство NUL (аналог «черной дыры» /dev/null):
BACKUP LOG [Base_Name] TO DISK = 'NUL';
Эта команда заставит SQL Server очистить виртуальный лог транзакций и пометить внутреннее пространство LDF-файла как свободное для повторного использования, при этом физический файл бэкапа создаваться не будет. После этого мы сможем без проблем выполнить сжатие файла лога до разумного размера с помощью команды:
DBCC SHRINKFILE (acc_main, 1024);
Здесь acc_main — логическое имя файла лога транзакций из настроек базы данных, а 1024 — желаемый размер файла в мегабайтах после сжатия. Обратите внимание! Сброс лога «в пустоту» прерывает цепочку бэкапов, необходимую для восстановления базы на определенный момент времени (Point-in-time recovery). Сразу же после выполнения этой процедуры обязательно сделайте полный бэкап всей базы данных!
В ходе обсуждения на форуме возник спор о том, какую модель восстановления (Recovery Model) лучше использовать для баз данных 1С:Предприятие. Рассмотрим подробнее аргументы обеих сторон.
Простая модель (Simple)
В этой модели лог транзакций очищается автоматически при фиксации транзакций и прохождении контрольной точки (checkpoint). Лог-файл LDF практически не разрастается, база требует минимум внимания со стороны администратора.
Полная модель (Full)
В этой модели SQL Server сохраняет абсолютно все транзакции в лог-файле. Пространство внутри файла LDF не освобождается автоматически, а только после успешного выполнения резервного копирования лога транзакций.
Если специфика бизнеса требует использования модели восстановления Full, мы должны правильно настроить регламентные задачи в SQL Server Agent. Ошибкой автора темы было то, что база находилась в модели Full, но регулярные бэкапы логов транзакций не выполнялись.
Правильный регламент обслуживания должен выглядеть следующим образом:
LDF, и обеспечивает минимальную потерю данных при сбоях.Для настройки этих задач мы можем использовать встроенные планы обслуживания (Maintenance Plans) в SSMS или написать собственные T-SQL скрипты для SQL Server Agent. При создании резервных копий сторонними средствами администрирования не забывайте использовать опцию COPY_ONLY, чтобы не нарушить основную цепочку резервного копирования, настроенную в СУБД.
Подводя итоги, отметим, что ошибка переполнения лога СУБД LOG_BACKUP в базах 1С всегда является следствием отсутствия или неверной настройки политики резервного копирования. Перезапуск службы SQL Server — это лишь временный костыль, который может навредить целостности данных. Правильным решением является точечное завершение блокирующего бэкапа с помощью команды KILL, очистка лога и последующая грамотная настройка регламентных планов обслуживания в зависимости от выбранной модели восстановления базы данных.