Пул пользовательских подключений для провайдера Exasol Ado.Net
Мы используем базу данных в памяти Exasol
, который предоставляет провайдера Ado.Net, но, похоже, не хватает некоторых важных функций, таких как ConnectionPooling
таким образом, каждое соединение создается и уничтожается по запросу, что влияет на нашу производительность, так как мы подключаемся к размещенной базе данных на AWS
, Я создал простой ConnectionPool
со способностью Resize
Пожалуйста, предложите, если это послужит цели или мне нужно сделать что-то еще.
Обратите внимание, что я не ищу рецензирование кода, а критический анализ того, что мне может не хватать в текущей реализации, а также, если есть реализация (Nuget, Git), которую я могу использовать повторно. В настоящее время я изменяю размер в зависимости от размера, как добиться того же в зависимости от времени, при котором определенная продолжительность простоя должна вычистить несколько ресурсов из очереди, уменьшив таким образом размер.
Важные детали:
- использование
ConcurrentQueue
внутренне для потокового безопасного доступа к ресурсам от нескольких клиентов - использование
AutoResetEvent
для ожидания и сигнала, если пул пуст использование
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, которые настолько малы и не слишком сложны для вашего случая. Я просто хочу добавить небольшое количество предложений, которые вы можете изучить самостоятельно.
StartNew
Опасная статья Стивена Клири - отличный пост о методе, который вы используете для изменения размера логики. Самая важная часть это:Поток "А" будет работать на что угодно
TaskScheduler
в настоящее время выполняется!Так что ваш код иногда может использовать
UI
нить контекст и ухудшить производительность вашего приложения. Если это нормально для вас (например, для приложения ASP.NET), хорошо, но если нет, я предлагаю вам использоватьTask.Run
метод вместо. Вы также можете изучить блог Стивена относительноTPL
лучшие практики.В общем, логика изменения размера выполняется простым способом, с удвоением размера, поэтому, если вы достигли предела, размер увеличился вдвое, и наоборот, для уменьшения. Я думаю, что предоставление пользователям возможности управлять этими константами может привести к некоторым странным ошибкам, таким как отрицательный размер пула и тому подобное.
Таким образом, вы должны сделать ваши свойства установщиков как
private
и, как по мне, удалите свойства, касающиеся изменения размера. Возможно, в будущем вы сможете собрать статистику для среднего размера пула для вашего приложения и использовать этот параметр по умолчанию.