Фоновые задания в OneScript и эксперименты с многопоточной выкачкой версий хранилища

09.01.22

Разработка - Групповая разработка (Git, хранилище)

Описываю использование фоновых заданий в OneScript.

Однажды передо мной встала задача выгрузить в гит многолетнюю историю версий хранилища - больше 3 тысяч версий. Решение в лоб - расчехляем старый добрый gitsync и натравливаем его на хранилище. Конфигурации уровня ERP скачиваются долго - и это большая проблема. Частично выгрузку можно ускорить, разделив выгрузку версий хранилища и обработку их для выгрузки в гит (как описано в моей статье Devops на коленке). Но все равно это очень долго.

Одно из возможных решений - распараллелить обработку версий хранилища, запустить выгрузку в разные ветки гита разных версий (например 1-1000, 1001-2000, 2001-3000 и тд), а потом сделать rebase силами git. Это тоже не очень быстрая операция. Параллельность обработки версий хранилища можно обеспечить вручную - запустив нужные команды в разных окошках консоли, а потом следить за их выполнением, не очень-то удобно.

А мы знаем, что с версии 1.6.0 в oscript появилась возможность использовать фоновые задания. Синтаксис работы с ними чуть отличается от 1С, но принцип схож - создаем массив с параметрами и вместе с именем выполняемой процедуры передаем его менеджеру фоновых заданий, затем можно ожидать завершения выполнения либо всех фоновых заданий, либо одного (оставлю ссылку на документацию, там все предельно понятно написано - Фоновое задание).

Попробую написать скрипт с фоновыми заданиями, который выгрузит версии хранилища в несколько потоков.

 

Скрипт многопоточной загрузки версий хранилища

Сформирую таблицу для управления потоками загрузки, в ее строчках будут лежать номера версий хранилища, также предусмотрим поля для хранения времени начала и окончания загрузки и статуса. В функцию заполнения таблицы передам начальный и конечный номер версии хранилища.

Функция ТаблицаВерсийДляЗагрузки(НачальныйНомер, КонечныйНомер)

    ТаблицаВерсий = Новый ТаблицаЗначений;
    ТаблицаВерсий.Колонки.Добавить("НомерВерсии");
    ТаблицаВерсий.Колонки.Добавить("Статус");
    ТаблицаВерсий.Колонки.Добавить("ДатаНачалаЗагрузки");
    ТаблицаВерсий.Колонки.Добавить("ДатаЗавершенияЗагрузки");

    Счетчик = НачальныйНомер;
    Пока Счетчик <= КонечныйНомер Цикл
        НоваяСтрока = ТаблицаВерсий.Добавить();
        НоваяСтрока.НомерВерсии = Счетчик;
        НоваяСтрока.Статус = "Не обработана";
        Счетчик = Счетчик + 1;
    КонецЦикла;

    Возврат ТаблицаВерсий;

КонецФункции

Чуть не забыл, хранилище 1С под одним и тем же пользователем не может работать одновременно с несколькими базами - значит нам надо создать несколько пользователей в хранилище и передать в скрипт описание этих пользователей.

 

 

Здесь я создал пользователей без паролей и каких-либо прав с именем по шаблону "ЧтениеХранилищаНомер". В функции получения массива пользователей беру пользователя, начиная с нулевого (ну программист я, что поделаешь) и заканчивая нужным количеством (вынес количество пользователей хранилища в переменную - пригодится дальше, когда буду экспериментировать).

Функция МассивПользователейХранилища(КоличествоПользователейХранилища)

    Результат = Новый Массив;

    СчетчикПользователей = 0;
    
    Пока СчетчикПользователей <= КоличествоПользователейХранилища Цикл
        Результат.Добавить(СтрШаблон("%1%2", ИмяПользователяХранилища, СчетчикПользователей));
        СчетчикПользователей = СчетчикПользователей + 1;
    КонецЦикла;

    Возврат Результат;

Конецфункции

Один поток - это один пользователь. При создании фонового задания буду исключать из массива пользователя, который в этом фоновом задании выгружает версию. При окончании фонового задания - верну его пользователя в массив для дальнейшего использования. И теперь все просто - обхожу циклом таблицу версий и создаю фоновое задание с выгрузкой. Когда доступные пользователи (потоки) кончаются, ожидаю завершения работы любого фонового, затем продолжаю обход таблицы.

ТаблицаВерсий = ТаблицаВерсийДляЗагрузки(1, 15);

МассивТекущихЗаданий = Новый Массив;

КоличествоПользователейХранилища = 8;
СвободныеПользователи = МассивПользователейХранилища(КоличествоПользователейХранилища);

Для Каждого СтрокаВерсии Из ТаблицаВерсий Цикл
    
    Если МассивТекущихЗаданий.Количество() = КоличествоПользователейХранилища Тогда
        ОжидатьВыполненияЛюбогоЗаданияЗагрузки(МассивТекущихЗаданий, ТаблицаВерсий, СвободныеПользователи);    
    КонецЕсли;

    СтрокаВерсии.Статус = "Отправлена на загрузку";
    СтрокаВерсии.ДатаНачалаЗагрузки = ТекущаяДата();
    ДобавитьЗаданиеЗагрузки(СтрокаВерсии.НомерВерсии, МассивТекущихЗаданий, СвободныеПользователи);
   
КонецЦикла;

Добавление задания загрузки для лаконичности вынес в отдельную процедуру:

Процедура ДобавитьЗаданиеЗагрузки(НомерВерсии, МассивЗаданий, СвободныеПользователи)

    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(СвободныеПользователи[0]);
    МассивПараметров.Добавить(НомерВерсии);

    МассивЗаданий.Добавить(ФоновыеЗадания.Выполнить(ЭтотОбъект, "СохранитьВерсию", МассивПараметров));
    
    СвободныеПользователи.Удалить(0);
    
КонецПроцедуры

Ну и приведу листинг процедуры СохранитьВерсию, это простое использование библиотеки v8storage.

Процедура СохранитьВерсию(Пользователь, НомерВерсии) Экспорт

    ИмяФайлаКофигурации = СтрШаблон("%1\%2.cf", КаталогСохранения, НомерВерсии);
	ВременноеИмяФайлаКофигурации = СтрШаблон("%1\%2.tmp", КаталогСохранения, НомерВерсии);

    ХранилищеКонфигурации = Новый МенеджерХранилищаКонфигурации();
    ХранилищеКонфигурации.УстановитьПутьКХранилищу(ПутьКХранилищу);
    ХранилищеКонфигурации.УстановитьПараметрыАвторизации(Пользователь, "");
    
	ХранилищеКонфигурации.СохранитьВерсиюКонфигурацииВФайл(НомерВерсии, ВременноеИмяФайлаКофигурации);
	ПереместитьФайл(ВременноеИмяФайлаКофигурации, ИмяФайлаКофигурации);
	
КонецПроцедуры

В процедуре ОжидатьВыполненияЛюбогоЗаданияЗагрузки я ожидаю завершения любого фонового задания, возвращаю используемого там пользователя хранилища в пул свободных пользователей и дозаполняю таблицу версий - проставляю время завершения загрузки и ее результат.

Процедура ОжидатьВыполненияЛюбогоЗаданияЗагрузки(МассивТекущихЗаданий, ТаблицаВерсий, СвободныеПользователи)

        ИндексЗавершившегося = ФоновыеЗадания.ОжидатьЛюбое(МассивТекущихЗаданий);
        Задание = МассивТекущихЗаданий[ИндексЗавершившегося];
        ПараметрыЗадания = Задание.Параметры;
        Пользователь = ПараметрыЗадания[0];
        СвободныеПользователи.Добавить(Пользователь);
        НомерВерсии = ПараметрыЗадания[1];

        Если ЗначениеЗаполнено(Задание.ИнформацияОбОшибке) Тогда
            Загружена = "Ошибка";
            Сообщить(Задание.ИнформацияОбОшибке.ПодробноеОписаниеОшибки());
        Иначе
            Загружена = "Загружена";
        КонецЕсли;

        НайденныеСтроки = ТаблицаВерсий.НайтиСтроки(Новый Структура("НомерВерсии", НомерВерсии));
        Для Каждого СтрокаТаблицы Из НайденныеСтроки Цикл
            СтрокаТаблицы.Статус = Загружена;
            СтрокаТаблицы.ДатаЗавершенияЗагрузки = ТекущаяДата();
        КонецЦикла;
        МассивТекущихЗаданий.Удалить(ИндексЗавершившегося);

КонецПроцедуры

Полный текст скрипта вы можете найти на гитхабе RepoToCFBackgroundTask.

Запускаю его:

oscript .\toCF\RepoToCFBackgroundTask.os

Работает! Процесс oscript породил кучу процессов 1С. Вот скрин из ProcessExplorer от Sysinternals

 

 

Да, в конце выполнения скрипта можно посмотреть отладкой таблицу значений ТаблицаВерсий, а можно вывести ее строки в консоль, чтобы посмотреть динамику загрузки.

 

Эксперименты с многопоточной загрузкой версий хранилища

Ну и теперь самое интересное - эксперименты!

Эксперименты проводил на отдельной виртуальной машине, не загруженной больше ничем. Хранилище находится рядом в локальной сети, подключение по TCP. Я скачивал первые 50 версий нашей основной рабочей конфигурации - ERP. На тот момент это была версия 2.4.5.83, размер CF - в районе 1.3 Гб.

Выгрузка одной версии занимает в среднем 5 минут. Я очищал каталог загрузки и запускал загрузку в n потоков, от 1 до 14, так три раза. Усредненное время загрузки вывел в таблицу. Прошу ознакомиться с моими результатами.

 

Потоков Общее время, минут На 1 версию абсолютное, сек На 1 версию в потоке, мин
1 225,3 270,4 4,5
2 175,1 210,1 7,0
3 122,5 147,0 7,4
4 104,8 125,8 8,4
5 88,6 106,3 8,9
6 80,7 96,8 9,7
7 75,5 90,6 10,6
8 70,9 85,1 11,3
9 67,9 81,5 12,2
10 65,9 79,1 13,2
11 64,6 77,5 14,2
12 63,9 76,7 15,3
13 62,3 74,8 16,2
14 61,6 73,9

17,2

 

 

Если не хочется смотреть в таблицу и график, опишу результат словами - чуда не случилось. Если 50 версий в один поток загружаются чуть меньше 4 часов, то в 10 потоков они загружаются за чуть больше часа, а хотелось бы за 20 минут. Да, ускорение загрузки есть, но оно нелинейное. После 6-7 потоков уменьшение общего времени загрузки незначительно.

При повышении количества потоков начинается конкуренция за ресурсы компьютера, в первую очередь - жесткий диск. Посмотрите, какая жесткая просадка по диску (очередь диска огромная):

 

 

Что тут можно сделать? Поставить более быстрый диск, подсыпать еще ресурсов компьютеру, перенести хранилище еще ближе (да хоть на этот же компьютер). Возможности для улучшений еще есть.

Еще, приглашаю вас, мои читатели, воспользоваться этим скриптом и выложить в комментарии свои результаты.

В скрипте нужно указать свои данные - имя пользователя хранилища, путь к нему, место для складывания выгруженных cf. Интересно, что будет у вас.

Итоги

Я научился работать с фоновыми заданиями в oscript. Написал скрипт, позволяющий загружать версии хранилища в несколько потоков.

В итоге с перерывами в течение недели сделал выгрузку всей истории хранилища. Команда git rev-list --count HEAD в репо покажет сколько версий было выгружено:

 

 

3578 версий.

Неплохо, да?

oscript многопоточность v8storage хранилище

См. также

SALE! 50%

1С-программирование DevOps и автоматизация разработки Групповая разработка (Git, хранилище) DevOps для 1С Программист Стажер Платформа 1С v8.3 Платные (руб)

Использования систем контроля версий — стандарт современной разработки. На курсе научимся использованию Хранилища 1С и GIT при разработке на 1С:Предприятие 8. Разберем подходы и приемы коллективной разработки, научимся самостоятельно настраивать системы и ориентироваться в них.

4900 2450 руб.

29.06.2022    11928    99    4    

131

Групповая разработка (Git, хранилище) Программист Руководитель проекта Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Когда в хранилище одновременно разрабатывают несколько команд, сортировка сделанного и несделанного при формировании релиза и проведение code review по задачам превращаются в непроходимый квест. В таких случаях нужен бранчинг. Расскажем об опыте перехода на новую схему хранения кода для ИТ-департамента.

23.09.2024    2826    kraynev-navi    2    

25

Групповая разработка (Git, хранилище) Программист Бесплатно (free)

Называть Git новой технологией – уже смешно, но для многих 1С-ников это действительно «новое и неизведанное». Расскажем о плюсах и минусах двух главных систем контроля версий в мире 1С: Git и хранилища.

17.09.2024    7235    Golovanoff    69    

26

Групповая разработка (Git, хранилище) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Во многих командах незаслуженно забывают о том, что в базе меняются расширения (как от вендора, так и собственные) и внешние отчеты и обработки. Вплоть до того, что релиз происходит каждый день – меняются печатные формы, отчеты, обработки. Расскажем о том, как выгружать в Git не только изменения конфигурации рабочего контура, но и файлы внешних обработок и расширений.

05.09.2024    2166    ardn    12    

15

EDT Групповая разработка (Git, хранилище) Программист Платформа 1С v8.3 Бесплатно (free)

Заказчики любят EDT+Git за прозрачность и контроль качества. А у разработчиков есть две основные причины не любить EDT – это тормоза и глюки. Расскажем о том, что нужно учесть команде при переходе на EDT+Git.

14.08.2024    7618    lekot    34    

8

Групповая разработка (Git, хранилище) Программист Платформа 1С v8.3 Бесплатно (free)

В «долгоиграющих» проектах стандартный захват объектов 1С в хранилище может привести к длительным простоям других разработчиков. Но и создавать под каждую доработку отдельное хранилище, чтобы использовать технологию разветвленной разработки конфигураций от фирмы «1С» – избыточно. Расскажем о том, как разрабатывать в отдельной базе без ожиданий, а потом с легкостью перенести изменения в хранилище, используя основную идею технологии 1С – конфигурацию на поддержке хранилища.

05.08.2024    4223    sinichenko_alex    16    

25

Групповая разработка (Git, хранилище) Программист Руководитель проекта Стажер Бесплатно (free)

Про изменения и новинки в агрегаторе открытых проектов OpenYellow, которые появились с момента его создания: про портал, Github и Telegram

15.07.2024    3223    bayselonarrend    8    

24
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Brawler 458 10.01.22 00:41 Сейчас в теме
Зачем вам такие большие хранилища? Какая цель у всего этого?
2. pavlov_dv 10.01.22 07:20 Сейчас в теме
Идея интересная, надо попробовать.

У меня похожая задача - залить в git-репозиторий всю историю продуктивного хранилища.
Конфигурация на треть меньше, чем у Вас, но все равно долго. Несколько тысяч коммитов выгружались около месяца :-)
В однопоточном режиме, конечно.
3. artbear 1563 10.01.22 10:48 Сейчас в теме
(0) Интересный набор статей, спасибо.

Насколько я понимаю, остались два вопроса
1 - как же слить все эти выгрузки в одну ветку средствами гита?
2 - есть планы в гитсинк добавить функционал из статей?
4. ardn 657 10.01.22 12:22 Сейчас в теме
(3)
1 - последовательная выгрузка версий в скриптом, ничего выдающегося
2 - сложно, подумаю
5. JohnyDeath 302 11.01.22 08:57 Сейчас в теме
Еще можно попробовать:
1. Использовать tool1CD. Тогда не нужно будет создавать пользователя под каждый поток. Но нужно обеспечить файловый доступ к каталогу хранилища.
2. Создать RAM-диск и выгружать CF на него. Скорее всего просадка в скорости обусловлена именно очередью записи на жесткий диск.

Короткое видео про многопоточную выгрузку в гит от 2016 года
http://xdd.silverbulleters.org/t/mnogopotochnyj-variant-sinhronizaczii-hranilishha-1s/685
6. kamisov 216 16.01.22 10:21 Сейчас в теме
Рекомендую подключиться к хранилищу по HTTP и попробовать сделать то же самое. Должно быть ещё быстрее, как ни странно :)
7. kamisov 216 18.08.22 22:26 Сейчас в теме
Плагин “increment” у гитсинка был включён?

И временную базу гитсинку, видно, не указывали для выгрузки. Тоже просаживается скорость от этого.
Оставьте свое сообщение