Подтвердить что ты не робот

Многоцелевые, многодокументные транзакции в MongoDB

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

Очевидно, что транзакция контролируется через приложение (в моем случае - веб-приложение Python). Для каждого документа в этой транзакции (в любой коллекции) добавляются следующие поля:

'lock_status': bool (true = locked, false = unlocked),
'data_old': dict (of any old values - current values really - that are being changed),
'data_new': dict (of values replacing the old (current) values - should be an identical list to data_old),
'change_complete': bool (true = the update to this specific document has occurred and was successful),
'transaction_id': ObjectId of the parent transaction

Кроме того, существует коллекция transaction, в которой хранятся документы, детализирующие каждую транзакцию. Они выглядят так:

{
    '_id': ObjectId,
    'date_added': datetime,
    'status': bool (true = all changes successful, false = in progress),
    'collections': array of collection names involved in the transaction
}

И вот логика процесса. Надеюсь, он работает таким образом, что если он перепутался или не сработает каким-то другим способом, он может быть откат должным образом.

1: Настройте документ transaction

2: Для каждого документа, на который влияет эта транзакция:

  • Установите lock_status на true (чтобы "заблокировать" документ от изменения)
  • Установите data_old и data_new в их старые и новые значения
  • Установите change_complete в false
  • Установите transaction_id в ObjectId документа transaction, который мы только что создали.

3: Выполните обновление. Для каждого документа:

  • Заменить любые затронутые поля в этом документе значениями data_new
  • Установите change_complete в true

4: Установите transaction document status на true (так как все данные были успешно изменены)

5: Для каждого документа, затронутого транзакцией, выполните некоторую очистку:

  • удалите data_old и data_new, поскольку они больше не нужны
  • установите lock_status в false (чтобы разблокировать документ)

6: Удалите документ transaction, настроенный на шаге 1 (или, как предлагается, отметьте его как завершенное)


Я думаю, что логически работает таким образом, что если он сбой в любой момент, все данные могут быть либо отброшены, либо транзакция может быть продолжена (в зависимости от того, что вы хотите сделать). Очевидно, что все откаты/восстановление/и т.д. выполняется приложением, а не базой данных, используя документы transaction и документы в других коллекциях с этой транзакцией_id.

Есть ли вопиющая ошибка в этой логике, которую я пропустил или пропустил? Есть ли более эффективный способ обойти это (например, меньше писать/читать из базы данных)?

4b9b3361

Ответ 1

В качестве универсального ответа многодокументные транзакции на MongoDB могут выполняться как двухфазные фиксации, которые были в значительной степени задокументированы в руководстве (см. http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/).

Схема, предложенная в руководстве, коротко описывает следующее:

  • Создайте отдельную коллекцию transactions, которая включает целевой документ, исходный документ, значение и состояние (транзакции)
  • Создайте новый объект транзакции с initial как state
  • Начните совершать транзакцию и обновлять state до pending
  • Применить транзакции к обоим документам (целевой, источник)
  • Обновить состояние транзакции до committed
  • Используйте find, чтобы определить, отражают ли документы состояние транзакции, если все в порядке, обновите состояние транзакции до done

Кроме того:

  • Вам нужно вручную обрабатывать сценарии отказа (что-то не произошло, как описано ниже)
  • Вам нужно вручную выполнить откат, в основном, введя имя state value canceling

Некоторые конкретные примечания для вашей реализации:

  • Я бы отговорил вас от добавления полей типа lock_status, data_old, data_new в исходные/целевые документы. Это должны быть свойства транзакций, а не сами документы.
  • Чтобы обобщить концепцию целевых/исходных документов, я думаю, вы могли бы использовать DBref s: http://www.mongodb.org/display/DOCS/Database+References
  • Мне не нравится идея удалять документы транзакций, когда они сделаны. Настройка состояния на done кажется лучшей идеей, так как это позволяет вам позже отлаживать и выяснять, какие транзакции были выполнены. Я уверен, что вы тоже не закончите дисковое пространство (и для этого есть и решения).
  • В вашей модели, как вы гарантируете, что все было изменено, как ожидалось? Вы как-то проверяете изменения?