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