Фоновые задания в 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 хранилище

См. также

Системы контроля версий для 1С-разработчиков.

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

Основы командной разработки на 1С. Использование систем контроля версий при разработке на платформе 1С:Предприятие 8

4900 руб.

29.06.2022    9460    78    4    

112

Обновляемый список последних статей Инфостарт для профиля Github

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

Не знаете, чем бы таким заполнить свой профиль Github? Заполните его своими статьями на Инфостарт! Этот простой workflow сам соберет список ваших последних статей и будет периодически обновлять его для актуализации данных.

08.04.2024    946    bayselonarrend    2    

31

Процесс разработки с использованием GIT и расширений для 1С:ERP. Без EDT

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

Доработки 1С:ERP на крупных проектах можно организовать, не внося изменения в саму типовую конфигурацию, а используя только расширения и отдельные «микроконфигурации». Расскажем о том, как это сделать без EDT, используя процесс разработки GitHub Flow.

02.04.2024    5005    Begemoth80    24    

45

Особенности национального Workflow: Github Actions и OneScript

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

Сегодня мы посмотрим на Github Actions - встроенный инструментарий Github для автоматизации рабочих процессов. Разберем, что это такое, зачем и причем тут OneScript.

25.03.2024    1614    bayselonarrend    3    

38

Автоматизация процесса разработки с помощью сервиса GitFlic

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

GitFlic – первая в России полностью самостоятельная реализация сервиса для хранения репозиториев с исходным кодом. За три года разработки сервис GitFlic стал полноценным инструментом, которым можно заменить GitLab, GitHub и BitBucket. Расскажем о том, как выстроить в GitFlic процесс автоматического тестирования, статического анализа кода и сборки приложений.

05.03.2024    2127    user1989937    6    

16

OpenYellow - рейтинг открытых GitHub репозиториев для платформы 1С:Предприятие

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

Обновляемый топ GitHub репозиториев для 1С по всем языкам программирования и еще немного рассуждений про open-source.

05.02.2024    4081    bayselonarrend    15    

63

Насколько глубок 1С-ный GitHub?

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

Open-source проекты - важная часть мира программного обеспечения. 1С привычно держится немного в стороне от глобальных трендов, но бросить холодный статистический взгляд на положение дел мне показалось небезынтересным.

22.01.2024    8121    bayselonarrend    50    

87

TCP прокси-сервер хранилища конфигурации 1С

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

Продолжение истории с прокси хранилища, но уже не на HTTP, а на TCP и без падений по памяти веб-сервера. Проверяем комментарии хранилища, вызываем веб-хуки, старты пайплайнов, gitsync по событию помещения версии в хранилище. И все это полностью на знакомом и понятном OneScript.

17.01.2024    3062    kamisov    17    

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

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

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

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

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