Статьи

Согласованность чтения и записи с PyMongo

Пользователь 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, и в ближайшем будущем эти варианты будут уменьшены или удалены в любом случае.