Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

Порівнюємо продуктивність MongoDB та Cosmos DB в Azure

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

Мене звати Юрій Івон, я співпрацюю з компанією EPAM як Senior Solution Architect. Багато проєктів зараз обирають Cosmos DB як базу даних, але не завжди цей вибір добре вмотивований. Мені багато доводилося працювати з цією технологією і я хотів би поділитись деяким досвідом, а саме показати, яку продуктивність можна очікувати від різних варіантів Cosmos DB і чи завжди вона виграє у звичайної MongoDB. Окрім цього, поділюся своєю утилітою для проведення тестів продуктивності баз даних — Database Benchmark, яка може допомогти у виборі технології для ваших проєктів.

Коли треба зберігати інформацію в документо-орієнтованій базі даних, перша технологія, що спадає на думку — це MongoDB. Зараз уже є багато альтернатив, але коли ми працюємо в хмарному середовищі, вибір зазвичай обмежений platform-as-a-service рішеннями, тому що DevOps підтримка баз, що задеплоєні на віртуальних машинах, видається значно дорожчою. Azure пропонує дуже цікаве рішення для баз даних — Cosmos DB, яке, окрім свого SQL API, підтримує MongoDB API та ще декілька інших, таких як Cassandra або Gremlin.

Крім цього, Cosmos DB має ще декілька потужних можливостей: висока доступність, дуже просте керування георозподілом, можливість запису в декількох регіонах одночасно, автоматичне індексування тощо. З усіма цими фактами, Cosmos DB API for MongoDB виглядає дуже привабливо: з одного боку, ви отримуєте всі переваги Cosmos DB, з іншого — ваше рішення залишається незалежним від конкретних хмарних провайдерів. Чи можуть бути якісь непередбачувані проблеми з таким підходом?

Одне з найважливіших питань, яке тут треба розглянути — це продуктивність. Неможливо без реальних тестів зрозуміти, наскільки швидка Cosmos DB API for MongoDB у порівнянні зі «справжньою» MongoDB чи Cosmos DB SQL API. І щоб краще зрозуміти цей аспект, зробимо декілька тестів на основі моєї утиліти Database Benchmark для наступних варіантів баз даних:

  • Cosmos DB API for MongoDB 4.0 — цю версію Azure пропонує за замовчуванням, коли ви створюєте новий аккаунт Cosmos DB API for MongoDB.
  • Cosmos DB API for MongoDB 3.6 — багато проєктів усе ще використовують цю версію, і я хочу зрозуміти, чи вплине на швидкість виконання запитів перехід на наступну.
  • Cosmos DB SQL API
  • MongoDB 4.2 на віртуальній машині під Linux — старіша версія обрана навмисно, щоб уникнути скарг про нечесне порівняння. Водночас ви маєте розуміти, що Cosmos DB і звичайний MongoDB усередині дуже різні, і версія тут просто вказує рівень сумісності API.

В усіх тестах будемо використовувати набір даних, який містить п’ять мільйонів рядків.

Запити:

  • Запит сторінки з діапазоном дат в умові — повертає перші 100 документів, відсортовані за датою замовлення та відфільтровані за випадковою країною, випадковим діапазоном дати замовлення та фіксованими критеріями для деяких інших полів.
  • Запит «прочитати все» з діапазоном дат в умові — такий самий запит, як і попередній, але без сортування і обмеження кількості документів.
  • Запит сторінки без діапазону дат в умові — повертає перші 100 документів, відсортовані за датою замовлення та відфільтровані за випадковою країною, випадковим типом товару та фіксованими критеріями для деяких інших полів.
  • Запит «прочитати все» без діапазону дат в умові — такий самий запит, як і попередній, але без сортування і обмеження кількості документів.
  • Запит з агрегацією — фільтрує набір даних за випадковою країною, випадковим діапазоном дати замовлення і групує його за типом товару для того, щоб розрахувати кількість документів та загальну кількість проданих одиниць для кожної з груп.

Умови тесту

  • Всі ресурси, які є в тесті, належать до одного регіону Azure (East US).
  • В тесті «справжньої» MongoDB, сервер бази даних і тестова утиліта належать до окремих віртуальних машин.
  • Обидві віртуальні машини мають форму D2s v3 (2 ядра, 8 GB RAM).
  • В усіх сценаріях з Cosmos DB, контейнер даних має тільки один розділ з максимально можливою пропускною здатністю в 10000 RU. Я поділюсь деякими думками на тему розділів наприкінці статті.
  • Сценарії для кожного запиту складаються з трьох запусків: 1, 10 і 20 паралельних потоків. Кожен запит виконується 500 разів на кожному з потоків.
  • Тестова утиліта використовує найновіші версії клієнтських .NET бібліотек для баз даних, що беруть участь у цьому дослідженні. Жодних змін до їхніх налаштувань за замовченням не зроблено.

Індекси

Cosmos DB і звичайна MongoDB побудовані на фундаментально різних механізмах індексації, тому є сенс пояснити деякі речі перед тим, як перейти до результатів.

Припустимо, що в нас є три поля, які ми використовуємо для фільтрації: Country, ItemType та OrderDate. Щоб покращити швидкість наших запитів ми створили три індекси — по індексу на кожне поле.

Звичайна MongoDB в основному використовує традиційні B-tree індекси, тобто якщо ми маємо запит з усіма трьома полями в умові, насправді тільки один індекс може бути задіяний, а всі інші предикати буде застосовано під час сканування індексу. Наприклад, колекція може містити мільйон документів для Великобританії, три мільйони з типом продукту «Одяг» і два мільйони — для вказаного діапазону дат, але тільки десять тисяч — для такої комбінації предикатів. З традиційним B-tree індексом база буде сканувати щонайменше мільйон документів щоб знайти всі відповідні результати. Або може навіть вирішити, що дешевше буде не використовувати індекси, а профільтрувати всю колекцію документів безпосередньо.

Ви завжди можете створити складений індекс для найчастіших комбінацій предикатів (наприклад, Country та ItemType), який значно покращить продуктивність у випадку, коли всі його компоненти є в умові запиту. Однак, створення складених індексів для усіх можливих комбінацій є непрактичним. Зазвичай додають тільки декілька, щоб покрити найтиповіші сценарії.

Cosmos DB, незалежно від зовнішнього API, використовує інвертовані індекси. На високому рівні, інвертований індекс можна уявити як словник, який містить список посилань на відповідні документи для кожної комбінації шляху до поля та його значення (мається на увазі саме шлях, а не просто ім’я, тому що документи можуть містити вкладені об’єкти). Якщо ми проіндексуємо всі три поля, і потім зробимо запит з усіма ними в умові, база зможе знайти списки посилань на документи для всіх вказаних пар шлях-значення і отримати їх перетин. На низькому рівні є багато оптимізацій цього механізму, які роблять інвертовані індекси дуже ефективними в обробці різноманітних комбінацій предикатів в запитах.

Як ви бачите, такий підхід не потребує складених індексів для прискорення пошуку відповідних документів, і будь-яка комбінація наших предикатів може бути покрита включенням всіх трьох до індексу. Тим не менш, Cosmos DB має складені індекси, але для інших цілей — для підтримки сортування по декількох полях. Ми не будемо експериментувати з ними в цих тестах.

Cosmos DB також підтримує «шаблонні» індекси, які дозволяють вказувати не конкретні поля, а шаблони шляхів до полів. Особливим випадком тут є шаблон, якому відповідає будь-яке поле в документі — я надалі буду називати його «повним індексом». З одного боку, він значно дорожчий для змін в даних, ніж «вибіркові» індекси, але, з іншого боку, може прискорити запити незалежно від їх критеріїв.

Для усіх тестів в цій статті я буду дотримуватись простого підходу до індексування:

  • Для будь-якого варіанту Cosmos DB, тестуватись будуть і повний і вибірковий індекси.
  • Для кожного запиту в звичайній MongoDB я створю складений індекс, який, на мою думку, найкраще підходить до сценарію і водночас не є надмірним.

Результати

Запит сторінки з діапазоном дат в умові

Цей запит має такий SQL-еквівалент:

SELECT
    *
FROM
    Sales
WHERE
    Sales.Country = @Country 
    AND Sales.OrderDate >= @OrderDateFrom 
    AND Sales.OrderDate < @OrderDateTo
    AND Sales.SalesChannel = @SalesChannel 
    AND Sales.UnitsSold > @UnitsSoldFrom 
ORDER BY
    Sales.OrderDate DESC
OFFSET 0
LIMIT 100

Параметри SalesChannel та UnitsSoldFrom фіксовані для всіх запусків, а Country, OrderDateFrom, та OrderDateTo — рандомізовані.

Зверніть увагу, що метрика «request charge» актуальна тільки для Cosmos DB, тому відповідні графіки не включають MongoDB встановлений на віртуальній машині. Більше інформації про те, що таке Request Unit (RU) можна знайти в моїй попередній статті.

На діаграмі вище можна побачити досить цікаві результати:

  • MongoDB встановлена на дешевій віртуальній машині швидша за будь-який з варіантів Cosmos DB.
  • Індекси на окремих полях дають кращу продуктивність, ніж повний індекс.
  • Cosmos DB SQL API швидший за MongoDB API, особливо з індексами на окремих полях.
  • Cosmos DB API for MongoDB 4.0 значно швидший, ніж 3.6 коли обидва використовують повний індекс, але з індексами на окремих полях обидві версії мають схожу продуктивність.

Запит «прочитати все» з діапазоном дат в умові

Основне призначення цього запиту — перевірити як різні бази обробляють великі обсяги даних, отриманих в одному запиті — він повертає близько 2200 документів в середньому. Його SQL еквівалент такий:

SELECT
    *
FROM
    Sales
WHERE
    Sales.Country = @Country 
    AND Sales.SalesChannel = @SalesChannel
    AND Sales.UnitsSold > @UnitsSoldFrom
    AND Sales.OrderDate >= @OrderDateFrom 
    AND Sales.OrderDate < @OrderDateTo

Аналогічно попередньому запиту, параметри SalesChannel та UnitsSoldFrom фіксовані для всіх запусків, а Country, OrderDateFrom, та OrderDateTo — рандомізовані.

Тут ми маємо трохи іншу ситуацію:

  • MongoDB встановлена на віртуальній машині все ще найшвидша. Я додав до результатів ще один запуск з більш потужною машиною для бази (D4s v3 що помножує ресурси вдвоє), щоб побачити наскільки добре вона піддається вертикальному масштабуванню. Таке невелике покращення може казати про те, що машина, яка виконує тести, теж вичерпує свої ресурси. Подальші перевірки показали, що це так, і збільшення потужності тестової машини покращує результати. Однак я вирішив не включати жодних результатів для інших конфігурацій тестової машини, щоб мати «спільний знаменник».
  • Cosmos DB SQL API набагато швидший в однопоточному сценарії, але відстає від MongoDB API під більшим навантаженням, не зважаючи на менші витрати одиниць запитів (Request Units). Це можна пояснити більшою ефективністю MongoDB протоколу та його .NET клієнту у порівнянні з Cosmos DB. Чесно кажучи, порівняння продуктивності клієнтів в цьому тесті не зовсім справедливе, тому що MongoDB плагін десеріалізує в BsonDocument, у той час як Cosmos DB — в стандартний .NET Dictionary. Тим не менш, подальше профілювання показує, що навіть з серіалізацією в один і той же POCO клас, клієнт Cosmos DB витрачає на 28% більше часу процесора на десеріалізацію одного мільйона документів і при цьому виділяє в 6.5 разів більше пам’яті загалом. Зверніть увагу, що остання цифра — про всі виділення пам’яті, які відбуваються під час операції читання даних, а не про фінальний об’єм.
  • У Cosmos DB API for MongoDB, повні індекси працюють ефективніше, ніж індекси на окремих полях. Cosmos DB SQL API витрачає менше одиниць запитів у випадку індексів на окремих полях, але реальні результати для обох варіантів індексу дуже схожі під великим навантаженням. Це може мати таке саме пояснення, як і попередній пункт.
  • Cosmos DB API for MongoDB 4.0 трохи швидший за 3.6.

Запит сторінки без діапазону дат в умові

Цей запит має такий SQL-еквівалент:

SELECT
    *
FROM
    Sales
WHERE
    Sales.Country = @Country 
    AND Sales.ItemType = @ItemType
    AND Sales.SalesChannel = @SalesChannel
    AND Sales.UnitsSold > @UnitsSoldFrom
ORDER BY
    Sales.OrderDate DESC
OFFSET 0
LIMIT 100

Параметри SalesChannel та UnitsSoldFrom фіксовані для всіх запусків, а Country та ItemType — рандомізовані.

Найбільша різниця у порівнянні з першим запитом полягає в поведінці Cosmos DB SQL API — він витрачає трохи більше одиниць запитів (Request Units) і є трохи повільнішим за будь-яку з версій Mongo DB API.

В іншому, результати відповідають тому, що ми бачили для першого запиту:

  • MongoDB встановлена на дешевій віртуальній машині набагато швидша за будь-який варіант Cosmos DB при умові, що відповідні індекси були створені.
  • Медіанна тривалість запитів для Cosmos DB SQL API майже не змінюється зі збільшенням кількості паралельних потоків, в той час як середня тривалість зростає.
  • Індекси на окремих полях дають більшу продуктивність, ніж повний індекс.
  • Cosmos DB API for MongoDB 4.0 трохи швидший за 3.6.

Запит «прочитати все» без діапазону дат в умові

Цей запит має такий SQL-еквівалент:

SELECT
    *
FROM
    Sales
WHERE
    Sales.Country = @Country 
    AND Sales.ItemType = @ItemType
    AND Sales.SalesChannel = @SalesChannel
    AND Sales.UnitsSold > @UnitsSoldFrom

Параметри SalesChannel та UnitsSoldFrom фіксовані для всіх запусків, а Country та ItemType — рандомізовані.

Оскільки запит повертає близько 1000 документів у середньому, результати дуже схожі на попередній «прочитати все»:

  • MongoDB встановлений на віртуальній машині — найшвидший, але з цим запитом тільки «подвійна» віртуальна машина виграє в усіх запусках.
  • Cosmos DB SQL API значно швидший в однопоточному сценарії, але відстає від Mongo DB API під навантаженням, не дивлячись на менші витрати одиниць запитів (Request Units). Як я вже писав, це можна пояснити більшою ефективністю .NET клієнта MongoDB.
  • Повні індекси дають вищу продуктивність, ніж індекси на окремих полях.
  • Хоча Cosmos DB API for MongoDB 4.0 витрачає трохи менше одиниць запитів (Request Units), ніж 3.6, відносна продуктивність цих двох версій нестабільна протягом тесту.

Запит з агрегацією

Цей запит має такий SQL-еквівалент:

SELECT
    Sales.ItemType,
    COUNT(1) OrderCount,
    SUM(Sales.UnitsSold) TotalUnitsSold
FROM
    Sales
WHERE
    Sales.Country = @Country 
    AND Sales.OrderDate >= @OrderDateFrom 
    AND Sales.OrderDate < @OrderDateTo)
GROUP BY
    Sales.ItemType

Зверніть увагу, що він не має ORDER BY, оскільки Cosmos DB SQL API не дозволяє мати ORDER BY та GROUP BY одночасно.

Параметри Country, OrderDateFrom, та OrderDateTo — рандомізовані.

Першим помітним результатом є падіння тесту Cosmos DB SQL API під час запусків в 20 потоків через перевищення відведеної пропускної здатності. Це може виглядати дивним, тому що метрика одиниць запиту (Request Units) нижча, ніж у декількох інших, які я вже тестував.

Коли загальна кількість одиниць запиту, витрачена паралельними запитами, перевищує відведену пропускну здатність (10000 RU на секунду в нашому випадку), база даних відповідає помилкою «Request rate too large». За замовченням, клієнтська бібліотека не кидає виняток одразу і повторює запит з деякою затримкою до 9 разів. І якщо дев’ята спроба дає таку саму помилку, клієнт кидає виняток. Кількість спроб, звісно, можна змінити, але ми використовуємо налаштування за замовченням.

Уявімо два запити, які витрачають однакову кількість RU, але мають різну тривалість. З них двох той, що займає менше часу, швидше вичерпає спроби і більш ймовірно викликає цю помилку. У порівнянні з усіма іншими запитами, раніше описаними в статті, варіант з агрегацією має найбільше співвідношення RU до секунд, тому ми і бачимо цю проблему.

Іншою важливою знахідкою є те, що Cosmos DB погано справляється з агрегаціями на великих наборах даних. Наприклад, виконання цієї агрегації без фільтру в запиті потребує близько 100000 RU з SQL API і близько 260000 — з Mongo DB API. Я помітив тільки одну оптимізацію під час перевірки сценаріїв з агрегацією — простий запит с «distinct» для поля Country по всій колекції даних бере тільки 140 RU в SQL API, в той час як Mongo DB API з’їдає близько 240000 RU (!).

Інші спостереження для цього випадка такі:

  • MongoDB встановлена на дешевій віртуальній машині — швидша за будь-який з варіантів Cosmos DB.
  • Cosmos DB SQL API швидший за MongoDB API.
  • Медіанна тривалість запитів для Cosmos DB SQL API майже не змінюється зі збільшенням кількості паралельних потоків, в той час як середня тривалість зростає.
  • Майже немає різниці між індексами на окремих полях і повним індексом.
  • Cosmos DB API for MongoDB 4.0 трохи швидший за 3.6.

Висновки

Наступна таблиця підсумовує найкращі результати часу виконання запитів в усіх тестах (в мілісекундах):

А ця таблиця — найкращі показники пропускної здатності (в запитах на секунду):

🔹MongoDB, встановлена на віртуальній машині, набагато швидша за будь-який варіант Cosmos DB, але це не означає, що її треба завжди використовувати. Є велика різниця в складності DevOps-підтримки між базою даних на віртуальних машинах і platform-as-a-service сервісом, таким як Cosmos DB. Якщо ви підете шляхом віртуальних машин, вашій DevOps-команді треба буде реалізовувати високу доступність, резервне копіювання, та масштабування на низькому рівні, а ще піклуватись про патчі безпеки. Бізнес може вимагати, щоб масштабування та встановлення патчів проходили без відключення всієї системи, що робить ситуацію ще складнішою.

Cosmos DB робить все це «під капотом» і дає адміністраторам просте керування цими функціями. MongoDB Atlas є альтернативним варіантом використання повноцінної MongoDB в Azure, але в мене немає з ним досвіду. Окрім набагато простішої реалізації та підтримки, Cosmos DB дає можливості, яких просто немає в звичайній MongoDB — запис в декількох регіонах одночасно, шаблонні індекси (повний індекс, який брав участь у тестах, є прикладом шаблонного). Немає універсального рецепту, тобто треба обирати технології з урахуванням потреб та обмежень бізнесу, беручі до уваги можливості, характеристики та обмеження технологій.

🔹Cosmos DB SQL API швидший за Cosmos DB API for MongoDB, але з деякими застереженнями. Якщо ваші запити повертають мегабайти даних за один раз, SQL API може працювати під навантаженням гірше за MongoDB API. Швидке дослідження показує, що .NET клієнт Cosmos DB витрачає більше процесорного часу і пам’яті для обробки такого самого набору документів. Запит сторінки без діапазону дат в умові працював трохи гірше з SQL API в паралельних сценаріях, але різниця не була настільки великою, щоб турбуватись.

🔹Cosmos DB погано справляється з агрегаціями на великих наборах даних. Не сподівайтесь реалізувати фасетний пошук на базі Cosmos DB, якщо ваша колекція буде містити більше, ніж декілька тисяч документів. Простий запит унікальних значень (distinct) схоже, що оптимізований в SQL API, в той час як MongoDB API показує дуже погані результати в цьому випадку. Існує спосіб вирішувати аналітичні задачі з даними в Cosmos DB, але це зовсім інша історія — Cosmos DB Analytical Store.

🔹Якщо продуктивність важлива для нового проєкту, я би не розглядав Cosmos DB API for MongoDB. Якщо є необхідність уникнути залежності від конкретного постачальника хмарних сервісів, я би абстрагував доступ до даних таким чином, щоб перехід на іншу технологію бази даних потребував змін тільки в невеликій частині коду. Буде помилкою думати, що міграція з Cosmos DB API for MongoDB на звичайну MongoDB буде безшовною: оскільки ці дві технології використовують абсолютно різні механізми індексації, міграція індексів «як є» може бути неможливою.

Щоб бути впевненим, що все працює добре, вам в будь-якому випадку треба буде робити тести продуктивності й коригувати налаштування індексів в залежності від результатів. Якщо все добре спроєктовано, зміна централізованого коду «стратегії доступу до даних» буде невеликою частиною зусиль витрачених на міграцію. В той же час, Cosmos DB API for MongoDB може бути корисною у випадку «lift-and-shift» — коли рішення переноситься з on-premise в Azure. Але майте на увазі, що звичайна MongoDB має набагато більше можливостей, тому не всі рішення можуть бути переключені на Cosmos DB API без змін в коді.

🔹Cosmos DB API for MongoDB 4.0 швидша за 3.6. Метрика одиниць запитів (Request Units) завжди краща у 4.0, і хоча є випадки коли 3.6 дає кращий час або кращу пропускну здатність, вони не є стабільно відтворюваними. Таким чином, має сенс запланувати перехід на нову версію, якщо ви все ще використовуєте 3.6. Досить важко передбачити ступінь покращення, адже він залежить від конкретних запитів, але в цьому тесті різниця коливалася від 0 до 50 відсотків.

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

🔹Стаття не покриває сценарії з багатьма розділами (partitioning), але я можу поділитись деякими думками на цю тему. Звичайна MongoDB може бути масштабована для читання або збільшенням кількості процесорів і оперативної пам’яті, або додаванням нових шардів і реплік, в той час як подальше масштабування Cosmos DB може бути досягнуто тільки додаванням нових розділів. Якщо б я розбив колекцію на логічні розділи за країнами, результати б не змінились, тому що фізичний розділ все одно був би тільки один. Нові фізичні розділи створюються автоматично, коли або існуючий досягає ліміту в 20 Гб, або коли нове значення пропускної здатності перетинає наступні 10000 RU. Наприклад, якщо в контейнері в 5 Гб та 10000 RU, буде тільки один фізичний розділ. Якщо ми дамо йому 10400 RU, то в ньому буде вже два фізичних розділи по 5200 RU кожен. Якщо ми дамо 30000 RU, то вже буде три фізичних розділи по 10000 RU. Кожні 10000 RU коштують близько 600 USD на місяць, в той час як базова віртуальна машина задіяна в цих тестах — тільки 70 USD на місяць.

Іншими словами — Cosmos DB легко масштабується, але це масштабування досить дороге. При великих обсягах, варіант з MongoDB на віртуальних машинах може виявитись дешевшим, навіть враховуючи додаткові витрати на DevOps. MongoDB Atlas теж може дати можливість знизити витрати при збереженні можливостей легкого масштабування.

🔹Хоча будь-які тести аналогічні цьому дають ідеї на тему того, що очікувати і на що звертати увагу, я рекомендую виконувати тести запитів, специфічних до вашого проєкту, перед тим як робити технологічне рішення. Моя утиліта Database Benchmark робить такі тести набагато простішими у порівнянні з написанням тестових програм з нуля.

Це переклад моєї статті з Medium.

👍ПодобаєтьсяСподобалось3
До обраногоВ обраному2
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

Дякую, але чому не було тестiв для Mongo 5 ?

Основний фокус був на різниці варіантів Cosmos DB і «аналогічної» MongoDB, а не на порівнянні різних версій MongoDB. Я би міг взяти MongoDB 5, але думаю, що були б коментарі в стилі «ну так монго на Космосі максимальна доступна 4.2, чому ми її порівнюємо з 5» :)

Привет, Юра. Спасибо за статью. Было бы интересно сравнить полученные результаты с PostgreSQL.
P.S. Ссылка на статью на Medium неработает — лишняя точка в конце URL’а.

Привет, Денис. Спасибо, исправил ссылку. Спойлер — PostgreSQL быстрее в таких тестах (если использовать обычные колонки, не JSONB) :)

Інші спостереження для цього випадка такі:

MongoDB встановлена на дешевій віртуальній машині — швидша за будь-який з варіантів Cosmos DB.
Cosmos DB SQL API швидший за MongoDB API.
Медіанна тривалість запитів для Cosmos DB SQL API майже не змінюється зі збільшенням кількості паралельних потоків, в той час як середня тривалість зростає.

Вы схоже робите перформанс тестування не для тих сценаріїв use cases для яких позиціонується використання космос.
docs.microsoft.com/...​azure/cosmos-db/use-cases
Тут переважно справа йде про:
— інтенсивний запис
— отримання данних по ключу

Загалом архітектура космос і підходи для роботи з ним мают більше відсилок до дизайну схеми данних і оперцій з ними як у Cassandra/Dynamo, а ніж rich document operations з Mongo..

Не дивлячись на те, як позиціонує Космос сам Майкрософт, я бачив багато проектів які її використуовують як звичайну документну базу. Наявність MongoDB API робить цей вибір ще «сліпішим». І одна з цілей статті — показати що не все так просто, і що можна очікувати від типових сценаріїв поза «запитом за айді»

я бачив багато проектів які її використуовують як звичайну документну базу.

і як эффективно з точки зору костів?

Наявність MongoDB API робить цей вибір ще «сліпішим».

на MSDN і в інтернетах можна знайти відгуки розробників Microsoft де доволі однозначно кажуть, що SQL api — це основний/нативний варіант використання технології, Mongo Api — для сумісності, на випадок міграції готового проекту у Azure, або якщо команда заточена під Mongo..

І одна з цілей статті — показати що не все так просто, і що можна очікувати від типових сценаріїв поза «запитом за айді»

Дивно що ви не порівняли перформанс, якщо читати по document key + partition key з сценарієм фільтрації агрегації у самому cosmos, щоб це показати.

З точки зору костів — дорого :). Один проект навіть переїхав на MongoDB Atlas через дороговизну і проблеми з перфомансом.

Не дивлячись на те, що написано в MSDN, багато хто дивиться на Cosmos DB API for MongoDB як варіант зробити Cloud-agnostic рішення використовуючі Azure.

Може колись зроблю додаткову статтю на тему пошуку в Cosmos DB за ки+партишен ки, але то буде порівняння вже зовсім інших технологій, чистий MongoDB для таких сценаріїв буде мати вже мало сенсу.

Можливо, Table API навіть більш нативніше)
але мені також здається що запис документа, читання документа, швидкість розподілення змін по регіонам, взагалі feature set по мультірегіонам, більше відображають use case. Інакше ми порівнюємо яка виделка краще працює як ложка)

Знову скажу, який би не був юзкейс, під який космос «заточений» — багато хто розглядає її як general-purpose документну базу і використовує її таким чином. Я ж не з теретичних міркувань ідею статті взяв, а з реальних проектів, які звертались за допомогою.

Соррі якщо це виглядало як критика.
Я розумію вашу точку зору і готовий погодитись що Cosmos, можливо, не ідеальна тулза для цих випадків.
але, думаю, моя точка зору також має право на життя ;)
Реально цікаво статья, і я якісь речі собі запам’ятав що треба дослідити.

хм, це одна пласка табличка...
цікаво, а як би себе повели postgresql чи mssql у подібних умовах?

а якщо інший варіант дати: декілька таблиць з даними і зробити бенч із join-ами для cosmos db, mongo та реляційної бд

а якщо інший варіант дати: декілька таблиць з даними і зробити бенч із join-ами для cosmos db, mongo та реляційної бд

у цих 3х база задача отримання зв’язанних данних має вирішуватися різними способами:
1. Cosmos — через запити до декілької коллекції по ключу/массиву ключів (об’єкт на query)
2. mongo — через денормалізацію і збереження данних в документі (об’єкт на ієрархію)
3. relational — через join (об’єкт на сутність)

у конкретних вихідних умовах кожен з варіантів може давати гірший\кращий перформанс та споживання ресурсів;

Да Cosmos та Монго ІМХО не для цього.
Як на мене use case це юзати Cosmos для регістрації OLTP даних та відправки далі за допомогою event sourcing в якусь реляційну чи не дуже БД вже для запитів.
Так ви получаєте максимальну швидкодію для OLTP і робите запити відносно реляційної бази, яка це зробить краще ніж Document DB.
Ще один use case це коли в вас невеликі партиції — наприклад юзер в якійсь соціальній мережі, робити запити відносно такого розміру доволі ефективно і партиції доволі рівномірно розподіляться між нодами за нагрузкою.
Робити OLAP запити в DocumеntDB це трохи як стріляти собі в ногу.) Але швидкодія все рівно цікава, бо вона транслюється і в меньші вибірки також.

Джойн в традиційному сенсі неактуален для документних баз. PostgreSQL на цих сценаріях швидший (мається на увазі звичайні колонки, не JSONB). MSSQL — не порівнював, але можете перевірити за допомогою моєї тули :)

Спасибо, что померяли производительность и сравнили.

Юзаем эту хрень т.к. другой manadged documentdb в azure не нашлось.
Еще с версии 3.2 отгребли проблем на ровном месте.
1. Индексирование на большой вложености объектов (5-7 уровней) — тупо падало при выборке со стектрейсом в ответе от azure и сюрприз-сюрприз в ответе был стектрейс sql exception
2. Были ограничения на количество индексов
3. Очень странно работает поиск по филду nullable embeded объекта
4. Как бы не секрет, но надо тюнить запросы прям сильно. Иначе реквест поинты таят на глазах.
5. Есть юник индексы, но создать можно только на пустой коллекции.
6. Ограничения в агрегации

А что мешает напрямую у монги купить кластер? У них ажур поддерживается.

В мене як поціновувача Cosmos є контр аргумент(и). Мені здається що всі Document DB це перш за все про маштабування і порівнювати перш за все треба це і всі штуки які з ним пов’язані.
Для всього іншого можна просто якийсь традиційний реляційний SQL сервер юзать і горя не знать.
Якщо сказати що розмір compute який виділяється під 1 partition Cosmos значно меньше мінімального VM на якому юзали Mongo — це може пояснити результати тесту?

P.S. Дякую за статтю )

Не все так просто :)

Наприклад, SQL не дуже добре працює, коли потрібна динамічна структура об’єктів моделі даних. Можна реалізувати EAV модель, але на великих маштабах вона не дасть нормальної продуктивності через декілька джойнів в кожному запиті. Можна покласти у вигляді JSON у поле в таблиці — ну іноді ок, але якщо захочеться кверяти по цим полям? Той же PostgreSQL дає таку можливість через JSONB і спецілальні індекси, але там теж є свої нюанси (можливо скоро напишу статтю на цю тему). З документною базою, в той же час, додавання динамічних полей дуже прозоре.

Навіть якщо структура статична, в моделі можуть бути вкладені об’єкти та колекції. Реалізовувати їх в SQL окремими таблицями — знов джойни. Класти у вигляді JSON — вже казав...

Коротко кажучі — є причини використовувати документні бази просто через особливості самої моделі. І, звісно, хотілося б отримати максимальну продуктивність за мінімальні гроші :)

Навіть якщо візьмемо масштабування — тут MongoDB виглядає більш гнучким, але загальні витрати треба уважно порівнювати. Проблема, з якою «космічні» проекти cтикаються регулярно вже частково згадувалась в коментах — треба маштабувати читання, а кожна нова фізічна партиція недешева і, до того ж, немає гарантії що не буде перекосу навантаження на фізічних партиціях, тому що система не дає контролю над тим, як розподіляються логічні партиції між нодами. Може скластись так, що одна нода горить і вивалюється за 10К реквест юнітів, і інші 8 — майже нічого не роблять.

Щодо пояснення результатів тесту потужністю ноди космоса — важко сказати, бо технічно це зовсім різні бази, і деякі фічі Cosmos DB можуть давати додатковий оверхед при виконанні звичайних запитів. Може навіть бути ситуація, що залізо ще має «сили» на виконання ще декількох паралельних запитів, а система все одно обрубає їх виконання, тому що відведена кількість реквест юнітів вичерпана. Це добре для доходів Майкрософту, але не дуже добре для економії грошей їх клієнтами :)

Я не кажу що Cosmos DB — погана база, мені багато чого в ній подобається, і є проекти до яких вона дуже добре підходить. Основна мотивація написання цієї статті була в тому, щоб показати, який рівень продуктивності можна очікувати від кожної з цих баз на типових запитах.

Дякую за детальну відповідь. Примусило задуматись скільки буде коштувати велика та нагружена система в Cosmos DB. :)

CosmosDB «shines» коли треба швидко зробити високу доступність даних між двома або більше регіонах. Це там дуже легко робиться.. Але його цінова політика мене дещо засмучує. Коли пропонуєш це кліентам які потребують «запис у одному регіоні та читання у всіх інших» то дехто каже що давайте піднімемо віртуалки з монгою на налаштуємо реплікацію бо у «Космоса- ціни космос»

странно что монга 4.2 ведь уже есть 6 хотя бы 5.0.9 и я что-то не понял мы в монгу sql ходим?

Я в самом начале статьи написал, почему именно 4.2 ;) И в монгу мы через SQL не ходим, там написано что это SQL *эквивалент* запроса, так всем понятнее будет какого плана запрос выполняется.

ну ок пусть будет

Треба ж якось розгортати віртуалки, регулярно їх патчити, налаштовувати репліки, бекапи, моніторити чи все ок, виправляти інфраструктурні проблемі та робити інші подібні процедури...

Так можна до будь якого розподілу ролей домахатись.

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