Пользователь PyMongo задал мне хороший вопрос сегодня: если вам нужна согласованность чтения-записи-записи, лучше ли делать подтвержденные записи с пулом соединений (по умолчанию) или выполнять неподтвержденные записи через один сокет?
Немного фона
Допустим, вы обновили документ MongoDB с помощью PyMongo и хотите сразу же прочитать обновленную версию:
client = pymongo.MongoClient() collection = client.my_database.my_collection collection.update( {'_id': 1}, {'$inc': {'n': 1}}) print collection.find_one({'_id': 1})
В многопоточном приложении пул соединений PyMongo может содержать несколько сокетов, поэтому мы не обещаем, что вы будете использовать один и тот же сокет для update
и для find_one
. Тем не менее, вы по-прежнему гарантируете согласованность чтения и записи: изменения, которые вы записали в документ, отражаются в той версии документа, с которой вы впоследствии читали find_one
. PyMongo выполняет эту последовательность, ожидая, пока MongoDB подтвердит операцию обновления, прежде чем отправит find_one
запрос. (В прошлом году я объяснил, как работает подтверждение в PyMongo .)
Есть еще один способ получить согласованность чтения-записи-записи: вы можете отправлять оба и один update
и find_one
тот же сокет, чтобы MongoDB обрабатывал их по порядку. В этом случае вы можете указать PyMongo не запрашивать подтверждение об обновлении с помощью w=0
опции:
# Reserve one socket for this thread. with client.start_request(): collection.update( {'_id': 1}, {'$inc': {'n': 1}}, w=0) print collection.find_one({'_id': 1})
Если вы установите опцию PyMongo, auto_start_request
он будет вызывать start_request
вас. В этом случае вам лучше позволить пулу соединений расти в соответствии с количеством потоков, удалив его max_pool_size
:
client = pymongo.MongoClient( auto_start_request=True, max_pool_size=None)
(См. Мою статью о запросах для деталей.)
Итак, чтобы ответить на вопрос пользователя: если есть два способа получить согласованность чтения-записи-записи, что вы должны использовать?
Ответ
Вы должны принять настройки по умолчанию PyMongo: использовать подтвержденные записи. Вот почему:
Количество сокетов : многопоточная программа Python, которая использует w=0
и auto_start_request
требует большего количества подключений к серверу, чем программа, которая вместо этого использует подтвержденные записи. При этом auto_start_request
мы должны зарезервировать сокет для каждого потока приложения, тогда как без него потоки могут совместно использовать пул соединений, меньший, чем общее количество потоков.
Обратное давление : если сервер становится очень сильно загруженным, программа, которая использует w=0
его, не будет знать, что сервер загружен, потому что не ожидает подтверждений. Напротив, сервер может оказывать обратное давление на программу, используя подтвержденные записи: программа не может продолжать запись на сервер, пока сервер не завершит и не подтвердит записи, которые в данный момент выполняются.
Отчет об ошибках : Если вы используете w=0
, ваше приложение не будет знать, не удалось ли выполнить запись из-за какой-либо ошибки на сервере. Например, вставка может вызвать нарушение дубликата ключа. Или вы можете попытаться увеличить поле в документе, но сервер отклоняет операцию, поскольку поле не является числом. По умолчанию PyMongo создает исключение при таких обстоятельствах, чтобы ваша программа не продолжала беспечно включаться, но если вы используете w=0
такие ошибки, молча проходите.
Согласованность : подтвержденные записи гарантируют согласованность чтения и записи независимо от того, подключены ли вы к mongod или к mongos в изолированном кластере.
Использование w=0
с auto_start_request
также гарантирует согласованность чтения-записи-записи, но только если вы подключены к mongod. Если вы подключены к mongos, использование w=0
с auto_start_request
не гарантирует какой-либо согласованности, потому что некоторые записи могут быть поставлены в очередь в прослушивателе обратной записи и завершены асинхронно. Ожидание подтверждения гарантирует, что все записи действительно были завершены в кластере, прежде чем ваша программа продолжит работу.
Прямая совместимость с MongoDB : Следующая версия сервера MongoDB предложит новую реализацию для вставки, обновления и удаления , которая снизит прирост производительности w=0
.
Совместимость с PyMongo : теперь вы можете сказать, что мы не большие поклонники auto_start_request
. Мы, скорее всего, удалим его из PyMongo в версии 3.0, поэтому лучше не полагаться на него.
Вывод
Короче говоря, вы должны просто принять настройки по умолчанию PyMongo: подтвержденные записи с auto_start_request=False
. Есть много недостатков и почти нет преимуществ по сравнению w=0
с auto_start_request
, и в ближайшем будущем эти варианты будут уменьшены или удалены в любом случае.