【问题标题】:MongoDB - write concern majority - Attempted to read past the end of the streamMongoDB - 写关注多数 - 尝试读取流的末尾
【发布时间】:2018-02-01 14:36:47
【问题描述】:

我正在使用 2.4.3 版的 C# 驱动程序连接到 3.4.4 版的 MongoDB。我有一个 3 成员副本集(一个主副本、一个辅助副本、一个仲裁器)。我已在我的连接字符串中将写关注设置为多数。当主节点和辅助节点都在线时,我可以毫无问题地写入数据库。但是当我使主要离线时我遇到了麻烦。我正在使用此代码:

    string connectionString = "mongodb://USERNAME:PASSWORD@PRIMARY,SECONDARY/?replicaSet=MyReplicaSet&w=majority";

    var client = new MongoClient(connectionString);
    IMongoDatabase database = client.GetDatabase("test");
    IMongoCollection<BsonDocument> collection = database.GetCollection<BsonDocument>("people");

    Console.WriteLine($"Number of documents: {collection.Count(FilterDefinition<BsonDocument>.Empty)}");

    collection.InsertOne(new BsonDocument("name", DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss")));

    Console.WriteLine($"Number of documents: {collection.Count(FilterDefinition<BsonDocument>.Empty)}");

当我使主节点脱机时,辅助节点被选举出来,我仍然可以写入数据库(我可以在新选举的主节点上看到数据库中的文档)。但是对 collection.InsertOne 的调用最终会抛出 MongoDBConnectionException:

MongoDB.Driver.MongoConnectionException: An exception occurred while receiving a message from the server. ---> System.IO.EndOfStreamException: Attempted to read past the end of the stream.
   at MongoDB.Driver.Core.Misc.StreamExtensionMethods.ReadBytes(Stream stream, Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Connections.BinaryConnection.ReceiveBuffer()
   --- End of inner exception stack trace ---
   at MongoDB.Driver.Core.Connections.BinaryConnection.ReceiveBuffer()
   at MongoDB.Driver.Core.Connections.BinaryConnection.ReceiveBuffer(Int32 responseTo, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Connections.BinaryConnection.ReceiveMessage(Int32 responseTo, IMessageEncoderSelector encoderSelector, MessageEncoderSettings messageEncoderSettings, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.AcquiredConnection.ReceiveMessage(Int32 responseTo, IMessageEncoderSelector encoderSelector, MessageEncoderSettings messageEncoderSettings, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.WireProtocol.CommandWireProtocol`1.Execute(IConnection connection, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Servers.Server.ServerChannel.ExecuteProtocol[TResult](IWireProtocol`1 protocol, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Servers.Server.ServerChannel.Command[TResult](DatabaseNamespace databaseNamespace, BsonDocument command, IElementNameValidator commandValidator, Func`1 responseHandling, Boolean slaveOk, IBsonSerializer`1 resultSerializer, MessageEncoderSettings messageEncoderSettings, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase.ExecuteProtocol(IChannelHandle channel, BsonDocument command, Func`1 responseHandling, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase.ExecuteBatch(IChannelHandle channel, BatchableSource`1 requestSource, Int32 originalIndex, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase.ExecuteBatches(IChannelHandle channel, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase.Execute(IChannelHandle channel, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.ExecuteBatch(IChannelHandle channel, Run run, Boolean isLast, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.Execute(IWriteBinding binding, CancellationToken cancellationToken)
   at MongoDB.Driver.OperationExecutor.ExecuteWriteOperation[TResult](IWriteBinding binding, IWriteOperation`1 operation, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.ExecuteWriteOperation[TResult](IWriteOperation`1 operation, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionBase`1.InsertOne(TDocument document, InsertOneOptions options, CancellationToken cancellationToken)
   at ReplicaSetTest.Program.Main(String[] args) in C:\Code\TFS\Published Register\Main\ReplicaSetTest\Program.cs:line 57

如果我没有将写关注设置为多数,那么我没有问题。我对 MongoDB 没有太多经验,所以我对出了什么问题感到困惑。谁能建议我应该从哪里开始追查这个问题的原因?

谢谢,

大卫

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    但是对 collection.InsertOne 的调用最终会抛出 MongoDBConnectionException

    首先,写关注多数意味着客户端请求来自大多数副本集的确认(必须包括主节点)。因此,客户端应用程序将等待来自主节点和您的一个辅助节点的响应。有关此图表,请参阅Verify Write Operations to Replica Sets。

    如果在等待确认写入期间主节点被降级,则客户端与主节点的连接将丢失。辅助节点也会尝试清除任何已建立的连接,因为节点的状态已从 SECONDARY 更改为 PRIMARY(另请参阅 Replica Set Member States )。这将导致客户端丢失连接(流),因为客户端期待回复但它永远不会到来。因此,你得到:

    System.IO.EndOfStreamException: Attempted to read past the end of the stream
    

    您应该尝试捕获此异常,并根据写入的性质适当处理。

    您可能也有兴趣知道,在 MongoDB v3.6 中,有Retryable Writes 提供对瞬态网络错误/副本集选举的处理。

    此外,我还注意到您的部署包含Primary with a Secondary and an Arbiter 而不是Primary with Two Secondaries。如果您只有 2 个数据承载节点并且其中一个已关闭,则写入关注大多数将无法满足。因为它要求副本集的大多数接收写操作,但只有一个数据承载成员处于活动状态。请考虑将仲裁者转换为次要成员。

    【讨论】:

    • 非常感谢,这是一个很好的详细答案。
    猜你喜欢
    • 2012-12-28
    • 2013-08-02
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多