Как стать автором
Обновить

Node.JS и выгрузка каталога из 1С на сайт

Время на прочтение 4 мин
Количество просмотров 36K
На днях закрыли очередной проект. Суть: создание новой версии интернет-каталога. Старая версия сайта, в силу ряда причин, клиента не устраивала. Особенностью проекта была его номенклатурная база. Объём номенклатуры каталога составлял ~26000 позиций раскиданных по дереву из 513 узлов + характеристики товара. Почти каждая номенклатурная позиция имела описание на 1-2К текста.

Файл выгрузки каталога в формате ComerceML 2 для старого сайта весил 104 MB. Формировался на стороне 1С 10 минут и после передачи на хостинг, парсился на стороне сайта полтора часа (!) со 100% загрузкой CPU.

Выход из ситуации


В качестве альтернативы XML формату решили выгрузить в JSON. Идея была в том, чтобы попробовать разобрать JSON чем-то, что имеет нативную реализацию парсера, а именно node.js с его JSON.parse().

Наш 1С-ник, разобравшись с новым для него форматом, в несколько итераций добился того, что выгрузка 1С формировала валидный JSON. Время формирования выгрузки сократилось с 10 до 3.5 минут. Те же данные которые в XML формате занимали 104 мегабайта, уместились в 58 мегабайт JSON. Но это было ожидаемо, неожиданностью стало другое…

Для тестирования времени разбора выгрузки я набросал тестовый код:

// Node.js

var fs = require('fs');

function parser(filename, callback){

    fs.readFile(filename, { encoding:'utf8' }, function(err, dataFromFile){
        var parsedData;

        if(err){
            callback(err);
        } else {
            try {
                console.time('parse data'); // парсинг - синхронная операция...
                parsedData = JSON.parse(dataFromFile.toString().trim()); // <- собственно сам парсинг.
                console.timeEnd('parse data'); // ... поэтому измеряем задержку "в лоб".

                callback(null, parsedData ); 
            }
            catch (e){
                callback(e)
            }
        }

    });
}

parser('../import/import.json', function(err, data){

    if(err){
        throw (err);
    }

    console.log('groups', data.groups.length);
    console.log('items', data.items.length);
    console.log('properties', data.properties.length);
});

Запустив его на своей машине (CPU 3.3GHz), я даже не успел привстать чтобы пойти за чаем. Результат и скорость с которой он был выведен в консоль, заставил меня предположить, что в коде баг и он не отработал корректно…
> node parse.js

parse data: 718ms
groups 513
items 26098
properties 149

Но это был не баг. Данные действительно были разобраны и помещены в память за ⅔ секунды. Количество элементов в коллекциях полностью совпадало с заявленным количеством в 1С. Оставалось только найти под столом отпавшую челюсть и написать сервис с полным циклом обработки данных.

Общая архитектура сервиса обработки выгрузки


В целом выгрузка на сайт отрабатывает по стандартной схеме:
  • формирование выгрузки из 1С и его упаковка архиватором;
  • загрузка сформированных файлов по FTP;
  • вызов обработчика выгрузки по HTTP;


Сервис обработчика выгрузки реализован по схеме:
  1. распаковывать архив;
  2. распарсить JSON;
  3. сообщить в HTTP ответе что всё впорядке или произошла ошибка;
  4. если всё хорошо — выставить флаг занятости и заливать данные в базу до победного конца;
  5. умереть очистив память.
  6. Возродиться новым процессом — за это отвечает Monit.


На продакшене (DigitalOcean, тариф за $10), с момента вызова и до пункта 3 сервис отрабатывает в целом через 3-4 секунды, после чего повторный вызов сервиса будет возвращать флаг занятости пока заливается база. Весь цикл обработки выгрузки с занесением данных в базу составляет 80 — 90 секунд. Загрузка процессора в момент парсинга выглядит как единичный пик до 70% с основанием в 10 — 30%.

В итоге:
  • время формирования выгрузки сократилось с 10 до 3.5 минут;
  • объём выгрузки сократился со 104 до 58 мегабайт (1.5 мегабайта после архивации);
  • полное время обработки выгрузки на стороне сервера сократилось с полутора часов до полутора минут;
  • ???????
  • PROFIT


P.S. Средство от головной боли при отладке.


При всей своей скорости JSON.parse() очень неудобен для отладки. В случае наличия ошибки в структуре JSON, вы получаете практически ноль отладочной информации. Пока ваш 1С специалист осваивает JSON, очень выручает модуль JSON Lint. Он может быть использован как отдельная утилита или в качестве библиотеки. В отличии от штатного парсера он сообщает в объект исключения номер строки JSON-файла где произошло недоразумение, что при разборе косяков в файле в десятки мегабайт кардинально облегчает жизнь. Цена за такое удобство — скорость. Она упадёт в 5-7 раз по сравнению с нативным JSON.parse().

Тот же тестовый код с JSON Lint будет выглядеть так:

// Node.js

var fs = require('fs'),
    jsonlint = require("jsonlint"); // Очень полезен на этапе отладки

function parser(filename, callback){

    fs.readFile(filename, { encoding:'utf8' }, function(err, dataFromFile){
        var parsedData;

        if(err){
            callback(err);
        } else {
            try {
                console.time('parse data'); // парсинг - синхронная операция...

                /* Используем Jsonlint если нам нужна более подробная информация о месте ошибки в структуре JSON.
                * Работает медленнее в 5-7 раз чем нативный JSON.parse().
                 */
                parsedData = jsonlint.parse(dataFromFile);  // тот же парсинг, но с дебагом и поэтессами.

                console.timeEnd('parse data'); // ... поэтому измеряем задержку "в лоб".

                callback(null, parsedData );
            }
            catch (e){
                callback(e)
            }
        }

    });
}

parser('../import/import.json', function(err, data){
    if(err){
        throw (err);
    }
    console.log('groups', data.groups.length);
    console.log('items', data.items.length);
    console.log('properties', data.properties.length);
});


В заключение хочу традиционно пожелать, чтобы этот материал был ещё кому-нибудь полезен также как был полезен нам.
Теги:
Хабы:
+25
Комментарии 30
Комментарии Комментарии 30

Публикации

Истории

Работа

Ближайшие события

PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн
Weekend Offer в AliExpress
Дата 20 – 21 апреля
Время 10:00 – 20:00
Место
Онлайн