有时当插入一小堆不同的文档(同步)时,我得到以下异常(请参阅下面的完整堆栈跟踪):
MongoDB.Driver.MongoWaitQueueFullException:等待队列 获取与服务器xyz.mongolab.com:54128的连接已满。
我在所有存储库之间使用单例MongoDatabase
实例(因而是单个连接)。基本上,我正在做这样的事情(每个集合中不超过20个文档):
Context.Collection<ClientDocument>("clients").InsertMany(clients);
Context.Collection<VendorDocument>("vendors").InsertMany(vendors);
Context.Collection<SaleDocument>("sales").InsertOne(sale);
以下是单身人士背景:
public class MongoContext
{
public IMongoDatabase Database { get; }
public MongoContext(IOptions<MongoSettings> settings)
{
var url = MongoUrl.Create(settings.Value.EndpointUri);
var client = new MongoClient(new MongoClientSettings()
{
Server = url.Server
});
Database = client.GetDatabase(url.DatabaseName);
}
public IMongoCollection<TDocument> Collection<TDocument>(string collection)
where TDocument : IDocument
{
return Database.GetCollection<TDocument>(collection);
}
}
在MongoDB的Jira(https://jira.mongodb.org/browse/CSHARP-1144)上提交了类似的东西,但是这些情况正在处理大量的大量插入(并且通常是异步的)。
我认为不需要使用这么小的插件来增加MaxConnectionPoolSize或WaitQueueSize。
这可能是什么原因?
我正在使用mLabs中托管的MongoDB 3.0.7。我们的应用程序托管在Azure(作为Web应用程序),我使用的是C#2.2.3 SDK。
MongoDB.Driver.MongoWaitQueueFullException:等待队列 获取与服务器xyz.mongolab.com:54128的连接已满。在 MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.AcquireConnectionHelper.CheckingOutConnection() 在 MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool.AcquireConnection(的CancellationToken cancelToken) MongoDB.Driver.Core.Servers.ClusterableServer.GetChannel(的CancellationToken cancelToken) MongoDB.Driver.Core.Bindings.ServerChannelSource.GetChannel(的CancellationToken cancelToken) MongoDB.Driver.Core.Bindings.ChannelSourceHandle.GetChannel(的CancellationToken cancelToken) MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.Execute(IWriteBinding binding,CancellationToken cancellationToken)at MongoDB.Driver.OperationExecutor.ExecuteWriteOperation [TResult](IWriteBinding 绑定,IWriteOperation'1操作,CancellationToken cancelToken) MongoDB.Driver.MongoCollectionImpl'1.ExecuteWriteOperation [TResult](IWriteOperation`1 operation,CancellationToken cancellationToken)at MongoDB.Driver.MongoCollectionImpl'1.BulkWrite(IEnumerable'1 requests, BulkWriteOptions选项,CancellationToken cancellationToken)at MongoDB.Driver.MongoCollectionBase'1.InsertOne(TDocument文档, InsertOneOptions选项,CancellationToken cancellationToken)
编辑:
如果我将MaxConnectionPoolSize设置为500并将WaitQueueSize设置为2000,则会出现以下异常:
MongoConnectionException:打开a时发生异常 连接到服务器。 ---&GT; System.Net.Sockets.SocketException:An 尝试以访问禁止的方式访问套接字 权限191.235.xxx.xxx:54128
实例化MongoClient
:
var client = new MongoClient(new MongoClientSettings()
{
Server = url.Server,
Credentials = credentials,
MaxConnectionPoolSize = 500,
WaitQueueSize = 2000
});
我最初提出了这个问题here。这导致我试图弄清楚为什么我有这么多的联系。这导致this post(询问Insert / InsertBulk是否可能是一个原因)。无论如何,我仍然需要修复原始的MongoWaitQueueFullException问题。
答案 0 :(得分:0)
解决问题的长久之路可能是引入限制机制,以确保您不超过最大连接数。幸运的是,有了信号量,这很容易实现。
public class ConnectionThrottlingPipeline : IConnectionThrottlingPipeline
{
private readonly Semaphore openConnectionSemaphore;
public ConnectionThrottlingPipeline( IMongoClient client )
{
//Only grabbing half the available connections to hedge against collisions.
//If you send every operation through here
//you should be able to use the entire connection pool.
openConnectionSemaphore = new Semaphore( client.Settings.MaxConnectionPoolSize / 2,
client.Settings.MaxConnectionPoolSize / 2 );
}
public async Task<T> AddRequest<T>( Task<T> task )
{
openConnectionSemaphore.WaitOne();
var result = await task;
openConnectionSemaphore.Release();
return result;
}
}
如果您通过此限制管道将所有请求发送到数据库,则永远都不会超出限制。
在您的情况下,通过管道发送操作可能看起来像这样(您必须进行的最大更改是使数据库调用异步):
await connectionThrottlingPipeline.AddRequest(
Context.Collection<ClientDocument>("clients").InsertManyAsync(clients))