ОСОБЛИВОСТІ БАГАТОПОТОКОВОЇ ОБРОБКИ ДАНИХ У ДОДАТКАХ, ПОБУДОВАНИХ НА БАЗІ NODE.JS
23.09.2021 21:42
[1. Information systems and technologies]
Author: Соботник Е.Л., магістр, кафедра інженерії програмного забезпечення, Івано-Франківський національний технічний університет нафти і газу;
Юрчишин В.М., доктор технічних наук, професор, кафедра інженерії програмного забезпечення, Івано-Франківський національний технічний університет нафти і газу
Багатопотокова обробка даних (англ. Multi-data-stream processing) —програмний та/або апаратний спосіб побудови архітектури обладнання, що дає змогу здійснювати одночасне оброблення двох або більше послідовностей даних під керуванням однієї або більше послідовностей команд.
Із проблемами багатопотокової обробки даних стикаються постійно через перевантаженість інформаційних систем файлами великих розмірів та невірний підхід до їх обробки, оскільки при цьому виникають збої у роботі програмного забезпечення. Саме проблему завантаженості програмного забезпечення у своїй праці «Node.js: Using JavaScript to Build High-Performance Network Programs» висвітлили Stefan Tilkov та Steve Vinoski [1]. Вони продемонстрували різні архітектурні підходи щодо організації опрацювання складної навантаженої бізнес-логіки для додатків різної складності.
Розглянемо загальний принцип обробки файлів великих розмірів засобами Node.js. Node.js спроектований для побудови масштабованих мережевих додатків. Те що Node.js спроектований без багатопоточності, не означає, що його можливості не можна використовувати для кількох ядер. Node.js був створений як експеримент для асинхронної обробки даних. Ідея полягала в тому, що асинхронна обробка в одному потоці може забезпечити більшу продуктивність і масштабованість для типових веб-навантажень, ніж типова реалізація на основі потоків.
Платформа Node.js підтримує обробку файлів, проте зчитування файлів великих розмірів потребує багатопотокової обробки, оскільки така операція є синхронною, то і файли еликих розмірів призведуть до завантаженості однопотокових процесів та ефекту «зависання» через брак оперативної пам’яті, виділеної середовищем виконання програмного забезпечення.
На рис. 1 зображена найпростіша операція зчитування інформації з файлу. Так, такий спосіб цілком підходить для файлів невеликих розмірів. Дослідження показали, що максимально можливий розмір файлу для обробки таким способом не повинен перевищувати 512 МБ для 32-бітних систем та до 1024 МБ для 64-бітних систем відповідно [2].
Рисунок 1 – Загальний вигляд оператора зчитування файлу
Проте, при перевищенні даного обмеження інформаційна система потрапляє під ризик, а саме некоректну роботу та й можливе аварійне завершення роботи програмного забезпечення в цілому. Щоб вирішити проблему обробки файлів великих розмірів необхідно звернутися до API Node.js та дізнатися інші способи опрацювання файлів засобами даної платформи. Оскільки платформа Node.js розглядає файл як окремий потік, то, відповідно, надає можливість завантажити будь-який файл частинами (чанками), що можна спостерігати на рис. 2.
Рисунок 2 – Загальний вигляд оператора зчитування файлу частинами.
В цілому, такий спосіб міг би і підійти, проте, на жаль, під час зчитування файлів необхідно виконувати певні асинхронні операції, наприклад калькуляція параметрів та подальше їх збереження у базу даних чи групування за певними критеріями і розповсюдження інформації різними засобами зв’язку, зокрема через електронні скриньки. Оскільки, як раніше було зазначено, зчитування файлу є синхронним, то програмне забезпечення не буде «очікувати» виконання асинхронних операцій. Тож якщо частин файлу буде багато, то це призведе до швидкого заповнення стеку процесу і до унеможливлення подальшої роботи інформаційної системи. Такий спосіб чудово підходить тільки для синхронних операцій. Проте розробники платформи передбачили можливість виконання асинхронних операцій при зчитуванні файлів великих розмірів. Для цього необхідно використовувати додатковий інструмент stream.pipe (див. рис. 3).
Рисунок 3 – Загальний вигляд оператора асинхронного зчитування файлу частинами.
Як бачимо, такий оператор дозволяє об’єднувати потрібні потоки та формувати складну бізнес-логіку, що залежить від попередніх результатів потоків, що виконувалися. Щоб головний потік міг правильно «спілкуватися» та керувати усіма іншими потоками (дочірніми потоками), необхідно щоб вони реалізовували спеціальну поведінку, а саме метод _transform, що приймає у собі як вхідні аргументи: частину файлу, його кодування, та функцію-callback done, яка повинна сповістити батьківський потік про завершення обробки інформації, а також у разі помилки повідомити про неї. Такий підхід дозволить накладати потоки один на одного, щоб вибудувати архітектуру ланцюга. Цей ланцюг допоможе розділити логіку складних ресурсозатратних операцій на дрібніші функціональні одиниці. Відомо, що при виконанні програмного забезпечення можуть виникати як помилки передбачені бізнес-логікою, так і аварійні непередбачувані помилки. Спосіб «сповіщення» головного потоку про виникнення помилки нами було розглянуто вище, проте варто згадати, що платформа Node.js дозволяє відловити будь-яку помилку, що виникає під час багатопотокового опрацювання інформації та виконати необхідні дії. Зазначимо, що Node.js не зупиняє усі дочірні потоки батьківського потоку при виникненні принаймні однієї помилки, саме тому інженерам програмного забезпечення надважливо є коректне завершення роботи усіх дочірніх потоків, щоб уникнути непередбачуваних витоків пам’яті. З версії Node.js 10.x була додана можливість автоматичного відлову помилок та закриття усіх дочірніх потоків за рахунок використання нового методу pipeline (див. рис. 4), що дозволяє аналогічно комбінувати потоки, але з можливістю відстеження виконання усіх потоків, а також зчитування можливих помилок.
Рисунок 4 – Загальний вигляд оператора pipeline.
Отже, шляхом вирішення проблеми опрацювання файлів великих розмірів з можливістю виконання асинхронних операцій є розбиття на потоки, які відповідають за свою частину файлу та передають інформацію далі по основному потоці, що було зображено на рис. 3 та рис. 4. Такий підхід дозволяє будувати складну бізнес-логіку, а також забезпечить подальшу масштабованість будь-якої інформаційної системи. Перспективою подальшого дослідження даної предметної області є її поширення серед сучасних додатків, які виконують обробку інформації файлів засобами Node.js задля покращення архітектури додатків, уникнення збоїв та пришвидшення роботи.
Список використаних джерел:
1. Tilkov S, Vinoski S. Node. js: Using JavaScript to build high-performance network programs. IEEE Internet Computing. 2010 Nov 1;14(6):80-3.
2. https://askinglot.com/how-much-memory-can-node-js-use