StackExchange.Redis 实现最小负载连接时出现问题
Problem in implementing least loaded connection for StackExchange.Redis
基于以下答案,我为 StackExchange.Redis
实现了 least loaded
连接:
public class RedisConnectionWrapper : IRedisConnectionWrapper
{
#region Fields
private readonly Config _config;
private bool _disposed = false;
private readonly Lazy<string> _connectionString;
private static ConcurrentBag<Lazy<ConnectionMultiplexer>> _connections;
#endregion
#region Ctor
public RedisConnectionWrapper(Config config)
{
_config = config;
_connectionString = new Lazy<string>("CONNECTION_STRING");
ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", _config.RedisPreventThreadTheft);
if (_config.UseLeastLoadedConnection)
InitializeLeastLoadedConnections();
}
#endregion
/// <summary>
/// Initialize lazy connections to Redis servers
/// </summary>
/// <returns></returns>
private void InitializeLeastLoadedConnections()
{
_connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (var i = 0; i < _config.PoolSize; i++)
{
var connection = ConnectionMultiplexer.Connect(_connectionString.Value);
connection.IncludePerformanceCountersInExceptions = true;
_connections.Add(new Lazy<ConnectionMultiplexer>(connection));
}
}
/// <summary>
/// Get least loaded connection to Redis servers
/// </summary>
/// <returns></returns>
protected ConnectionMultiplexer GetLeastLoadedConnection()
{
Lazy<ConnectionMultiplexer> connection;
var loadedLazys = _connections.Where(lazy => lazy.IsValueCreated && lazy.Value.IsConnected);
if (loadedLazys.Count() == _connections.Count)
{
var minValue = _connections.Min(lazy => lazy.Value.GetCounters().TotalOutstanding);
connection = _connections.First(lazy => lazy.Value.GetCounters().TotalOutstanding == minValue);
}
else
{
Console.WriteLine("Creating a new connection to Redis");
connection = _connections.First(lazy => !lazy.IsValueCreated);
}
return connection.Value;
}
/// <summary>
/// Release all resources associated with this object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (_config.UseLeastLoadedConnection)
{
var activeConnections = _connections.Where(lazy => lazy.IsValueCreated).ToList();
activeConnections.ForEach(connection => connection.Value.Dispose());
}
}
_disposed = true;
}
但我在高流量时遇到此异常:
System.InvalidOperationException: Sequence contains no matching element
at System.Linq.ThrowHelper.ThrowNoMatchException()
at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate)
有人可以帮助我吗?
经过一些追踪,我做了一些修改,它起作用了:
var loadedLazys = _connections.Where(lazy => lazy.IsValueCreated);
if (loadedLazys.Count() == _connections.Count)
{
connection = _connections.OrderBy(lazy => lazy.Value.GetCounters().TotalOutstanding).First();
}
我也更改了这部分代码:
private void InitializeLeastLoadedConnections()
{
lock (_lock)
{
_connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (var i = 0; i < _config.PoolSize; i++)
{
_connections.Add(new Lazy<ConnectionMultiplexer>(() =>
{
var connection = ConnectionMultiplexer.Connect(_connectionString.Value);
connection.IncludePerformanceCountersInExceptions = true;
return connection;
}));
}
}
}
另外,我将 GetLeastLoadedConnection()
的 return 类型从 ConnectionMultiplexer
更改为 IConnectionMultiplexer
。
基于以下答案,我为 StackExchange.Redis
实现了 least loaded
连接:
public class RedisConnectionWrapper : IRedisConnectionWrapper
{
#region Fields
private readonly Config _config;
private bool _disposed = false;
private readonly Lazy<string> _connectionString;
private static ConcurrentBag<Lazy<ConnectionMultiplexer>> _connections;
#endregion
#region Ctor
public RedisConnectionWrapper(Config config)
{
_config = config;
_connectionString = new Lazy<string>("CONNECTION_STRING");
ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", _config.RedisPreventThreadTheft);
if (_config.UseLeastLoadedConnection)
InitializeLeastLoadedConnections();
}
#endregion
/// <summary>
/// Initialize lazy connections to Redis servers
/// </summary>
/// <returns></returns>
private void InitializeLeastLoadedConnections()
{
_connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (var i = 0; i < _config.PoolSize; i++)
{
var connection = ConnectionMultiplexer.Connect(_connectionString.Value);
connection.IncludePerformanceCountersInExceptions = true;
_connections.Add(new Lazy<ConnectionMultiplexer>(connection));
}
}
/// <summary>
/// Get least loaded connection to Redis servers
/// </summary>
/// <returns></returns>
protected ConnectionMultiplexer GetLeastLoadedConnection()
{
Lazy<ConnectionMultiplexer> connection;
var loadedLazys = _connections.Where(lazy => lazy.IsValueCreated && lazy.Value.IsConnected);
if (loadedLazys.Count() == _connections.Count)
{
var minValue = _connections.Min(lazy => lazy.Value.GetCounters().TotalOutstanding);
connection = _connections.First(lazy => lazy.Value.GetCounters().TotalOutstanding == minValue);
}
else
{
Console.WriteLine("Creating a new connection to Redis");
connection = _connections.First(lazy => !lazy.IsValueCreated);
}
return connection.Value;
}
/// <summary>
/// Release all resources associated with this object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (_config.UseLeastLoadedConnection)
{
var activeConnections = _connections.Where(lazy => lazy.IsValueCreated).ToList();
activeConnections.ForEach(connection => connection.Value.Dispose());
}
}
_disposed = true;
}
但我在高流量时遇到此异常:
System.InvalidOperationException: Sequence contains no matching element at System.Linq.ThrowHelper.ThrowNoMatchException() at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate)
有人可以帮助我吗?
经过一些追踪,我做了一些修改,它起作用了:
var loadedLazys = _connections.Where(lazy => lazy.IsValueCreated);
if (loadedLazys.Count() == _connections.Count)
{
connection = _connections.OrderBy(lazy => lazy.Value.GetCounters().TotalOutstanding).First();
}
我也更改了这部分代码:
private void InitializeLeastLoadedConnections()
{
lock (_lock)
{
_connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (var i = 0; i < _config.PoolSize; i++)
{
_connections.Add(new Lazy<ConnectionMultiplexer>(() =>
{
var connection = ConnectionMultiplexer.Connect(_connectionString.Value);
connection.IncludePerformanceCountersInExceptions = true;
return connection;
}));
}
}
}
另外,我将 GetLeastLoadedConnection()
的 return 类型从 ConnectionMultiplexer
更改为 IConnectionMultiplexer
。