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