Ускоряем обновление тяжёлых баз 1С
В этой статье я собрал методы ускорения обновления тяжёлых баз 1С. Все методы рабочие и неоднократно проверены на практике. Актуальны для современных конфигураций. Для более старых – частично, кое-что надо адаптировать.
Под обновлением я буду понимать только накатывание на рабочую базу – от момента начала реструктуризации до окончания выполнения дополнительных обработчиков данных. Т.е. говорим о той части обновления, которая обычно считается непобедимым, неуправляемым злом. Изготовления конфигурации для обновления не касаемся.
Кратко о проблеме. Иногда база 1С обновляется так долго, что не влезает в технологическое окно (время, в течение которого бизнес готов потерпеть без 1С). Иногда проблема в слабом сервере, но в большинстве случаев – в большом записей некоторых таблиц (справочников, документов, регистров). Ну и в остром желании разработчиков конфигурации что-то поменять в этих таблицах 😊. Особенно при переходе между LTS-версиями.
Тяжёлое обновление может занимать несколько суток, из которых существенную часть будет занимать монопольная часть, когда пользователи вообще не могут работать. Окна – значительно меньше. Оптимизация с помощью приведённых ниже методов может сократить время обновления в несколько раз.
Отдельно отмечу: знаю, что есть и фоновая реструктуризация, и механизм обновления через копию. Также знаю, что они не всегда могут быть применены. Если у вас эти штуки работают и всё хорошо – отлично, я за вас рад.
Окна
Тут у всех по-разному, но самый распространённый случай: в течение месяца есть несколько небольших окон (например, часов по 8), и под финальное обновление бизнес может выделить окно побольше – например, часов 40.
В зависимости от расписания и количества окон можно применять разные методы.
Процесс обновления
Процесс обновления состоит из трёх основных частей – пропишу на всякий случай, чтобы мы одинаково всё понимали.
Реструктуризация – когда мы накатили новую конфигурацию и нажали F7. Заканчивается появлением списка изменений с кнопкой «Принять». Во время реструктуризации в базу не может зайти вообще никто ни под какими правами. Это – самый чёрный ящик обновления. Но мы будем его оптимизировать.
Регистрация – назову его так, хотя на самом деле этап комплексный. Реструктуризация прошла, запустили 1С в режиме Предприятие, вылезло окно, спросило точно ли мы легально получили обновление, мы согласились – начался этап.
Там два действия – выполняются обязательные обработчики данных (сюда мы лезть вообще не будем) и регистрируются объекты для следующего этапа (выполнения доп. обработчиков данных).
Регистрация занимает больше всего времени – выполняются конские запросы, которые собирают миллионы объектов для обработки, и каждый объект регистрируется в плане обмена. Этот этап может занимать до нескольких часов, и больше всего времени уходит на регистрацию. Её мы тоже будем оптимизировать, но прицепом, не целенаправленно.
Пока идёт этап регистрации, в базу тоже никто зайти не может (кроме нашего единственного сеанса).
Доп. обработчики – обрабатываются объекты, зарегистрированные на предыдущем этапе. Для каждого типа объектов код обработки – свой, их ещё и несколько может быть. Каждый отдельный поток обработки – это обработчик, так его и будем называть. Обработчиков может быть 15, а может 500.
В большинстве случаев обработчики меняют и перезаписывают существующие данные. Например, заполняют новое измерение в регистре, или перекладывают значение одного реквизита в другой (так было, например, при появлении справочника ставок НДС). Бывает перекладывание из одного объекта в другой – например, из удаляемого регистра в новый. Случается и создание новых объектов – так, например, создавали справочник объектов расчётов.
При выполнении доп. обработчиков пользователи уже могут работать в 1С, но с ограничениями – когда люди заходят в объект, по которому ещё не выполнились обработчики, то не смогут ничего в нём менять. Соответственно, полноценно работать они не могут.
Доп. обработчики будут главным объектом для нашей оптимизации.
Что где лежит
Все значимые процедуры, связанные с обновлением, лежат в модулях менеджеров объектов.
ПриДобавленииОбработчиковОбновления – тут регистрируются обработчики обновления для данного объекта. Мы их потом видим в прогрессе обновления (в отчете «Прогресс отложенного обновления»).
ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию – тут лежит запрос, который выбирает объекты для конкретного обработчика и складывает их в план обмена.
ОбработатьДанныеДляПереходаНаНовуюВерсию – здесь, собственно, обрабатываются объекты. Берутся из плана обмена, что-то с ними делается, отмечается выполнение.
Как выбрать объекты для оптимизации
Самый простой способ выбора – сделать обновление на копии и посмотреть, на чём тормозит.
В реструктуризации обычно львиная доля времени уходит на небольшое количество объектов, в которых очень много записей. Делаем реструктуризацию на копии и смотрим, на чём дольше всего висит. Неприятность тут в том, что нет лога – надо сидеть глазками глядеть, т.к. текущий объект реструктуризации в конфигураторе написан. Ребята мои придумали такой способ: ставят запись видео с экрана, потом пересматривают на высокой скорости.
С доп. обработчиками проще – когда закончится реструктуризация, можно в отчёте «Прогресс отложенного обновления» посмотреть, сколько каких объектов попало под обработку. Ну и подождать самой обработки – вы сами увидите, какие обрабатываются дольше всего.
Всё посмотрели, записали, пошли оптимизировать.
Обрезка регистров
Обрезка регистров – неплохой способ уменьшить и время реструктуризации, и выполнение доп. обработчика. Как обрезать регистр – сами знаете, обработкой. Ввести новые остатки и удалить записи до выбранной точки обрезки. Не забудьте только на время удаления записей из регистра отключить у него итоги, иначе место на диске кончится из-за многоразового пересчёта.
Но есть проблема – эти записи потом, с высокой вероятностью, восстановятся. Среди обработчиков 1С очень часто встречается полное переформирование записей по регистру. Если не хотите – напишите в коде фильтрацию по дате документа.
Однако, способ все-таки неплох. Как минимум реструктуризация ускоряется.
Лучше всего этот способ работает с независимыми регистрами сведений – например, версиями объектов.
Не меняем то, что 1С решила изменить
Некоторые изменения в тяжёлых объектах хорошо видно – сравнением конфигураций.
Помним, что добавление нового поля в объект не приводит к долгой реструктуризации, поэтому такие изменения можно проигнорировать. Аналогично – расширение составного типа.
А вот удаление поля – это да, это надолго. Мы можем это поле просто не удалять, по крайней мере в основном окне. Переименуйте его так, чтобы мама родная не узнала – и пускай пока поживёт.
Аналогично с сужением составного типа – можно пока пожить и со старым типов.
Некоторые типы изменений видно плохо. Например, в регистре или документе вроде нет никаких изменений, а реструктуризация по нему идёт долго. Значит, изменили тип, используемый в нашем объекте. Обычно это удаление значения перечисления (мне часто попадалось перечисление ХозяйственныеОперации). Если перечисление много где используется, то удаление одного его значения дёргает все эти объекты.
Мы вполне можем оставить удаляемое значения перечисления ещё пожить. Переименовать только, чтобы где-то кодом его не использовал никто. Заодно можете проверить, где и кто на него ссылается.
Этот метод экономит просто конское время на реструктуризации.
Как потом вернуть объекты к типовой конфигурации
Как вернуть – сами знаете, но сделать это можно потом, после обновления, в следующее окно. Если окна регулярные и короткие, то можно по одному объекту кошмарить.
Подбирать под размер окна можно на копии – развернули, удалили что-нибудь, запустили реструктуризацию, посмотрели на замеры времени. Если ок – повторяем на рабочей.
Некоторые изменения так страшны, что и в последующие окна не влезают – например, уже упомянутые ХозяйственныеОперации. Ну и пусть себе лежат.
Вынос и распараллеливание обработчика
Это основной метод ускорения доп. обработчиков. Типовая конфигурация выполняет их очень медленно и неэффективно. Да, там есть настройка про количество потоков, но она то ли совсем не распараллеливает один обработчик, то ли делает это очень плохо. В итоге мы имеем выполнение каждого обработчика в один поток.
При этом, если посмотреть код обработчика, то видно, что там обычно не важна последовательность обработки объектов, т.к. они друг от друга не зависят. Каждый обрабатывается изолированно. Значит, их вполне можно распараллелить.
Первым делом отключаем типовое выполнение обработчика – в расширение тащим его процедуру ПриДобавленииОбработчиковОбновления и делаем её пустой. Тут же получаем приятный бонус – раз обработчик отключён, он сократит время этапа Регистрация, т.к. не будет выполняться его запрос и запись в план обмена.
Дальше нам нужна простенькая инфраструктура для выполнения распараллеленного кода. Мы сделали в расширении общий модуль, туда вытаскивали код обработчиков, и написали обработку с кучей кнопок (одна под каждый обработчик).
Первой действие кнопки – выполнить запрос, который взят из процедуры ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию. Он там хорошо написан, можно брать практически один в один. Обратите внимание – запрос почти всегда возвращает только те объекты, которые надо обработать. Если объект обработан, запрос его не возвращает. Значит, при прерывании обработки и выполнении её заново запрос вернёт только недоделанные объекты. Исключением бывают документы, суть обработки которых – переформирование движений. Вот тут надо осторожнее, не прерывать обработку, а то придётся начинать заново.
Полученные объекты делим на нужное количество параллельных потоков. Мы прям в обработке указывали, сколько потоков запустить. Доходило до 128 под один обработчик – так он выполнится в десятки раз быстрее, чем типовым кодом. Формируем массив объектов для каждого потока, и типовыми процедурами длительных операций отправляем обрабатываться в наш общий модуль. Под каждый обработчик – отдельная процедура в общем модуле.
В общем модуле нам нужна слегка переделанная процедура ОбработатьДанныеДляПереходаНаНовуюВерсию из модуля менеджера объекта. Вырезаем оттуда получение объектов из плана обмена (мы список объектов передаём параметром), и заменяем запись объекта. В типовой будет ОбновлениеИнформационнойБазы.ЗаписатьДанные(НаборЗаписей), ну а мы просто пишем НаборЗаписей.Записать(). И убираем отметку выполнения ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки – нам это не нужно, т.к. объект к обновлению мы не регистрировали.
С первого взгляда кажется непросто, но нужно только руку набить. Объекты делятся на потоки, каждый поток обрабатывает свою пачку, а когда закончит – фоновое задание завершается.
Проблем с блокировкой не возникало, т.к. во всех обработчиках этот момент учтён разработчиками 1С. Они как знали, что мы будем их распараллеливать 😊.
Прогресс выполнения обработчиков
Т.к. обработчики у нас выполняются нетиповым способом, мы не видим прогресса их выполнения. Это немного нервирует – хочется же какого-то понимания и контроля.
Мы для себя сделали несложный механизм контроля через регистр сведений. Измерения: ИмяПроцедуры и НомерПотока, ресурсы – Всего, Обработано, ДатаИзменения, ДатаНачала. Когда запускаем потоки, пишем для каждого запись в регистр – думаю, понятно, что будет в каждом поле.
Дальше в каждом обработчике, который лежит в нашем общем модуле, добавляем счётчик обработанных объектов в цикле и обновление «его» записи в регистре – заходит, меняет дату изменения и инкрементирует количество обработанных объектов.
Ну а мы сидим, смотрим в регистр и понимаем прогресс отдельно по каждому потоку. Заодно видим время выполнения обработчиков – есть и дата начала, и дата последнего изменения.
Выбор обработчиков для распараллеливания
Большинство обработчиков – независимые, т.е. они не пользуются результатами других обработчиков, и их результат никому не нужен. Но бывают зависимые – этот момент надо учитывать и при выборе обработчиков для распараллеливания, и при определении порядка нажимания кнопочек в нашей обработке.
Первым делом смотрим на приоритет обработчика в процедуре ПриДобавленииОбработчиковОбновления. Будет написано что-то вроде:
Обработчик.Порядок = Перечисления.ПорядокОбработчиковОбновления.Критичный;
Значит, этот обработчик можно распараллелить, но выполнить его надо в первую очередь, не запуская типовые доп. обработчики.
Второе, на что надо обращать внимание – взаимосвязи обработчиков. Иногда там прямо написано, что такое-то обработчик выполняется после такого-то. Конструкции лежат в процедуре ПриДобавленииОбработчиковОбновления, после добавления обработчика, их можно искать по конструкциям:
Приоритет.Порядок = "До";
Приоритет.Порядок = "После";
Распараллеливать их можно, но учитывайте порядок – его надо будет соблюдать вручную.
Предварительное выполнение обработчиков
Если есть регулярные небольшие окна, то некоторые обработчики можно выполнить предварительно, до основного обновления. Разумеется, потребуется и небольшая реструктуризация. Зато сэкономите время в основном окне обновления – и на реструктуризации, и на доп. обработчиках.
Обычно это обработчики, связанные с добавлением новых полей, если в них используются данные либо простых типов, либо уже существующих в конфигурации. Т.е. выполнение обработчика максимально изолированно, в т.ч. от остальных изменений релиза.
Например, в одном из релизов в регистр сведений РеестрДокументов добавили измерение ИдентификаторЗаписи, куда просто писали какой-нибудь уникальный идентификатор (генерировали при записи). Мы добавили это измерение предварительно, и сразу заполнили для всех записей. Заодно и код генерации этого идентификатора сразу вставили в конфигурацию – пусть себе пишутся.
Мой кейс
Ну и напоследок реальные цифры. Мне надо было обновить клиента УТ с 11.4 на 11.5.22. Это 4 тяжёлых перехода между редакциями и LTS, в т.ч. наш любимый невообразимый переход с 11.4 на 11.5, где просто невообразимое количество тяжёлых обработчиков (одни только ставка НДС и объекты расчётов чего стоят).
Доступное окно было 40 часов. Регулярные окна – раз в неделю, часов по 12. Обновление типовыми средствами занимало порядка 300 часов, из которых монопольное время (реструктуризация + регистрация) порядка 70 часов.
Так-то можно было по одной редакции в неделю накатывать, но это дорого – конфигурация сильно доработанная, и пришлось бы проводить 4 больших тестирования. И заставлять людей неделю работать на релизе, который через неделю заменится другим. Выбрали накатить все 4 обновления за один присест.
Применили все методы, изложенные в статье. Регистры обрезали, часть обработчиков выполнили предварительно, реструктуризацию сжали раза в 3-4, пару десятков доп. обработчиков вынесли в параллельное выполнение.
Ну и влезли в окно.
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.