[Из песочницы] 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 с, и без транзакции

kHlllUV.png

D4R8Kgu.png

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

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

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

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

5VOArkb.png

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

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

aEefn9S.png

Вычислить среднее значение

i426mX1.png

Вычислить стандартное отклонение

gMo7jpD.png

Определить существование статистически достоверной разницы между выборками с помощью ttest (подтверждение или опровержение нулевой гипотезы)

enDqMAY.png

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

tt9aMaI.png

3Hdz0re.png

Выводы:

  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/cashpositive/the-hitchhikers-guide-to-mongodb-transactions-with-mongoose-5bf8a6e22033
blog.yugabyte.com/are-mongodb-acid-transactions-ready-for-high-performance-applications
medium.com/@Alibaba_Cloud/multi-document-transactions-on-mongodb-4–0-eebd662ac237
www.mongodb.com/blog/post/mongodb-multi-document-acid-transactions-general-availability
docs.mongodb.com/manual/core/write-operations-atomicity
www.dbta.com/Columns/MongoDB-Matters/Limitations-in-MongoDB-Transactions-127057.aspx
dzone.com/articles/multi-document-transactions-on-mongodb-40
www.dbta.com/Columns/MongoDB-Matters/MongoDB-Transactions-In-Depth-125890.aspx
www.codementor.io/@christkv/mongodb-transactions-vs-two-phase-commit-u6blq7465
docs.mongodb.com/manual/core/read-isolation-consistency-recency
mathworld.wolfram.com/Outlier.html
support.minitab.com/en-us/minitab-express/1/help-and-how-to/basic-statistics/inference/how-to/two-samples/2-sample-t/interpret-the-results/key-results

© Habrahabr.ru