Как обойти отсутствие транзакций в MongoDB?

117

Я знаю, что здесь есть похожие вопросы, но они говорят мне, чтобы переключиться на обычные системы РСУБД, если мне нужны транзакции или используйте атомные операции или двухфазное принятие. Второй вариант кажется лучшим выбором. Третий я не хочу следовать, потому что кажется, что многие вещи могут пойти не так, и я не могу проверить это во всех аспектах. Мне сложно реорганизовать мой проект для выполнения атомных операций. Я не знаю, связано ли это с моей ограниченной точки зрения (я только работал с базами данных SQL до сих пор), или это действительно невозможно сделать.

Мы хотели бы пилотировать тест MongoDB в нашей компании. Мы выбрали относительно простой проект - шлюз SMS. Это позволяет нашему программному обеспечению отправлять SMS-сообщения в сотовую сеть, а шлюз выполняет грязную работу: фактически общается с поставщиками через различные протоколы связи. Шлюз также управляет выставлением счетов. Каждый клиент, который подает заявку на услугу, должен купить несколько кредитов. Система автоматически уменьшает баланс пользователя при отправке сообщения и отказывает в доступе, если баланс недостаточен. Кроме того, поскольку мы являемся клиентами сторонних провайдеров SMS, у нас также могут быть свои собственные балансы. Мы также должны отслеживать их.

Я начал думать о том, как я могу хранить требуемые данные с помощью MongoDB, если я сократил некоторую сложность (внешняя биллинг, отправка посылок в очереди). Исходя из мира SQL, я бы создал отдельную таблицу для пользователей, другую для SMS-сообщений и одну для хранения транзакций относительно баланса пользователей. Скажем, я создаю отдельные коллекции для всех из них в MongoDB.

Представьте задачу отправки SMS со следующими шагами в этой упрощенной системе:

  • проверьте, имеет ли пользователь достаточный баланс; запретить доступ, если недостаточно кредитов

  • отправьте и сохраните сообщение в сборнике SMS с подробной информацией и стоимостью (в живой системе сообщение будет иметь атрибут status, и задача подберет его для доставки и установит цену SMS в соответствии с его текущим состоянием)

  • уменьшить баланс пользователей за счет стоимости отправленного сообщения

  • зарегистрировать транзакцию в коллекции транзакций

Теперь, что проблема с этим? MongoDB может выполнять атомарные обновления только на одном документе. В предыдущем потоке может случиться, что в базу данных заходит некоторая ошибка, и сообщение сохраняется в базе данных, но баланс пользователя не обновляется и/или транзакция не регистрируется.

Я придумал две идеи:

  • Создайте единую коллекцию для пользователей и сохраните баланс как поле, связанные с пользователем транзакции и сообщения в качестве поддокументов в пользовательском документе. Поскольку мы можем обновлять документы атомарно, это фактически решает проблему транзакции. Недостатки: если пользователь отправляет много SMS-сообщений, размер документа может стать большим и может быть достигнут предел документа 4 МБ. Возможно, я могу создавать документы истории в таких сценариях, но я не думаю, что это была бы хорошая идея. Кроме того, я не знаю, насколько бы быстрой была система, если я нажимаю все больше и больше данных на один и тот же большой документ.

  • Создайте одну коллекцию для пользователей и одну для транзакций. Могут быть два вида сделок: покупка кредита с положительным изменением баланса и сообщения, отправленные с отрицательным сальдо. Транзакция может иметь поддокумент; например, в отправляемых сообщениях детали SMS могут быть встроены в транзакцию. Недостатки: я не сохраняю текущий баланс пользователя, поэтому я должен рассчитать его каждый раз, когда пользователь пытается отправить сообщение, чтобы сообщить, может ли сообщение пройти или нет. Я боюсь, что этот расчет может стать медленным, поскольку количество хранимых транзакций растет.

Я немного смущен тем, какой метод выбрать. Существуют ли другие решения? Я не мог найти ни одного передового опыта в Интернете о том, как обойти эти проблемы. Я думаю, многие программисты, которые пытаются познакомиться с миром NoSQL, сталкиваются с аналогичными проблемами в начале.

  • 59
    Простите, если я ошибаюсь, но похоже, что этот проект будет использовать хранилище данных NoSQL независимо от того, выиграет он от этого или нет. NoSQL не является альтернативой SQL как «модному» выбору, но в тех случаях, когда технология реляционных СУБД не соответствует проблемному пространству, а не реляционное хранилище данных. У многих из ваших вопросов есть «Если это был SQL, то ...», и это звучит для меня как предупреждение. Все NoSQL возникли из-за необходимости решить проблему, которую SQL не мог сделать, и затем они были несколько обобщены, чтобы упростить их использование, и тогда, конечно, популярность начинает развиваться.
  • 4
    Я знаю, что этот проект не совсем лучший для опробования NoSQL. Однако я боюсь, что мы начнем использовать его с другими проектами (скажем, с программным обеспечением для управления коллекциями библиотек, потому что мы занимаемся управлением коллекциями), и вдруг приходит какой-то запрос, требующий транзакций (и он действительно существует, представьте, что книги переносится из одной коллекции в другую) нам нужно знать, как мы можем преодолеть проблему. Может быть, только я ограничен и думает, что всегда нужны транзакции. Но может быть, есть способ как-то преодолеть это.
Показать ещё 5 комментариев
Теги:
transactions

6 ответов

18
Лучший ответ

Отметьте этот из Tokutek. Они разрабатывают плагин для Mongo, что promises не только транзакции, но и повышение производительности.

  • 0
    @ Джованни Битлинер. С тех пор Токутек был приобретен компанией Percona, и по указанной вами ссылке я не вижу ссылок на какую-либо информацию о том, что произошло со времени публикации. Вы знаете, что случилось с их усилиями? Я по электронной почте адрес электронной почты на этой странице, чтобы узнать.
  • 0
    Что тебе конкретно нужно? Если вам нужна технология току, примененная к Mongodb, попробуйте github.com/Tokutek/mongo , если вам нужна версия mysql, возможно, они добавили ее в свою стандартную версию Mysql, которую они обычно предоставляют
Показать ещё 1 комментарий
62

Жизнь без транзакций

Поддерживает транзакции ACID, но, хотя транзакций в MongoDB нет, у нас есть атомарные операции. Ну, атомные операции означают, что когда вы работаете над одним документом, эта работа будет завершена до того, как кто-либо еще увидит документ. Они увидят все сделанные нами изменения или ни одно из них. И используя атомные операции, вы часто можете выполнить ту же самую вещь, которую мы выполнили бы с помощью транзакций в реляционной базе данных. И причина в том, что в реляционной базе данных нам нужно внести изменения в несколько таблиц. Обычно таблицы должны быть объединены, и поэтому мы хотим сделать это все сразу. И для этого, поскольку существует несколько таблиц, нам нужно будет начать транзакцию и выполнить все эти обновления, а затем завершить транзакцию. Но с MongoDB мы собираемся внедрить данные, так как мы собираемся предварительно присоединить к ним в документах, и это эти богатые документы, которые имеют иерархию. Мы можем часто выполнять одно и то же. Например, в примере блога, если мы хотим убедиться, что мы обновили сообщение в блоге атомарно, мы можем это сделать, потому что мы можем сразу обновить весь блог. Если бы это была куча реляционных таблиц, нам, вероятно, пришлось бы открыть транзакцию, чтобы мы могли обновлять коллекцию записей и комментариев.

Итак, каковы наши подходы, которые мы можем предпринять в MongoDB, чтобы преодолеть недостаток транзакций?

  • реструктурировать - реструктурировать код, чтобы мы работали в одном документе и использовали атомные операции, которые мы предлагаем в этом документе. И если мы это сделаем, тогда, как правило, мы все настроены.
  • реализовать в программном обеспечении - мы можем реализовать блокировку в программном обеспечении, создав критический раздел. Мы можем построить тест, тест и установить с помощью поиска и изменения. Мы можем строить семафоры, если это необходимо. И в некотором роде, так устроен более крупный мир. Если мы подумаем об этом, если один банк должен перевести деньги в другой банк, они не будут жить в одной и той же реляционной системе. И у каждого из них есть свои собственные реляционные базы данных. И они должны иметь возможность координировать эту операцию, даже если мы не можем начинать транзакцию и завершать транзакцию в этих системах баз данных только внутри одной системы внутри одного банка. Таким образом, есть определенные способы в программном обеспечении, чтобы обойти проблему.
  • переносить - окончательный подход, который часто работает в современных веб-приложениях и других приложениях, которые используют огромное количество данных, - это просто терпеть немного несогласованности. Например, если мы говорим о фиде друзей в Facebook, неважно, будут ли все одновременно видеть обновление вашей стены. Если okey, если один человек несколько бьет позади в течение нескольких секунд, и они догоняют. Часто во многих конструкциях системы не критично, что все должно быть идеально согласованным и что каждый имеет абсолютно последовательный и одинаковый вид базы данных. Таким образом, мы могли бы просто терпеть немного несогласованности, которая несколько временная.

Update, findAndModify, $addToSet (в рамках обновления) и $push (в рамках обновления) операции работают атомарно внутри одного документа.

  • 2
    Мне нравится, как этот ответ делает, вместо того, чтобы продолжать задавать вопросы, если мы должны вернуться к реляционной БД. Спасибо @xameeramir!
  • 3
    критический раздел кода не будет работать, если у вас более 1 сервера, необходимо использовать службу внешней распределенной блокировки
Показать ещё 3 комментария
10

Довести это до такой степени: если целостность транзакций является обязательной, тогда не используйте MongoDB, а используйте только компоненты в системе, поддерживающей транзакции. Чрезвычайно сложно создать что-то поверх компонента, чтобы обеспечить ACID-подобную функциональность для компонентов, не совместимых с ACID. В зависимости от индивидуальных условий может иметь смысл отделить действия к транзакционным и не транзакционным действиям каким-либо образом...

  • 1
    Полагаю, вы имеете в виду, что NoSQL можно использовать в качестве базы данных сторонних разработчиков в классической RDBMS. Мне не нравится идея смешивать NoSQL и SQL в одном проекте. Это повышает сложность и, возможно, вводит некоторые нетривиальные проблемы.
  • 1
    Решения NoSQL редко используются в одиночку. Магазины документов (монго и кушетка), вероятно, единственное исключение из этого правила.
7

Теперь, что проблема с этим? MongoDB может выполнять атомарные обновления только на одном документе. В предыдущем потоке может случиться, что в базе данных происходит некоторая ошибка, и сообщение сохраняется в базе данных, но баланс пользователя не уменьшается и/или транзакция не регистрируется.

Это не проблема. Вы упомянули ошибку либо логическую ошибку (ошибка), либо ошибку ввода-вывода (сеть, сбой диска). Такая ошибка может оставлять как транзакционные, так и транзакционные хранилища в несогласованном состоянии. Например, если он уже отправил SMS, но при сохранении ошибки сообщения произошел - он не может отменить отправку SMS, что означает, что он не будет зарегистрирован, баланс пользователя не будет уменьшен и т.д.

Настоящая проблема заключается в том, что пользователь может использовать условия гонки и отправлять больше сообщений, чем позволяет его баланс. Это также относится к РСУБД, если только вы не отправляете SMS внутри транзакции с блокировкой поля баланса (что было бы большим препятствием). В качестве возможного решения для MongoDB сначала следует использовать findAndModify, чтобы уменьшить баланс и проверить его, если он отрицательно отклоняет отправку и возвращает сумму (атомный приращение). Если положительный, продолжите отправку и в случае, если он не сможет вернуть сумму. Также можно сохранить коллекцию истории баланса, чтобы помочь исправить/проверить поле баланса.

  • 0
    Спасибо за этот отличный ответ! Я знаю, что если я использую хранилища, способные к транзакциям, данные могут быть повреждены из-за системы SMS, которая не контролируется. Однако с Mongo есть вероятность, что ошибка данных может произойти и внутри компании. Допустим, код изменяет баланс пользователя с помощью findAndModify, баланс становится отрицательным, но, прежде чем я могу исправить ошибку, происходит ошибка, и приложение должно быть перезапущено. Я предполагаю, что вы имеете в виду, что я должен реализовать что-то похожее на двухфазную фиксацию на основе сбора транзакций и регулярно проверять исправления в базе данных.
  • 9
    Неверно, транзакционные хранилища будут откатываться, если вы не сделаете окончательный коммит.
Показать ещё 4 комментария
6

Транзакции отсутствуют в MongoDB по уважительным причинам. Это одна из тех вещей, которые делают MongoDB быстрее.

В вашем случае, если транзакция является обязательной, mongo кажется не очень подходящей.

Может быть RDMBS + MongoDB, но это добавит сложности и затруднит управление и поддержку приложения.

  • 1
    В настоящее время существует дистрибутив MongoDB под названием TokuMX, который использует фрактальную технологию для повышения производительности в 50 раз и одновременно предоставляет полную поддержку транзакций ACID: tokutek.com/tokumx-for-mongodb
  • 9
    Как транзакция может не быть обязательной. Как только вам когда-нибудь понадобится 1 простой случай, когда вам нужно обновить 2 таблицы, монго вдруг больше не подходит? Это не оставляет очень много вариантов использования вообще.
Показать ещё 1 комментарий
6

Проект прост, но вы должны поддерживать транзакции для оплаты, что затрудняет выполнение всего этого. Так, например, сложная система портала с сотнями коллекций (форум, чат, реклама и т.д.) В некотором отношении проще, потому что, если вы теряете форум или запись в чате, никто действительно не заботится. Если вы, с другой стороны, потеряете транзакцию платежа, которая является серьезной проблемой.

Итак, если вам действительно нужен пилотный проект для MongoDB, выберите тот, который прост в этом отношении.

  • 0
    Спасибо за объяснение. Грустно это слышать. Мне нравится простота NoSQL и использование JSON. Мы ищем альтернативу ORM, но похоже, что мы должны придерживаться ее некоторое время.
  • 0
    Можете ли вы привести веские причины, по которым MongoDB лучше, чем SQL, для этой задачи? Пилотный проект звучит немного глупо.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню