【问题标题】:MongoDB updateOne() returns "modifiedCount": 1 for simultaneous update calls on the same documentMongoDB updateOne() 返回“modifiedCount”:1 表示同一文档上的同时更新调用
【发布时间】:2020-11-21 10:51:39
【问题描述】:

我们正在尝试使用updateOne() 更新文档。过滤器识别文档,我们使用$set 更新文档的属性。此更新作业每分钟由一个 cron 作业触发。

说,原始文件是{_id: "USER1001", status: "INACTIVE"}。我们通过使用过滤器{_id: "USER1001", status: "INACTIVE"} 调用updateOne() 并将状态字段更新为{"$set":{status:"ACTIVE"}} 来更新它。我们查看modifiedCount 的结果值并期望它为1,以声称updateOne() 操作成功。这会触发下游作业。

应用程序在 Kubernetes 中运行,我们已经对其进行了扩展。当我们在负载下测试系统时,从两个不同的 pod 对具有相同过滤器的同一个文档同时进行两个 updateOne() 调用,并且都将 modifiedCount 返回为 1。

我们希望modifiedCount 为 1 对应一个 pod,0 对应另一个。但对于某些文档,我们会看到此结果。

示例代码供参考

// cron job that calls update() every minute

func update(){
  filter := bson.D{{"_id", "USER1001"}, {"status", "INACTIVE"}}
  result, err := collection.UpdateOne(context.Background(), filter, bson.M{"$set": bson.M{"status": "ACTIVE"}})
  
  if result.ModifiedCount != 1 {
    // no update done
  } else {
    // call downstream jobs
  }
}

我们从应用程序 pod 中获得的示例日志行

  • POD-1

[2020-11-20 17:30:58.610518875 +0000 UTC] [DEBUG] [myJob-7dc8b78bcf-c4677] update() :: 更新结果 :: USER1001 / Matched=1 / Modified=1

  • POD-2

[2020-11-20 17:30:58.409843674 +0000 UTC] [DEBUG] [myJob-7dc8b78bcf-jd7m8] update() :: 更新结果 :: USER1001 / Matched=1 / Modified=1

这里的问题是 -

  1. 有其他人看到过这种行为吗?
  2. 什么可能导致此问题?

其他信息,

  • 应用程序在 Go 中
  • Mongo 是 4.4 并且
  • 我们正在使用最新的 mongo-driver for go。
  • cron 作业每分钟运行一次,而不是在一分钟内运行。意思就是,
    • POD-1 可能会运行它,
      • 10:00:23
      • 10:01:23
      • 10:02:23 等
    • POD-2 可能会运行它,
      • 10:00:35
      • 10:01:35
      • 10:02:35 等

【问题讨论】:

  • 鉴于赞成的答案,您应该提供一个演示问题的程序。
  • 当然。我已经用我们的应用程序、日志和其他信息中的示例代码更新了问题。
  • 我认为,如果您真的希望有人为您调查此问题,您需要提供一个完整的程序来重现该问题。
  • 结束这个问题,因为这是代码中根深蒂固的竞争条件。

标签: mongodb go kubernetes


【解决方案1】:

如果您先阅读此文档,发现它处于非活动状态,然后决定激活它,这是您必须处理的常见竞争条件。另一个进程做同样的事情,然后都更新文档。

有办法防止这种情况发生。 Mongodb 文档级别的操作是原子的,因此最简单的解决方案是将过滤器更改为 {_id:"USER1001","status":"INACTIVE"} 以确保文档在更新时处于非活动状态。然后只有一个节点会成功更新文档,尽管多个节点可能会尝试更新它。

【讨论】:

  • 我们的过滤器也包括"status": Inactive。我只是没有提到它。
  • 更新过滤器包括状态:非活动,还是搜索过滤器?
  • 如果您使用您提到的更新过滤器,则不会发生这种情况。文档级别的操作在 mongodb 中是原子的。这可能是驱动程序错误,或者您的代码中没有提及其他内容。
  • 正如我所说,这不可能发生,所以要么存在错误,要么有更多细节需要听到。有很多生产代码依赖于这种行为。您是否有机会与副本集交谈?主节点在更新期间是否失败?如果是这样,可能会发生不一致。
  • 我知道这不应该发生。但是我们在我们的环境中观察到这一点,经过 2 周的调试后我们一无所知。我们拥有的 mongoDB 设置是一个 3 节点集群。
【解决方案2】:

我过去也有类似的要求。我建议您尝试使用“锁定”机制。当一个操作正在运行时,它会阻止另一个操作。

供参考,请查看:https://www.mongodb.com/blog/post/how-to-select--for-update-inside-mongodb-transactions

官方文档:

请注意,我记得,Mongo 服务器应该是一个“副本集”。不可能是一个人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-16
    • 2011-04-16
    • 1970-01-01
    • 2018-05-09
    • 2014-09-04
    • 2020-05-06
    • 2020-08-29
    相关资源
    最近更新 更多