Операции с документами MongoDB являются атомными и изолированными, но согласуются ли они? - программирование
Подтвердить что ты не робот

Операции с документами MongoDB являются атомными и изолированными, но согласуются ли они?

Я переношу свое приложение из хранилища данных App Engine в базу данных MongoDB и задаю вопрос о согласованности "обновлений документов". Я понимаю, что обновления одного документа являются атомарными и изолированными, но есть ли способ гарантировать, что они "совместимы" с различными наборами реплик?

В нашем приложении многие пользователи могут (и будут) пытаться обновить один документ одновременно, вставив в него несколько встроенных документов (объектов) во время одного обновления. Мы должны обеспечить, чтобы эти обновления происходили логически последовательным образом во всех репликах, т.е. Когда один пользователь "помещает" несколько встроенных документов в родительский документ, другие пользователи не могут помещать свои внедренные документы в родительский документ, пока мы не гарантируем, что они читать и получать первые обновления для пользователей.

Итак, что я подразумеваю под консистенцией, так это то, что нам нужен способ убедиться, что если два пользователя попытаются выполнить обновление одного документа в одно и то же время, MongoDB разрешает только одно из этих обновлений и отбрасывает другое один (или, по крайней мере, предотвращает их возникновение). Мы не можем использовать стандартное решение "sharding" здесь, потому что одно обновление состоит не только из приращения или уменьшения.

Какой лучший способ гарантировать согласованность одного конкретного документа?

4b9b3361

Ответ 1

MongoDB не предлагает репликации master-master или multi-version concurrency. Другими словами, записи всегда идут на один и тот же сервер в наборе реплик. По умолчанию даже чтения из вторичных отключены, поэтому поведение по умолчанию заключается в том, что вы обмениваетесь только одним сервером за раз. Поэтому вам не нужно беспокоиться о непоследовательных результатах в безопасном режиме, если вы используете атомные модификаторы (например, $inc, $push и т.д.).

Если вы не хотите ограничивать себя этими атомными модификаторами, сравните и поменяйте, как рекомендовано dcrosta (и mongo docs) выглядит как хорошая идея. Тем не менее, все это не связано с наборами реплик или осколков, однако в односерверном сценарии будет.

Если вам необходимо обеспечить согласованность чтения в случае сбоя базы данных / node, вы должны убедиться, что вы пишете большинство серверов в безопасном режиме.

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

Ответ 2

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

>>> db.foo.save({'_id': 'a', 'version': 1, 'things': []}, safe=True)
'a'
>>> db.foo.update({'_id': 'a', 'version': 1}, {'$push': {'things': 'thing1'}, '$inc': {'version': 1}}, safe=True)
{'updatedExisting': True, 'connectionId': 112, 'ok': 1.0, 'err': None, 'n': 1}

отметить выше, ключ "n" равен 1, что указывает на то, что документ был обновлен

>>> db.foo.update({'_id': 'a', 'version': 1}, {'$push': {'things': 'thing2'}, '$inc': {'version': 1}}, safe=True)
{'updatedExisting': False, 'connectionId': 112, 'ok': 1.0, 'err': None, 'n': 0}

здесь, где мы пытались обновить неверную версию, ключ "n" равен 0

>>> db.foo.update({'_id': 'a', 'version': 2}, {'$push': {'things': 'thing2'}, '$inc': {'version': 1}}, safe=True)
{'updatedExisting': True, 'connectionId': 112, 'ok': 1.0, 'err': None, 'n': 1}
>>> db.foo.find_one()
{'things': ['thing1', 'thing2'], '_id': 'a', 'version': 3}

Обратите внимание, что этот метод основан на использовании безопасной записи, иначе мы не получим подтверждение, указывающее количество обновленных документов. Вариант этого будет использовать команду findAndModify, которая либо вернет документ, либо None (в Python), если не найден документ, соответствующий запросу. findAndModify позволяет вернуть либо новый (то есть после того, как будут применены обновления), либо в старую версию документа.