使用Mongo API连接到CosmosDB在闲置后失败

12

我们有一个使用 Java MongoDB 驱动包装的 Scala 服务器,该驱动包装了 Casbah。 最近,我们将其数据库从实际的 MongoDB 切换到了使用 Mongo API 的 Azure CosmosDB。 这通常运行良好,但是偶尔会出现对 Cosmos 的调用失败,并显示 MongoSocketWriteException(以下是堆栈跟踪信息)。

我们创建客户端的方式是

import com.mongodb.casbah.Imports._

val mongoUrl = "mongodb://username:password@host.documents.azure.com:10255/?ssl=true&replicaSet=globaldb"

val client = MongoClient(MongoClientURI(mongoUrl))
val collection: MongoCollection = client("mongoDatabase")("mongoCollection")

按照此看似类似的错误(如何解决连接到CosmosDB时出现的MongoError:池已销毁)的建议解决方法,我们尝试从连接URI中删除&replicaSet=globaldb,但它并没有解决问题。

堆栈跟踪:

com.mongodb.MongoSocketWriteException: Exception sending message
    at com.mongodb.connection.InternalStreamConnection.translateWriteException(InternalStreamConnection.java:462)
    at com.mongodb.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:205)
    at com.mongodb.connection.UsageTrackingInternalConnection.sendMessage(UsageTrackingInternalConnection.java:95)
    at com.mongodb.connection.DefaultConnectionPool$PooledConnection.sendMessage(DefaultConnectionPool.java:424)
    at com.mongodb.connection.CommandProtocol.sendMessage(CommandProtocol.java:209)
    at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.java:111)
    at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:159)
    at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:286)
    at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:173)
    at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:215)
    at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:206)
    at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:112)
    at com.mongodb.operation.CountOperation$1.call(CountOperation.java:210)
    at com.mongodb.operation.CountOperation$1.call(CountOperation.java:206)
    at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:230)
    at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:203)
    at com.mongodb.operation.CountOperation.execute(CountOperation.java:206)
    at com.mongodb.operation.CountOperation.execute(CountOperation.java:53)
    at com.mongodb.Mongo.execute(Mongo.java:772)
    at com.mongodb.Mongo$2.execute(Mongo.java:759)
    at com.mongodb.DBCollection.getCount(DBCollection.java:962)
    at com.mongodb.DBCursor.count(DBCursor.java:670)
    at com.mongodb.casbah.MongoCollectionBase.getCount(MongoCollection.scala:496)
    at com.mongodb.casbah.MongoCollectionBase.getCount$(MongoCollection.scala:488)
    at com.mongodb.casbah.MongoCollection.getCount(MongoCollection.scala:1106)
    at com.mongodb.casbah.MongoCollectionBase.count(MongoCollection.scala:897)
    at com.mongodb.casbah.MongoCollectionBase.count$(MongoCollection.scala:894)
    at com.mongodb.casbah.MongoCollection.count(MongoCollection.scala:1106)
    [snip]
Caused by: java.net.SocketException: Broken pipe (Write failed)
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
    at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
    at sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
    at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:876)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:847)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
    at com.mongodb.connection.SocketStream.write(SocketStream.java:75)
    at com.mongodb.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:201)
    ... 38 common frames omitted

我发表这个回答时附带翻译,因为我希望这个解决方案对其他人有用,并且因为我很欢迎任何进一步的见解。

2个回答

14
在连接 URI 中添加 &maxIdleTimeMS=1500000,从而将最大连接空闲时间设置为25分钟后,问题已经解决。
问题似乎是由于 Azure 服务器上空闲连接的超时时间为30分钟,而 Mongo 客户端的默认行为是根本没有空闲超时。服务器不会向客户端通知它正在关闭一个闲置的连接,因此下一次尝试使用该连接会失败并出现以上错误。将最大连接空闲时间设置为小于30分钟的值使我们的服务器在 Azure 服务器关闭它们之前关闭闲置的连接。在使用连接之前进行某种心跳检测或检查可能也是可行的。
实际上,我还没有找到有关 CosmosDB 的此问题或其他参考资料,尽管它可能是由于或与 Azure 内部负载均衡器的 TCP 连接的30分钟空闲超时有关(请参见例如 https://feedback.azure.com/forums/217313-networking/suggestions/18823588-increase-idle-timeout-on-internal-load-balancers-t)。

3
除了从 AzureChina 文档中提供的方法外,您还可以在应用程序中添加 keepalive 参数:MongoClientOptions.Builder b = new MongoClientOptions.Builder().socketKeepAlive(true).heartbeatFrequency(1000).maxConnectionIdleTime(18000);https://docs.azure.cn/en-US/articles/azure-operations-guide/cosmos-db/aog-cosmos-db-qa-connection-error - Howard.TH
看起来Azure团队已经意识到了这个问题,但是一段时间以来没有更新/评论。 https://feedback.azure.com/forums/263030-azure-cosmos-db/suggestions/33825712-azure-mongodb-timeout-after-30-mins - Jet_C

0

您可以使用以下代码设置时间:

var options = new MongoClientOptions.Builder() .socketKeepAlive(true) .heartbeatFrequency(1000) .maxConnectionIdleTime(18000) var clientUri = new MongoClientURI(uri,options)

请尝试一次。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接