В процессе администрирования и обслуживания крупных информационных баз 1С перед техническими специалистами нередко возникают нестандартные задачи. Например, когда в рабочей базе на платформе 8.3.14 при попытке удаления или замены дублирующихся элементов возникает критическая Ошибка SDBL (ошибка слоя базы данных 1С). При этом известно, что на более новой версии платформы, например 8.3.15, эта системная ошибка уже исправлена разработчиками фирмы «1С».
В такой ситуации у некоторых администраторов возникает соблазн реализовать «быстрое» решение: развернуть на отдельном компьютере новый сервер приложений 1С версии 8.3.15, подключить его напрямую к той же самой «живой» рабочей SQL-базе, где в этот момент продолжают трудиться пользователи на старой платформе, выполнить замену дублей и тем самым «причинить добро» системе. В этой статье мы подробно проанализируем, почему подобная схема является критически опасной для целостности ваших данных, к каким катастрофическим последствиям она может привести и какими альтернативными безопасными путями следует решить эту проблему.
Начнем с базовых принципов архитектуры «1С:Предприятие 8». Официальная позиция разработчиков платформы и экспертов по технологическим вопросам однозначна: одному физическому пространству базы данных в СУБД должен соответствовать ровно один кластер серверов 1С. Платформа 1С программно не блокирует одновременное подключение двух независимых кластеров (и тем более разных версий) к одной базе данных SQL, так как на уровне СУБД это выглядит как обычные клиентские сессии. Однако это нештатный режим, который полностью ломает логику работы платформенных механизмов.
Если запустить два сервера приложений 1С параллельно на одной базе данных, то процессы будут полностью изолированы друг от друга. При этом гарантированно выйдут из строя следующие жизненно важные механизмы:
8.3.15 начнет изменять данные, которые сервер 8.3.14 считает монопольно заблокированными. СУБД SQL попытается спасти ситуацию за счет физических блокировок таблиц, но из-за несогласованности уровней приложения это неизбежно приведет к логической каше в транзакциях.8.3.15 запишет измененные данные напрямую в СУБД SQL, рабочий сервер 8.3.14 об этом изменении ничего не узнает, так как его локальный кэш останется прежним. При первой же записи со стороны пользователя на старом сервере закэшированные устаревшие данные могут перетереть новые корректные изменения, сделанные новой платформой.Ситуация усугубляется тем, что мы пытаемся подключить к одной базе серверы разных поколений. При этом возникают специфические технологические риски:
8.3.15 к СУБД платформа может автоматически обновить структуру служебных таблиц (например, таблиц конфигурации _Config, системных индексов или таблиц регистрации изменений) под новые стандарты и алгоритмы версии 8.3.15. Как только эта тихая реструктуризация завершится, старый сервер 8.3.14 мгновенно потеряет физическую возможность работать с этой базой данных. Все активные пользователи вылетят из системы с критическими ошибками несовместимости форматов, а восстановить работоспособность старого сервера без отката базы из резервной копии будет невозможно.8.3.14 и 8.3.15 используют разную логику оптимизации и генерации запросов. Сформированные новой платформой структуры данных или индексы могут оказаться абсолютно нечитаемыми для старого сервера 8.3.14, что вызовет лавинообразное падение рабочих процессов rphost на основном сервере.Рассмотрим подробнее саму операцию удаления дублирующихся элементов. Замена ссылок — это не просто перезапись реквизита в одной таблице, а сложнейшая и крайне тяжелая транзакционная процедура:
Во-первых, система под капотом использует метод НайтиПоСсылкам(). Чтобы определить, в каких именно местах базы данных используется дублирующийся элемент, платформа выполняет последовательное сканирование практически всех таблиц базы данных, где этот тип данных теоретически может встречаться. Это накладывает массовые разделяемые блокировки (Shared Locks) на таблицы СУБД.
Во-вторых, в момент непосредственной перезаписи ссылок эти блокировки эскалируются до монопольных (Exclusive Locks). Если в этот момент в базе работают кассиры или менеджеры, неизбежно возникнут жесткие взаимоблокировки (Deadlocks) на уровне СУБД. Так как менеджеры управляемых блокировок серверов изолированы, СУБД SQL начнет аварийно «убивать» сессии пользователей либо прерывать сам процесс замены дублей. При прерывании транзакции в базе могут остаться «битые ссылки» (когда дубль из базы уже удален, но ссылки на него в некоторых документах не успели замениться на оригинал).
Ниже приведем пример того, как выглядит классический небезопасный код замены ссылок, который при одновременной работе двух серверов гарантированно вызовет блокировки данных:
// Пример небезопасного поиска и замены дублей в распределенной среде
ТаблицаЗамены = Новый ТаблицаЗначений;
ТаблицаЗамены.Колонки.Добавить("Ссылка");
НоваяСтрока = ТаблицаЗамены.Добавить();
НоваяСтрока.Ссылка = СсылкаДубль;
// Поиск мест использования по всей базе данных
ТаблицаМестИспользования = НайтиПоСсылкам(ТаблицаЗамены);
Для Каждого СтрокаМеста Из ТаблицаМестИспользования Цикл
// Прямая перезапись объектов без учета транзакционного контекста другого сервера
ОбъектМеста = СтрокаМеста.Данные.ПолучитьОбъект();
// Логика замены ссылки на СсылкаОригинал...
ОбъектМеста.Записать();
КонецЦикла;
Если ваша база данных должна функционировать непрерывно, а исправить ошибки SDBL и удалить дубли необходимо, разберем по шагам три безопасных сценария решения задачи.
Поскольку ошибка SDBL на релизе 8.3.14 при замене элементов является официально зафиксированным и признанным багом платформы, самым правильным решением будет системное обновление рабочего сервера приложений до стабильного релиза ветки 8.3.15 (или более современной поддерживаемой версии).
Проанализируем шаги выполнения обновления:
8.3.14.8.3.15 на рабочий сервер приложений и запустите службу.Если полноценно обновить основной сервер приложений прямо сейчас невозможно по организационным причинам, необходимо согласовать короткий технологический перерыв (буквально на 20-30 минут) и выполнить работы по следующей схеме:
8.3.15 на отдельной временной машине и настройте подключение к SQL-серверу (но не запускайте транзакции!).8.3.15, подключитесь к базе, выполните обработку по замене и удалению дублей.8.3.15.8.3.14 и разрешите вход пользователям.Важное предупреждение: Перед выполнением этого сценария обязательно проверьте на тестовой копии базы данных, сможет ли старый сервер 8.3.14 запустить базу после того, как к ней физически подключался сервер версии 8.3.15. Если в процессе работы новой платформы произойдет реструктуризация системных таблиц конфигурации, старая версия платформы не сможет прочитать структуру базы данных.
Если технологическое окно получить невозможно совсем, единственным теоретическим выходом остается написание T-SQL скрипта непосредственно на стороне СУБД SQL для прямой замены идентификаторов в таблицах базы данных в обход сервера 1С.
Выясним особенности этого подхода:
_Document120 с реальными именами СУБД).Таким образом, проведение экспериментов с одновременным подключением двух разных серверов к одной базе данных SQL является неоправданной авантюрой, которая почти наверняка закончится повреждением структуры данных вашей компании. Настоятельно рекомендуем использовать Сценарий №1 или Сценарий №2 для решения возникших технических сложностей.