【问题标题】:MongoDB+Azure+Android: com.mongodb.WriteConcernException err: "not master" code: "10058"MongoDB+Azure+Android:com.mongodb.WriteConcernException err:“not master”代码:“10058”
【发布时间】:2013-12-25 07:52:19
【问题描述】:

背景

您好,我正在 Azure 上运行一个 MongoDB 副本集,并已从 Android 应用程序中远程连接到它。我已经从所有实例中读取工作正常(更新:因为它们被允许在主节点和辅助节点上读取)。但是,写入数据库仍然会出现间歇性错误并出现以下错误,因为必须仅在主节点上进行写入。

此外,如果您可以提供任何更具体的资源来处理此问题,那也将非常有帮助。我已经浏览了大部分文档并搜索了相当多的这个错误。

问题

如何防止此错误并允许 100% 的时间写入?

E/AndroidRuntime(): com.mongodb.WriteConcernException: {
        "serverUsed" : "/<my-remote-ip>:27017" , "err" : "not master" , 
        "code" : 10058 , "n" : 0 , "lastOp" : { "$ts" : 0 , "$inc" : 0} , 
        "connectionId" : 1918 , "ok" : 1.0}

堆栈跟踪

E/AndroidRuntime(13731): FATAL EXCEPTION: Thread-7629
E/AndroidRuntime(13731): Process: com.myapplication.examplemongodb, PID: 13731
E/AndroidRuntime(13731): com.mongodb.WriteConcernException: { "serverUsed" : "/<my-remote-ip>:27017" , "err" : "not master" , "code" : 10058 , "n" : 0 , "lastOp" : { "$ts" : 0 , "$inc" : 0} , "connectionId" : 1918 , "ok" : 1.0}
E/AndroidRuntime(13731):    at com.mongodb.CommandResult.getException(CommandResult.java:77)
E/AndroidRuntime(13731):    at com.mongodb.CommandResult.throwOnError(CommandResult.java:110)
E/AndroidRuntime(13731):    at com.mongodb.DBTCPConnector._checkWriteError(DBTCPConnector.java:102)
E/AndroidRuntime(13731):    at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:142)
E/AndroidRuntime(13731):    at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:115)
E/AndroidRuntime(13731):    at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:248)
E/AndroidRuntime(13731):    at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:204)
E/AndroidRuntime(13731):    at com.mongodb.DBCollection.insert(DBCollection.java:76)
E/AndroidRuntime(13731):    at com.mongodb.DBCollection.insert(DBCollection.java:60)
E/AndroidRuntime(13731):    at com.mongodb.DBCollection.insert(DBCollection.java:105)
E/AndroidRuntime(13731):    at com.myapplication.examplemongodb.ActivityMain$1.run(ActivityMain.java:83)
E/AndroidRuntime(13731):    at java.lang.Thread.run(Thread.java:841)

注意事项

  • 我正在使用mongo-java-driver v2.11.3
  • 我使用mongo-azure library 来帮助创建具有两个工作角色的 MongoDB 副本集。
    • (如果您对此有更多资源,那么我很乐意阅读它。我已经阅读了 GitHub 自述文件、thisthis,以及其他一些与 MongoDB/Azure 无关的内容. 但是,这些资源没有更新,也没有详细说明。)

可能的解决方案

  • 我认为与拥有副本集有关。
  • 我不确定是否会发生这种情况,因为我只有一个两个实例副本集(一个主副本集和一个辅助副本集),并且他们正在争夺(阅读:投票)谁想成为主副本。也许,需要一个仲裁者?但是,我目前不知道该怎么做。

更新

  • 感谢@David Makogon 的帮助,我很确定问题在于我如何设置与 Azure 的连接,以及如何访问工作角色。因此,这是我关于如何配置系统的更新说明:
    • 两个工作角色 (MongoDB.WindowsAzure.MongoDBRole),我通过 Android 应用程序的 TCP Input Endpoint 端口 27017 直接连接到它们。正如@David 所说,我目前无法控制连接到哪个实例。
    • 一个 Web 角色 (MongoDB.WindowsAzure.Manager),我不使用它,在端口 80 上有一个 HTTP Input Endpoint。这是默认情况下使用我上面提到的 mongo-azure 库创建的。我不确定我是否应该对此做些什么。

【问题讨论】:

  • 旁注:对于同样遇到这个和其他 MongoDB+Azure+Android 问题的读者,我写了另外两个 SO 问题并回答了它们:this 1that 2。这些链接可以解释我是如何陷入目前的困境的。

标签: java android mongodb azure mongodb-java


【解决方案1】:

如果所有实例都位于单个负载平衡的Input 端点(例如 27017)之后,那么每次您的客户端计算机连接到端点时,它都会连接到副本集集群中可能存在的不同节点(而您'd 无法控制你去哪个实例)。这或许可以解释为什么您有时尝试写入非主节点并收到错误,但您的所有读取操作都有效(因为您可能将 MongoDB 集群设置为允许在辅助节点上读取)。

Worker 角色还支持InstanceInput 端点,它允许您设置面向外部的端口范围(例如 27017-27019),映射到工作实例本身的单个端口(例如 27017)。如果您这样做,您的客户端应用程序现在可以直接连接到所有三个实例(27017、27018、27019)。许多驱动程序支持副本集连接,因此它将能够确定哪个节点是主节点,并将所有写入定向到它。 我不知道您在 Android 上使用的驱动程序是否支持副本集。 如果驱动程序不支持副本集,那么您可能需要考虑建立一个 API 层,然后它可以完成所有工作与数据库的通信(无论如何,这是一个普遍遵循的好习惯,您可以查看 Azure 的移动服务以快速实现此功能)。

所以...如果您的副本集集群的端点配置为 Input,这可能解释了您看到的问题,应该可以通过将端点类型切换为 InstanceInput 来解决。

【讨论】:

  • +1 感谢您提供如此重要的信息!对于我没有提到的事情,这是非常好的洞察力。你所说的关于我的设置的一切都是正确的。我将更新原始帖子以反映此信息等。我将重新开始检查我上传到 Azure 的项目,并希望利用这些新发现的信息解决问题并回复您。
  • 再次非常感谢您!初步测试表明,该问题现已得到解决。 mongo-java-driver 确实支持副本集。因此,我所要做的就是将角色的配置从 Input 更改为 InstanceInput。我确实喜欢实施最佳实践,那么您对通过 Azure 的移动服务而不是直接连接的利弊有更多见解吗?或者,至少你是从哪里得知这些信息的?我想一个好处是可以更好地控制所实施的安全措施,就像任何其他自定义 API 可以提供的一样。还有什么?
猜你喜欢
  • 2023-03-10
  • 2018-06-29
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
  • 2014-03-06
  • 2015-05-22
  • 2018-05-18
相关资源
最近更新 更多