当前位置: 首页 > 知识库问答 >
问题:

MongoDB客户端引发等待队列完全异常

齐永昌
2023-03-14

我看到了一个奇怪的问题。NET client for MongoDB抛出了一个等待队列,等待获取到服务器127.0.0.1:27017的连接已满 异常。

我有一个信号灯,可以保护对MongoDB的任何呼叫,大小为10。也就是说,对Mongo的并发调用永远不会超过10次。

默认连接池大小为100。NET驱动程序,超过10。所以10个并发调用应该不是问题。

为了复制这一点,我有下面的代码,是的,但它使问题变得明显。

我还为MongoDB找到了这个规范https://github.com/mongodb/specifications/blob/master/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst#id94

这是相关的吗?每个调用线程(在这种情况下是线程池工作线程)是否都进入等待队列并尝试获取连接,如果我有更多的工作线程,即使并发级别很低,连接仍然必须分配给这个新的调用工作线程?

using System;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using System.Threading;

namespace ConsoleApp58
{
    public class AsyncSemaphore
    {
        private readonly SemaphoreSlim _semaphore;

        public AsyncSemaphore(int maxConcurrency)
        {
            _semaphore = new SemaphoreSlim(
                maxConcurrency,
                maxConcurrency
            );
        }

        public async Task<T> WaitAsync<T>(Task<T> task)
        {
            await _semaphore.WaitAsync();
            //proves we have the correct max concurrent calls
            //  Console.WriteLine(_semaphore.CurrentCount);

            try
            {
                var result = await task;
                return result;
            }
            finally
            {
                _semaphore.Release();
            }
        }
    }
    
    class Program
    {
        public class SomeEntity
        {
            public ObjectId Id { get; set; }
            public string Name { get; set; }
        }

        static void Main(string[] args)
        {
            var settings = MongoClientSettings.FromUrl(MongoUrl.Create("mongodb://127.0.0.1:27017"));
            // settings.MinConnectionPoolSize = 10;
            // settings.MaxConnectionPoolSize = 1000;
            
            // I get that I can tweak settings, but I want to know why this occurs at all?
            // if we guard the calls with a semaphore, how can this happen?

            var mongoClient = new MongoClient(settings);
            var someCollection = mongoClient.GetDatabase("dummydb").GetCollection<SomeEntity>("some");
            var a = new AsyncSemaphore(10);
            
            // is this somehow related ?
            // https://github.com/mongodb/specifications/blob/master/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst#id94


            _ = Task.Run(() =>
                {
                    while (true)
                    {
                        // this bit is protected by a semaphore of size 10
                        // (we will flood the thread pool with ongoing tasks, yes)
                        _ = a.WaitAsync(RunTask(someCollection))
                            //after the task is done, dump the result
                            // dot is OK, else exception message
                            .ContinueWith(x =>
                            {
                                if (x.IsFaulted)
                                {
                                    Console.WriteLine(x.Exception);
                                }
                            });
                    }
                }
            );

            Console.ReadLine();
        }

        private static async Task<SomeEntity> RunTask(IMongoCollection<SomeEntity> pids)
        {
            //simulate some mongo interaction here
            var res = await pids.Find(x => x.Name == "").FirstOrDefaultAsync();
            return res;
        }
    }
}

共有1个答案

欧阳成弘
2023-03-14

建立连接需要时间。您不会立即获得100个可用连接。如果您创建一个客户端并立即请求甚至10个操作,而没有可用连接,您可能会遇到等待队列超时。

一些司机也有等待队列长度限制。它不是标准化的,在我看来应该被弃用,但出于兼容性原因,它可能会继续存在。咨询驾驶员文档,了解如何提升。

然后,增加waitQueueTimeoutMS或逐步增加负载或在开始负载之前等待建立连接(您可以对后者使用CMAP事件)。

确保您的10个未完成操作的并发绑定实际上也正常工作。

 类似资料:
  • 我创建了一个用C编写的gRPC异步客户端,它使用完成队列向服务器发出流式和一元请求。 在客户机类的析构函数中,调用了完成队列的方法,然后我想我可以调用来耗尽队列并获取挂起的标记,但对的调用会阻止一切。 挂起的标签是需要的,因为它们是用创建的对象,必须删除以避免泄漏。 对异步客户机使用的队列进行排空的正确方法是什么?

  • 等待队列 到目前为止,我们的实验中,用户进程或内核线程还没有睡眠的支持机制。在课程中提到用户进程或内核线程可以转入等待状态以等待某个特定事件(比如睡眠,等待子进程结束,等待信号量等),当该事件发生时这些进程能够被再次唤醒。内核实现这一功能的一个底层支撑机制就是等待队列wait_queue,等待队列和每一个事件(睡眠结束、时钟到达、任务完成、资源可用等)联系起来。需要等待事件的进程在转入休眠状态后插

  • 等待队列接口 结构体 struct   rt_wqueue   等待队列控制块 更多...   struct   rt_wqueue_node   等待队列节点 更多...   宏定义 #define  RT_WQ_FLAG_CLEAN   0x00   等待队列清除   #define  RT_WQ_FLAG_WAKEUP   0x01   等待队列唤醒   #define  DEFINE_WA

  • 我通读了Dart/flatter中的Async/Await/then,试图理解为什么aysnc函数中的Await不会等到完成后再继续。在我的UI中,有一个按钮调用一个异步方法来返回一个位置,该位置总是返回null,并且不等待函数完成。 该函数将调用推送到一个新的UI页面,该页面选择一个位置,并应返回一个结果。如何使该函数等待结果?我不是在使用异步吗?

  • 我已经创建了一个简单的Jersey客户端,它能够成功地使用有效负载执行POST请求。但现在它正在等待来自httpendpoint的响应: 问:代码是否有可能不等待响应。 我试图阅读泽西客户端文档,以确定我的代码是否有可能不等待响应?我看到我们只能在读取响应后关闭连接,但在我的情况下没有用。我想在将有效负载发布到endpoint后立即关闭连接。 我只需要触发并忘记POST请求,因为我不关心响应。这是

  • 我有一些文件要上传,有些文件失败了,因为帖子是异步的,而不是同步的。 我正在尝试将此调用作为同步调用。 我想等回应。 如何将此调用设为同步调用? 任何帮助感谢!