В практике администрирования и разработки на платформе 1С:Предприятие иногда возникают крайне загадочные и трудновоспроизводимые ошибки. Одна из таких проблем — расхождение данных в табличной части одного и того же документа у разных пользователей. Представьте ситуацию: один пользователь открывает документ и видит в табличной части 8 строк, а другой в то же самое время в своем сеансе видит только 7 строк. При этом перезапуск сеанса временно решает проблему. Ситуация усугубляется, если в «проблемном» варианте в одном из полей (например, «Договор») отображается битая ссылка <Объект не найден>.
В данной статье мы подробно проанализируем эту ситуацию на примере конфигурации «Управление торговлей 10.3», работающей на СУБД IBM DB2, выясним истинные технические причины этого поведения и выработаем пошаговый план устранения неисправности.
На первый взгляд такое поведение кажется невозможным, ведь база данных едина для всех сеансов. Однако детальный технический анализ показывает, что проблема лежит на стыке трех технологий: платформенного кэширования 1С, механизма ограничения доступа на уровне записей (RLS) и особенностей работы транзакций конкретной СУБД.
Рассмотрим четыре главные причины, которые могут приводить к подобному эффекту:
<Объект не найден> в поле «Договор». В 1С ограничения доступа накладываются динамически при выполнении запросов к базе данных. Если у пользователя в одном из сеансов не до конца или некорректно инициализировались параметры сеанса (например, список разрешенных контрагентов или организаций), система RLS начинает скрывать записи. Платформа 1С при этом может вести себя двояко: либо полностью скрыть строку табличной части, где фигурирует «запрещенный» договор (тогда строк становится меньше), либо отобразить строку, но заменить ссылку на договор битой ссылкой.rphost. Платформа активно кэширует данные объектов на сервере приложений. Если синхронизация кэша между процессами дает сбой (например, из-за микросекундных сетевых задержек или нехватки оперативной памяти), один процесс выдает актуальные данные из СУБД, а второй — устаревшие данные из локального кэша сеансов (каталог snccntx).---
Разберем детально, как проверить гипотезу с ограничениями доступа. Нам необходимо убедиться, что параметры сеанса, используемые в шаблонах ограничений, инициализируются гарантированно правильно.
Проанализируем код модуля сеанса. Откроем конфигуратор и найдем предопределенную процедуру УстановкаПараметровСеанса. Обратите внимание на то, как происходит заполнение параметров. Инициализация должна происходить атомарно и без возможности пропуска из-за случайных ошибок выполнения.
Рекомендуется использовать безопасную конструкцию инициализации параметров «по требованию». Посмотрим на пример реализации:
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
// Если массив требуемых параметров пуст, инициализируем критически важные параметры RLS
Если ТребуемыеПараметры = Неопределено Тогда
ИнициализироватьПараметрыДоступаПользователя();
Иначе
// Инициализация конкретных параметров по запросу платформы
Для Каждого ИмяПараметра Из ТребуемыеПараметры Цикл
Если ИмяПараметра = "РазрешенныеКатегорииНоменклатуры" Тогда
ПараметрыСеанса.РазрешенныеКатегорииНоменклатуры = ПолучитьДоступныеКатегории();
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Если в момент возникновения проблемы у «проблемного» пользователя открыть консоль параметров сеанса, мы сможем воочию увидеть, какие именно значения установлены в его сеансе. Разница в наборах значений между «нормальным» и «глючным» сеансом сразу укажет на ошибку в коде инициализации.
---
Поскольку перезапуск сеанса решает проблему, кэширование является вторым главным подозреваемым. Выполним полную очистку кэша по шагам.
Очистка серверного кэша сеансов (snccntx):
1C:Enterprise 8.3 Server Agent).C:\Program Files\1cv8\srvinfo\reg_1541).snccntx (именно в них хранится NoSQL-кэш сеансовых данных) и полностью удалим их содержимое.Для борьбы с зависанием кэша функций в общих модулях (если используется свойство «Повторное использование возвращаемых значений») в коде конфигурации в критических местах (например, при открытии формы документа) можно программно вызывать очистку:
ОбновитьПовторноИспользуемыеЗначения();
Это принудительно заставит платформу сбросить устаревшие закешированные данные функций на сервере для текущего сеанса.
---
Если дело в СУБД, нам необходимо выполнить регламентные процедуры, которые обновят статистику распределения данных и устранят физическую фрагментацию таблиц табличных частей документов.
Для IBM DB2 критически важно регулярно выполнять команды утилит RUNSTATS и REORG. Разберем, как выполнить их через командную строку DB2 (Command Line Processor):
db2 connect to ИМЯ_БАЗЫ_ДАННЫХ user ИМЯ_ПОЛЬЗОВАТЕЛЯ using ПАРОЛЬ
_Document150_VT1200):
db2 REORG TABLE SCHEMA._Document150_VT1200
db2 RUNSTATS ON TABLE SCHEMA._Document150_VT1200 ON ALL COLUMNS WITH DISTRIBUTION AND DETAILED INDEXES ALL
Также проверим параметры конфигурации базы данных DB2, отвечающие за управление блокировками. Для этого выполним команду:
db2 get db cfg for ИМЯ_БАЗЫ_ДАННЫХ
Обратим внимание на параметры LOCKLIST (размер памяти под блокировки) и MAXLOCKS (процент памяти блокировок, после которого происходит эскалация блокировок строк до блокировки всей таблицы). Если эти значения слишком малы, СУБД будет принудительно блокировать таблицы целиком или переходить на более слабые уровни изоляции транзакций, что и приводит к фантомным чтениям в параллельных сеансах 1С. Увеличим их при необходимости.
---
Если проблема плавающая и возникает очень редко, идеальным способом поймать ее за руку является настройка Технологического журнала (ТЖ) 1С. Мы можем настроить сбор логов таким образом, чтобы фиксировать только запросы, связанные со специфическим документом, в котором разнится число строк.
Создадим файл конфигурации ТЖ logcfg.xml в каталоге C:\Program Files\1cv8\conf на сервере 1С следующего содержания:
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\v8logs\db_queries" history="72">
<event>
<eq property="Name" value="DBMSSQL"/>
</event>
<event>
<eq property="Name" value="SDBL"/>
</event>
<property name="all"/>
</log>
</config>
Важное примечание: Событие DBMSSQL в терминологии технологического журнала 1С отвечает за все SQL-запросы к СУБД, включая СУБД IBM DB2 и PostgreSQL (несмотря на название).
Когда пользователь снова сообщит, что видит неверное количество строк, мы сможем открыть логи технологического журнала за эту минуту, найти SQL-запрос от его сеанса к табличной части документа и сопоставить его с запросом из «правильного» сеанса. Это даст 100% ответ на вопрос, вернула ли СУБД некорректные данные или же платформа отфильтровала их на своей стороне по механизму RLS.