#mongodb
#mongodb
Вопрос:
У меня есть две коллекции, одна (A), содержащая элементы, подлежащие обработке (относительно небольшие), и одна (B) с уже обработанными элементами (довольно большая, с дополнительными полями результатов).
Элементы считываются из A, обрабатываются и сохраняют ()’d в B, затем удаляют ()’d из A.
Обоснование заключается в том, что индексы у них могут отличаться, и что таким образом «входящая» коллекция может быть очень маленькой и быстрой.
Я столкнулся с двумя проблемами с этим:
- если либо время ожидания remove (), либо save (), либо иной сбой при загрузке, я полностью теряю элемент или обрабатываю его дважды
- если оба выходят из строя, возникают побочные эффекты, но записи об этом нет
Я могу обойти случай двойного сбоя с помощью блокировок findAndModify (в противном случае они не нужны, у нас блокировка на уровне процесса), но тогда у нас возникают проблемы с устаревшей блокировкой, и частичные сбои все еще могут произойти. Насколько я могу судить, нет способа атомарно удалить сохранить в разные коллекции (возможно, по дизайну?)
Существует ли наилучшая практика для этой ситуации?
Ответ №1:
Насколько я могу судить, нет способа атомарно удалить сохранить в разные коллекции (возможно, по дизайну?)
Да, это сделано специально. MongoDB явно не предоставляет объединения или транзакции. Удалить Сохранить — это форма транзакции.
Существует ли наилучшая практика для этой ситуации?
Здесь действительно есть два варианта низкой сложности, оба предполагают findAndModify
.
Вариант № 1: единая коллекция
Основываясь на вашем описании, вы в основном создаете очередь с некоторыми дополнительными функциями. Если вы используете одну коллекцию, то вы используете findAndModify
для обновления статуса каждого элемента по мере его обработки.
К сожалению, это означает, что вы потеряете это: …что таким образом «входящую» коллекцию можно сохранить очень маленькой и быстрой.
Вариант # 2: две коллекции
Другой вариант — это в основном двухфазная фиксация с использованием findAndModify
.
Взгляните на документы для этого здесь.
Как только элемент обрабатывается в A, вы устанавливаете поле, помечающее его для удаления. Затем вы копируете этот элемент в B. После копирования в B вы можете удалить элемент из A.
Комментарии:
1. Я на самом деле пришел к существенно более простой версии реализации двухфазной фиксации с откатами, еще немного почесав голову, рад узнать, что это официальный способ 🙂 Блокировка с одной коллекцией не совсем работает из-за различных способов использования элементов, подлежащих обработке, по сравнению с уже обработанными (рекурсивные / безотказные блокировки findAndModify были бы здесь очень плохими). Это двухфазный процесс!
Ответ №2:
Я еще не пробовал это сам, но в новой книге «50 советов и хитростей для разработчиков MongoDB» несколько раз упоминается об использовании заданий cron (или служб / планировщика) для очистки подобных данных. Вы могли бы оставить документы в коллекции помеченными для удаления и запускать ежедневное задание для их очистки, уменьшая общий объем исходной транзакции.
Из того, что я узнал до сих пор, я бы никогда не оставил базу данных в состоянии, в котором я полагаюсь на выполнение следующего действия базы данных, если это не последнее действие (ведение журнала повторно отправит последнее действие базы данных после восстановления). Например, у меня есть трехэтапный процесс регистрации учетной записи, в котором я создаю пользователя в CollectionA, а затем добавляю другой связанный документ в CollectionB. Когда я создаю пользователя, я встраиваю детали документа CollectionB в CollectionA на случай, если вторая запись завершится неудачей. Позже я напишу процесс, который удаляет внедренные данные из CollectionA, если документ в CollectionB существует
Отсутствие транзакций действительно вызывает подобные болевые точки, но я думаю, что в некоторых случаях есть новые способы думать об этом. В моем случае время покажет, как я продвигаюсь с моим приложением
Комментарии:
1. Вы знаете, читая мой собственный комментарий, это кажется неудовлетворительным решением. Создание новой учетной записи — одна из наиболее важных частей веб-приложения, и в моем случае это неизбежно многоступенчатое обновление. Я рассматриваю возможность использования dapper для sql Express или mysql для базовой системы. А для отчетов / архивирования / форума я бы использовал mongo
2. Выполнение cronjobs очистки и скрытие резервных копий внутри других структур не совсем похоже на чистое решение (хотя я не могу придумать лучшего для вашего случая — откат создания пользователя на самом деле не вариант — кроме небольшого варианта записи в качестве элемента «job» сначала в коллекцию C, затем создания записей в A и B и удаления / маркировки C уникальными индексами в A / B)
3. Ах, вы имеете в виду что-то вроде коллекции (C) заданий, которые необходимо выполнить, и флага для указания стадии, на которой они находятся, чтобы их можно было завершить чисто. Мне это тоже не кажется чистым, поэтому я начинаю отходить от Mongo для этого конкретного проекта