StackExchange.Redis实现最小负载连接高并发下异常问题求助
异常触发原因
- 核心问题1:Lazy初始化逻辑错误。你在创建
Lazy<ConnectionMultiplexer>时,直接传入了已经调用Connect生成的连接实例,这会导致所有Lazy实例的IsValueCreated属性在初始化阶段就为true,完全失去了延迟加载的作用。当出现已创建的连接断开的情况时,loadedLazys.Count() < _connections.Count会进入else分支,此时调用First(lazy => !lazy.IsValueCreated)永远找不到匹配元素,直接抛出异常。 - 核心问题2:高并发下的竞态条件。你对
ConcurrentBag的多次LINQ枚举没有取快照,两次操作(Count判断、First取值)之间连接的状态(是否已连接、未处理请求数)可能已经发生变化,导致First找不到符合条件的元素。 - 边缘场景问题:如果连接池内所有连接都处于断开状态,不管走哪个分支都会找不到符合条件的连接,触发异常。
修复方案
第一步:修正Lazy初始化逻辑
把连接创建逻辑放到Lazy的工厂委托中,实现真正的延迟初始化:
private void InitializeLeastLoadedConnections() { _connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>(); for (var i = 0; i < _config.PoolSize; i++) { // 把连接逻辑放到Lazy的工厂委托里,不要提前Connect _connections.Add(new Lazy<ConnectionMultiplexer>(() => { var connection = ConnectionMultiplexer.Connect(_connectionString.Value); connection.IncludePerformanceCountersInExceptions = true; return connection; })); } }
第二步:优化连接获取逻辑,解决竞态问题
先取连接池快照,避免多次枚举的状态不一致,同时增加空值判断和降级逻辑:
protected ConnectionMultiplexer GetLeastLoadedConnection() { // 先取连接池快照,避免后续操作过程中集合变化 var connectionsSnapshot = _connections.ToList(); // 筛选已创建且可用的连接 var validConnections = connectionsSnapshot .Where(l => l.IsValueCreated && l.Value.IsConnected) .ToList(); // 情况1:有可用的已初始化连接,选负载最小的 if (validConnections.Any()) { var minOutstanding = validConnections.Min(l => l.Value.GetCounters().TotalOutstanding); return validConnections.First(l => l.Value.GetCounters().TotalOutstanding == minOutstanding).Value; } // 情况2:没有可用的已初始化连接,找未初始化的Lazy触发初始化 var uninitializedConnection = connectionsSnapshot.FirstOrDefault(l => !l.IsValueCreated); if (uninitializedConnection != null) { Console.WriteLine("Creating a new connection to Redis"); return uninitializedConnection.Value; } // 情况3:所有连接都已初始化但不可用,抛出明确异常或者触发连接池重建逻辑 throw new InvalidOperationException("No available Redis connections in pool, all connections are disconnected"); }
可选优化点
- 可以在情况3触发时自动重建连接池,或者扩容连接池,提升可用性
- 高并发场景下可以对连接获取逻辑加轻量级锁,避免多个线程同时触发不必要的连接创建
- 增加连接健康检查逻辑,定期清理已经断开的连接,补充新的连接到池中
内容的提问来源于stack exchange,提问作者Milad Sadri
相关产品推荐
相关产品推荐

