Node.js + MongoDB: перформанс транзакцій

«Іноді ми платимо найбільше за те, що отримуємо безкоштовно» — А.Ейнштейн

Не так давно в MongoDB версії 4+ з’явилась підтримка мульти-документних транзакцій.

А оскільки наш проект якраз мігрував на версію 4.2, закономірно виникли запитання:

  • Що буде з перформансом?
  • На скільки операції сповільняться?
  • Чи готові ми пожертвувати швидкістю заради (хоч якоїсь) точності?

Під час вивчення документації та інтернетів питань тільки побільшало:

  • Чи всі операції буде сповільнено за рахунок транзакцій?
  • На скільки буде сповільнено комбінації операцій?

Давайте спробуємо дати відповіді на ці запитання.

Для того, щоб претендувати хоча б на якусь мізерну долю істини — доведеться трохи попрацювати. Для простоти сприйняття розділю імплементацію на 3 кроки:

  1. Вибір інструментів
  2. Опис комбінацій операцій та отримання результатів
  3. Аналіз результатів

Тепер про кожен окремий крок детально.

Вибір інструментів:

  1. Необхідна тестова MongoDB (репліка з мінімільною кількістю mongod процесів) і драйвер для неї: mongodb-memory-server, mongodb.
  2. Для простоти вимірювання часу я обрав модуль «microseconds»
  3. Для аналізу отриманих результатів та візуалізації використаємо наступне: ttest, stdlib.

Опис комбінацій операцій та отримання результатів:

Імплементуємо кожну (із основних) окрему операцію insertOne, updateOne, deleteOne, findOne, insertMany*, updateMany*, deleteMany*, find* та їх комбінації insertOne + updateOne + deleteOne, insertOne + updateOne + deleteOne + findOne, insertMany* + updateMany* + deleteMany*, insertMany* + updateMany* + deleteMany* + find* з, та без використання транзакцій.

Вимірюємо час виконання кожної операції.

Для прикладу — insertMany + updateMany + deleteMany з, та без транзакції

Кожну операцію/вимір повторимо 300 разів (для аналізу будемо використовувати 100 результатів «посередині», тобто з 101-го по 200-ий)** — назвемо це «мікроітераціями» (ітераціями окремих операцій чи комбінацій).

Тепер, постійно змінюючи послідовність, проведемо 100 «макроітерації» (1 «макроітерація» = загальна кількість «мікроітарацій» * 300)*
* кількість 300 обрано абсолютно емпірично
** для більш повної інформації про імплементацію запрошую відвідати github репозиторій (посилання нижче по тексту)

Аналіз результатів:

В результаті всіх ітерацій ми отримали 20000 замірів для кожної операції та комбінації операцій (10000 з використанням транзакції, 10000 — без) у вигляді масивів

Далі необхідно провести деякі обчислення.

Обрізати результати, які явно випадають за межі вибірки

Вирахувати середнє значення

Знайти стандартне відхилення

Визначити існування статистично достовірної різниці між вибірками за допомогою ttest (підтвердження або спростування нульової гіпотези)

Візуалізуємо результати за допомогою простих графіків. Для прикладу візьмемо комбінацію insertMany + updateMany + deleteMany та окремо insertOne (всі інші результати будуть викладені в текстовому форматі в розділі «Висновки»). В результаті у згенерованих html-файлах маємо графік, назва якого відповідає назві операції чи комбінації операції (бірюзовим кольором позначені безтранзакційні ітерації, оранжевим — транзакційні). «Is statistically significant» (true/false) говорить про те, чи була взагалі якась статистично значима різниця. Все інше — абсолютні та відносні значення в мікросекундах та відсотках відповідно.


Висновки:

  1. Взагалі, це не має ніякої різниці між операціями з використанням транзакцій і без: insertMany + updateMany + deleteMany (шукайте ілюстрацію вище)
  2. Існує невелика різниця (до 7%): updateMany, find, insertOne + updateOne + deleteOne + findOne, insertMany + updateMany + deleteMany + find
  3. Транзакції проходять повільніше, але не так критично (до 91%): updateOne, deleteMany, findOne
  4. Транзакції значно повільніші (від 197% до 792%): insertOne, insertMany, deleteOne, insertOne + updateOne + deleteOne

Щоб отримати додаткову інформацію та мати можливість перевірити результати, запустивши сценарії самостійно, відвідайте github.

Дякую за те, що прочитали.

Не соромтесь коментувати, сподіваюся, що у нас буде хороша дискусія.

Також ви можете запустити все це самостійно і отримати власні результати. Буде круто їх порівняти

Корисні посилання:
medium.com/...​ith-mongoose-5bf8a6e22033
blog.yugabyte.com/...​performance-applications
medium.com/...​-mongodb-4-0-eebd662ac237
www.mongodb.com/...​ions-general-availability
docs.mongodb.com/...​ite-operations-atomicity
www.dbta.com/...​-Transactions-127057.aspx
dzone.com/...​ransactions-on-mongodb-40
www.dbta.com/...​ions-In-Depth-125890.aspx
www.codementor.io/...​wo-phase-commit-u6blq7465
docs.mongodb.com/...​tion-consistency-recency
mathworld.wolfram.com/Outlier.html
support.minitab.com/...​-the-results/key-results

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному1
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Хм 2020 и до сих пор еще ноду тащат в прод... её удел где-то в вебпаках крутиться . Давным-давно выкинули ноду и переехали на джаву и Го, держат отличный rps, а не это гуано, каждый год обрастающее ворохом костылей

Так-то вопрос про транзакции и базу данных, а откуда её упражнять — из ноды, Java или Go — вопрос десятый.

Давным-давно выкинули ноду и переехали на джаву и Го,

в 2020 переехали на джаву :)

Чет мне подсказывает что тест у вас некорректный, ибо я не понимаю как insertMany может быть намного медленнее, updateOne и deleteMany просто медленнее, при этом они в связке (insertMany updateOne deleteMany) вдруг магическим образом работать так же, как и без транзакций.

Для мене результати також в деякій мірі стали несподіваними. Але врахуйте, що досліджувались лише відношення між операціями і їх комбінаціями з аналогічними операціями/комбінаціями, але уже з використанням транзакцій. Не було жодного намагання порівняти операції між собою. Також не відкидаю можливості наявності помилки у будь-якому з тестів, тому якщо така буде виявлена — готовий виправити і повторити виміри

Хайп с nosql уже давно утих. Нормальные люди делают на реляционных бд.

Увы, не везде.
Есть компании где носкль+микросервисы это священная корова и сильвер пуля в одном до сих пор.

никогда не поздно сменить компанию)
И да, связка нода + монга уже морально устарела, прошел хайп ноды и хайп монги. Постгрес выруливает, а для аналитических данных есть отличные колоночные базы типа clickhouse, которые пережевывают огромные объемы данных не глядя. Та и distributed transaction весьма щекочущее нервы удольствие, особенно когда в проде блокировки начинают друг друга ожидать

Постгрес выруливает, а для аналитических данных есть отличные колоночные базы типа clickhouse

Вот! Плюсану нещадно :) У кликхауса, правда, есть нюансы с правкой данных задним числом, как минимум, на merge tree / aggregating merge tree движках, но то детали.

Так LSM как структура данных в принципе append-only.

Нормальные люди всегда делали то что надо на реляционных — на реляционных, а то что надо на носиквеле — на носиквеле.

Оно то так.
Вот только есть категория людей которые до сих пор хайпят монгу и у которых дефолтная архитектура начинается с монги для любых решений просто потому что носкль.

А те, що без бази — без бази

откройте описание любой вакансии из реальной жизни
и все будет наоборот, бизнес данные — в nosql, а к примеру, метрики из zabbix — в sql

я бы держался подальше от таких вакансий, если там проблемы с архитектурой, и не собираются это переделывать. Зачем этот лишний головняк, будут вечные нерешаемые проблемы решаемые очередной грудой костылей

Реляційні СУБД — це ACID транзакції, блокування, довідкова цілісність і багато іншого, що гальмує операції. Тому при всіх інших рівних параметрах NoSQL буде працювати швидше.

неверно, любую базу, самую лучшую, можно уронить неправильной структурой данной и кошмарными запросами. Это старый хайповый тренд, SQL vs NoSQL, который только на реальном проекте уже решается грматотным проектированием. Даже часть данных хранят в реляционке, а другие виды данных кидают в другие движки баз, где точность выборки не сильно критична и транзакции не нужны

Про транзакції: jepsen.io/analyses/mongodb-4.2.6

Підписатись на коментарі