Я знаю, что здесь есть аналогичные вопросы, но они либо говорят мне вернуться к обычным системам РСУБД, если мне нужны транзакции, либо использовать атомарные операции или двухфазную фиксацию . Второе решение кажется лучшим выбором. Третье я не хочу следовать, потому что кажется, что многое может пойти не так, и я не могу проверить его во всех аспектах. Мне сложно рефакторинг моего проекта для выполнения атомарных операций. Я не знаю, исходит ли это с моей ограниченной точки зрения (пока я работал только с базами данных SQL), или это действительно невозможно.
Мы хотели бы провести пилотное тестирование MongoDB в нашей компании. Мы выбрали относительно простой проект - SMS-шлюз. Это позволяет нашему программному обеспечению отправлять SMS-сообщения в сотовую сеть, а шлюз выполняет грязную работу: фактически общается с провайдерами через различные протоколы связи. Шлюз также управляет выставлением счетов за сообщения. Каждый покупатель, который обращается за услугой, должен купить кредиты. Система автоматически уменьшает баланс пользователя при отправке сообщения и отказывает в доступе, если баланс недостаточен. Кроме того, поскольку мы являемся клиентами сторонних поставщиков SMS, у нас также может быть собственный баланс на их счетах. Мы также должны следить за ними.
Я начал думать о том, как я могу хранить необходимые данные с помощью MongoDB, если я уменьшу некоторую сложность (внешний биллинг, отправка SMS в очереди). Исходя из мира SQL, я бы создал отдельную таблицу для пользователей, еще одну для SMS-сообщений и одну для хранения транзакций, касающихся баланса пользователей. Скажем, я создаю отдельные коллекции для всех в MongoDB.
Представьте себе задачу отправки SMS со следующими шагами в этой упрощенной системе:
проверьте, достаточно ли у пользователя средств на балансе; отказать в доступе, если недостаточно кредита
отправить и сохранить сообщение в коллекции SMS с подробностями и стоимостью (в действующей системе сообщение будет иметь
status
атрибут, и задача заберет его для доставки и установит цену SMS в соответствии с его текущим состоянием)уменьшить баланс пользователя на стоимость отправленного сообщения
зарегистрировать транзакцию в коллекции транзакций
В чем проблема? MongoDB может выполнять атомарные обновления только в одном документе. В предыдущем потоке могло случиться, что закрадывалась какая-то ошибка, и сообщение сохранялось в базе данных, но баланс пользователя не обновлялся и / или транзакция не регистрировалась.
У меня возникли две идеи:
Создайте единую коллекцию для пользователей и сохраните баланс как поле, транзакции и сообщения, связанные с пользователем, как вложенные документы в документе пользователя. Поскольку мы можем обновлять документы атомарно, это фактически решает проблему транзакции. Недостатки: если пользователь отправляет много SMS-сообщений, размер документа может стать большим и может быть достигнут предел документа в 4 МБ. Может быть, я смогу создавать исторические документы в таких сценариях, но я не думаю, что это будет хорошей идеей. Также я не знаю, насколько быстрой будет система, если я буду помещать все больше и больше данных в один и тот же большой документ.
Создайте одну коллекцию для пользователей и одну для транзакций. Транзакции могут быть двух видов: покупка в кредит с положительным изменением баланса и сообщения, отправленные с отрицательным изменением баланса. У транзакции может быть вложенный документ; например, в отправленных сообщениях детали SMS могут быть встроены в транзакцию. Недостатки: я не храню текущий баланс пользователя, поэтому мне приходится вычислять его каждый раз, когда пользователь пытается отправить сообщение, чтобы узнать, может ли сообщение пройти или нет. Боюсь, что этот расчет может замедлиться по мере роста количества хранимых транзакций.
Я немного не понимаю, какой метод выбрать. Есть ли другие решения? Я не смог найти в Интернете никаких передовых методов решения подобных проблем. Я полагаю, что многие программисты, которые пытаются познакомиться с миром NoSQL, вначале сталкиваются с аналогичными проблемами.