我们正在使用内存数据库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);
}
}
}
});
}
}
答案 0 :(得分:1)
您的游泳池的实施很好。我不知道任何NuGet实现对于您的情况来说很小并且不会过于复杂。我只想添加一些您可以自行调查的建议。
StartNew
is Dangerous文章是关于您用于调整逻辑大小的方法的精彩帖子。最重要的部分是:
线程&#34; A&#34;将在
TaskScheduler
当前正在执行的任何内容上运行!
因此,您的代码有时可能会使用UI
线程上下文并降低应用程序的性能。如果你没问题(例如对于ASP.NET应用程序),那很好,但如果没有,我建议你改用Task.Run
方法。您还可以查看Stephen关于TPL
最佳做法的博客。
一般来说,调整大小的逻辑是以一种简单的方式完成的,大小加倍,所以如果你达到了极限,那么大小变为两倍,反之亦然。我认为为用户提供管理此常量的能力可能会导致一些奇怪的错误,例如负池大小和类似错误。
因此,您应该将属性设置器设置为private
,并且就我而言,删除有关调整大小的属性。也许将来您可以收集应用程序平均池大小的统计信息,并将该参数用作默认值。