1

Мы используем базу данных In Exasol, которая предоставляет провайдера Ado.Net, но, похоже, отсутствуют некоторые важные функции, такие как ConnectionPooling, поэтому каждое соединение создается и уничтожается за запрос, который влияет на нашу производительность, поскольку мы подключаемся к размещенной базе данных по адресу AWS. Я создал простой ConnectionPool, с возможностью Resize, пожалуйста, предложите, будет ли это служить цели, или мне нужно сделать что-то еще.Пул пользовательских подключений для провайдера Exasol Ado.Net

Обратите внимание, что я не ищу обзор кода, но критический анализ того, что мне может не хватать в текущей реализации, также, если есть доступная реализация (Nuget, Git), которую я могу повторно использовать. В настоящее время я изменяю размер в зависимости от размера, как добиться того же, исходя из времени, когда определенная продолжительность бездействия, очистит несколько ресурсов из очереди, тем самым уменьшив размер.

Важные детали:

  1. Использование ConcurrentQueue для внутренних потоков безопасного доступа к ресурсам, от нескольких клиентов
  2. Используйте AutoResetEvent для ожидания и сигнала, если пул пуст
  3. Использование TPL для операции изменения размера, не останавливая код вызова, я понимаю, что это работа, даже когда клиентский вызов возвращается, поскольку его на Threadpool thread

    class ExasolConnectionPool 
    { 
        /// <summary> 
        /// Thread safe queue for storing the connection objects 
        /// </summary> 
        private ConcurrentQueue<EXAConnection> ExasolConnectionQueue { get; set; } 
    
        /// <summary> 
        /// Number of connections on the Connection pool 
        /// </summary> 
        private int _connectionCount; 
    
        /// <summary> 
        /// Max Pool Size 
        /// </summary> 
        private int MaxPoolSize { get; set; } 
    
        /// <summary> 
        /// Min Pool Size 
        /// </summary> 
        private int MinPoolSize { get; set; } 
    
        /// <summary> 
        /// Increase in Pool Size 
        /// </summary> 
        private int IncreasePoolSize { get; set; } 
    
        /// <summary> 
        /// Decrease in Pool Size 
        /// </summary> 
        private int DecreasePoolSize { get; set; } 
    
        /// <summary> 
        /// Connection string for the Connection pool connections 
        /// </summary> 
        private string ConnectionString { get; set; } 
    
        /// <summary> 
        /// Auto Reset event for the connection pool 
        /// </summary> 
        private AutoResetEvent ExasolConnectionPoolAre { get; set; } 
    
        /// <summary> 
        /// Connection pool specific Lock object 
        /// </summary> 
        private readonly object lockObject; 
    
        /// <summary> 
        /// Connection pool constructor 
        /// </summary> 
        /// <param name="connectionString"></param> 
        /// <param name="poolSize"></param> 
        public ExasolConnectionPool(string connectionString, int poolSize = 10) 
        { 
         // Set the Connection String 
         ConnectionString = connectionString; 
    
         // Intialize the Connection Queue 
         ExasolConnectionQueue = new ConcurrentQueue<EXAConnection>(); 
    
         // Enqueue initial set of connections 
         for (int counter = 0; counter < poolSize; counter++) 
         { 
          var exaConnection = new EXAConnection {ConnectionString = ConnectionString}; 
    
          ExasolConnectionQueue.Enqueue(exaConnection); 
         } 
    
         // Initialize Lock object 
         lockObject = new object(); 
    
         // Set the Connection queue count 
         _connectionCount = poolSize; 
    
         // Max pool size 
         MaxPoolSize = poolSize; 
    
         // Min Pool Size 
         MinPoolSize = 2; 
    
         IncreasePoolSize = 5; 
    
         DecreasePoolSize = 3; 
    
         ExasolConnectionPoolAre = new AutoResetEvent(false); 
        } 
    
        /// <summary> 
        /// 
        /// </summary> 
        /// <returns></returns> 
        public EXAConnection GetConnection() 
        { 
         // Return ExaConnection object 
         EXAConnection returnConnection; 
    
         // Try Dequeue the connection object from the Concurrent Queue 
         var validExasolConnection = ExasolConnectionQueue.TryDequeue(out returnConnection); 
    
         // If No Valid connection is available, then wait using AutoReset signaling mechanism 
         while (!validExasolConnection) 
         { 
          ExasolConnectionPoolAre.WaitOne(); 
    
          validExasolConnection = ExasolConnectionQueue.TryDequeue(out returnConnection); 
         } 
    
         // Thread safe connection count update 
         Interlocked.Decrement(ref _connectionCount); 
    
         Task.Factory.StartNew(() => 
         { 
          lock (lockObject) 
          { 
           if (_connectionCount > MinPoolSize) return; 
    
           for (var counter = 0; counter < IncreasePoolSize; counter++) 
           { 
            var exaConnection = new EXAConnection {ConnectionString = ConnectionString}; 
    
            ExasolConnectionQueue.Enqueue(exaConnection); 
    
            Interlocked.Increment(ref _connectionCount); 
           } 
          } 
         }); 
    
         return (returnConnection); 
        } 
    
        /// <summary> 
        /// 
        /// </summary> 
        /// <param name="returnedConnection"></param> 
        public void ReturnConnection(EXAConnection returnedConnection) 
        { 
         ExasolConnectionQueue.Enqueue(returnedConnection); 
    
         Interlocked.Increment(ref _connectionCount); 
    
         ExasolConnectionPoolAre.Set(); 
    
         Task.Factory.StartNew(() => 
         { 
          lock (lockObject) 
          { 
           if (_connectionCount < MaxPoolSize * 1.5) return; 
    
           for (var counter = 0; counter < DecreasePoolSize; counter++) 
           { 
            EXAConnection exaConnection; 
    
            if (ExasolConnectionQueue.TryDequeue(out exaConnection)) 
            { 
             exaConnection.Dispose(); 
    
             exaConnection = null; 
    
             Interlocked.Decrement(ref _connectionCount); 
            } 
           } 
          } 
         }); 
        } 
    } 
    

ответ

1

Реализация для вашего бассейна в порядке. Я не осведомлен о каких-либо реализациях NuGet, которые являются такими маленькими и не слишком сложными для вашего дела. Я просто хочу добавить небольшое количество предложений, которые вы можете исследовать самостоятельно.

  1. StartNew is Dangerous статья Стивен Клири велик пост о методе, который вы используете для изменения размера логики. Наиболее важная часть заключается в следующем:

    тему «А» будет работать на любой TaskScheduler является в настоящее время исполнения!

    Так что ваш код иногда может использовать контекст потока в UI и снизить производительность вашего приложения. Если это нормально для вас (например, для приложения ASP.NET), хорошо, но если нет, я предлагаю вам вместо этого использовать метод Task.Run. Вы также можете изучить блог Стефана относительно TPL лучших практик.

  2. В общем, логика изменения размера выполняется простым способом с удвоением размера, поэтому, если вы достигли предела, размер стал вдвое больше, а наоборот - уменьшался. Я думаю, что предоставление пользователям возможности управлять этими константами может привести к некоторым странным ошибкам, таким как отрицательный размер пула и тому подобное.

    Так что вы должны сделать свой набор свойств как private и, как для меня, удалить свойства, касающиеся изменения размера. Возможно, в будущем вы можете собрать статистику для размера пула в среднем для своего приложения и использовать этот параметр по умолчанию.

+0

Спасибо за обзор и важные детали.Для изменения размера, поскольку объект соединения является дорогостоящим ресурсом, поэтому, в отличие от стандартных пулов ресурсов, предпочтет управляемый механизм изменения размера, время от времени незанятое открытое соединение за определенную продолжительность будет пустой тратой ресурса, которую можно воссоздать. В других пулах ресурсов они также увеличивают размер коллекции путем удвоения, а не фактических объектов, которые все еще необходимо создавать/добавлять по необходимости. –

+0

Для различных свойств, как вы могли заметить, они являются частными объектами, но, как и любой стандартный пул соединений, пользователь должен настроить его, с определенными проверками, чтобы избежать исключения –

+0

Да, это было просто наблюдение. Я думаю, вы знаете, что делаете, так что удачи в вашем проекте :) – VMAtm

Смежные вопросы