所有
我刚从我们的applcation发出了一个奇怪的错误:
当我使用两个进程进行更新时,它抱怨在具有唯一索引的集合上出现重复键错误,但有问题的操作是一个upsert。
案例代码:
import time
from bson import Binary
from pymongo import MongoClient, DESCENDING
bucket = MongoClient('127.0.0.1', 27017)['test']['foo']
bucket.drop()
bucket.update({'timestamp': 0}, {'$addToSet': {'_exists_caps': 'cap15'}}, upsert=True, safe=True, w=1, wtimeout=10)
bucket.create_index([('timestamp', DESCENDING)], unique=True)
while True:
timestamp = str(int(1000000 * time.time()))
bucket.update({'timestamp': timestamp}, {'$addToSet': {'_exists_foos': 'fooxxxxx'}}, upsert=True, safe=True, w=1, wtimeout=10)
当我使用两个进程运行脚本时,Pymongo Exception:
Traceback (most recent call last):
File "test_mongo_update.py", line 11, in <module>
bucket.update({'timestamp': timestamp}, {'$addToSet': {'_exists_foos': 'fooxxxxx'}}, upsert=True, safe=True, w=1, wtimeout=10)
File "build/bdist.linux-x86_64/egg/pymongo/collection.py", line 552, in update
File "build/bdist.linux-x86_64/egg/pymongo/helpers.py", line 202, in _check_write_command_response
pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: test.foo index: timestamp_-1 dup key: { : "1439374020348044" }
ENV:
mongodb 3.0.5,WiredTiger
单个mongodb实例
pymongo 2.8.1
mongo.conf
systemLog:
destination: file
logAppend: true
logRotate: reopen
path: /opt/lib/log/mongod.log
# Where and how to store data.
storage:
dbPath: /opt/lib/mongo
journal:
enabled: true
engine: "wiredTiger"
directoryPerDB: true
# how the process runs
processManagement:
fork: true # fork and run in background
pidFilePath: /opt/lib/mongo/mongod.pid
# network interfaces
net:
port: 27017
bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces.
setParameter:
enableLocalhostAuthBypass: false
对这里可能出现的问题有什么想法?
PS:
我在MMAPV1存储引擎中重试了同样的情况,它运行正常,为什么?
我在这里找到了相关的东西: https://jira.mongodb.org/browse/SERVER-18213
但在此错误修复后,它会出现此错误,因此看起来此错误并未完全修复。
干杯
答案 0 :(得分:6)
upsert会检查要更新的现有文档,或者插入新文档。
我最好的猜测是你遇到了一个时间问题:
首先检查你的python库在底下发送的本机查询。确认它对本地mongo方面的期望。然后,如果您可以定期在有线电视上重播此半音,但从不在mmap上重播,请使用mongo引发错误,以确认其预期行为是什么。有时很难选择他们保证原子性的东西。
这是为什么Mongo ObjectIDs将时间戳,机器ID,pid和计数器组合为唯一性的一个很好的例子。
答案 1 :(得分:6)
我发现了以下错误: https://jira.mongodb.org/browse/SERVER-14322
请随时投票支持并观看更多内容。
答案 2 :(得分:1)
http://docs.mongodb.org/manual/core/storage/
使用WiredTiger,所有写入操作都发生在文档级别锁定的上下文中。因此,多个客户端可以同时修改单个集合中的多个文档。
您的多个客户端可以同时更新集合。 Wiredtiger将锁定您正在更新的文档,而不是集合。
答案 3 :(得分:0)
我使用MongoDB管理我的存储系统的目录树数据。我遇到了同样的问题:使用upsert=True
的update命令有时会创建重复的文档。
但是我使用了MMAPv1,我不知道使用WiredTiger引擎时会发生什么。我认为这是MongoDB的竞争条件问题。最后,我决定使用python-redis-lock编写一种锁定机制(文档锁定级别)。运行良好!