MongoDB 3.2空集合执行update操作缓慢的原因咨询
嘿,这个问题确实有点出乎意料——空集合上的update操作居然跑了10秒多,结合你给出的日志和环境信息,咱们从几个关键点来分析:
1. Majority写关注的同步等待是核心元凶
你的update操作明确指定了writeConcern: { w: "majority" },这意味着主节点必须等到**至少2个节点(主+1个从节点)**确认接收到并持久化这次写操作,才会给你的Spring应用返回结果。
而这次操作是针对空集合的第一个写操作(哪怕没有实际更新任何文档),MongoDB需要先在主节点创建集合的元数据(比如集合配置、存储结构初始化信息),然后把这些元数据同步到副本节点。如果你的副本节点网络延迟高、或者刚好处于负载状态,主节点就会一直等majority确认——看你的耗时刚好接近10秒,这和MongoDB默认的write concern超时时间完全吻合,大概率是卡在这一步了。
2. 无索引导致的全集合扫描(空集合也有额外开销)
虽然集合里没文档,但你的update带了查询条件{ lockExpiry: { $lte: 1516705340965 } },而且没给lockExpiry建索引。MongoDB执行这个查询时,必须做一次全集合扫描来确认没有匹配的文档。
别以为空集合就没东西扫——WiredTiger的空集合底层还是有元数据、存储结构的初始化信息的,全扫过程中需要遍历这些结构,虽然开销不大,但结合上面的写关注等待,就把整体时间拉上去了。
3. MongoDB 3.2版本的历史局限性
MongoDB 3.2是个比较老的版本了(2015年发布的),在副本集元数据同步、majority写关注的处理逻辑上存在一些性能短板。后续的3.4、3.6版本优化了空集合的元数据同步流程,也改进了写关注的等待机制,这类问题在新版本里出现的概率会低很多。
给你的几个解决建议
- 给
lockExpiry建索引:哪怕集合是空的,索引也能让MongoDB瞬间判断没有匹配的文档,直接跳过全集合扫描。执行这个命令就行:db.myCollection.createIndex({ lockExpiry: 1 }) - 调整写关注级别(如果业务允许):如果你的业务不需要强一致性,可以把write concern改成
w: 1(只等主节点确认),这样能大幅减少等待时间。要是必须用majority,那得检查下副本节点的网络状态和负载,确保元数据同步能快速完成。 - 考虑升级MongoDB版本:升级到3.6及以上的稳定版本,新版本在副本集同步、WiredTiger性能上有不少优化,能从根儿上减少这类奇怪的性能问题。
内容的提问来源于stack exchange,提问作者mchinaloy

