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

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

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

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

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

  1. проверьте, достаточно ли у пользователя баланса; отказать в доступе, если недостаточно средств

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

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

  4. записать транзакцию в коллекцию транзакций

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

Я пришел к двум идеям:

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

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

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

136
задан Community 23 May 2017 в 12:34
поделиться