You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 6中StackExchange.Redis连接池缺失add_ServerMaintenanceEvent实现

问题分析与解决方案

异常根源

这个异常是版本兼容性问题:你使用的StackExchange.Redis.MultiplexerPool(1.0.2版本)与当前依赖的StackExchange.Redis主库版本不匹配。新版本的StackExchange.Redis在IConnectionMultiplexer接口中新增了ServerMaintenanceEvent事件,但MultiplexerPool库的内部实现类InternalDisposableConnectionMultiplexer没有实现该事件的add_ServerMaintenanceEvent/remove_ServerMaintenanceEvent方法,导致类型加载失败。

解决步骤

1. 版本对齐修复

  • 查看StackExchange.Redis.MultiplexerPool的兼容说明,将StackExchange.Redis主库版本降级到与MultiplexerPool 1.0.2匹配的版本(通常是StackExchange.Redis 2.x系列,比如2.6.70及以下)。
  • 或者直接升级StackExchange.Redis.MultiplexerPool到最新版,确保其与当前StackExchange.Redis版本兼容。

2. 代码实现优化(附带问题修正)

除了版本问题,你的类库实现还有几个需要调整的点:

(1)配置硬编码问题

LibraryRedisCacheService构造函数中硬编码了连接字符串,应该从配置注入,保持类库灵活性:

// 修改构造函数,接收配置参数
public LibraryRedisCacheService(IConfiguration configuration)
{
    var connectionString = configuration.GetValue<string>("Redis:ConnectionString");
    var configureOptions = ConfigurationOptions.Parse(connectionString);
    configureOptions.AllowAdmin = true;
    configureOptions.AsyncTimeout = 10000;

    _connectionMultiplexerPool = ConnectionMultiplexerPoolFactory.Create(
        poolSize: 10,
        configurationOptions: configureOptions,
        connectionSelectionStrategy: ConnectionSelectionStrategy.RoundRobin);
    
    _connectionsErrorCount = new int[_connectionMultiplexerPool.PoolSize];
}

(2)错误计数索引逻辑错误

原代码中_connectionsErrorCount[connection.ConnectionIndex++]会导致错误计数对应到下一个连接的索引,修正为:

catch (RedisConnectionException)
{
    var currentIndex = connection.ConnectionIndex;
    _connectionsErrorCount[currentIndex]++;

    if (_connectionsErrorCount[currentIndex] < 3)
    {
        throw;
    }

    await connection.ReconnectAsync();
    return await op(connection.Connection.GetDatabase());
}

(3)递归重试的栈溢出风险

SetCacheAsync和GetCacheAsync使用递归重试,高重试次数可能导致栈溢出,改为循环实现:

public async Task SetCacheAsync<T>(string key, T value, TimeSpan? expiry = null)
{
    int currentRetry = 0;
    while (currentRetry <= 3)
    {
        try
        {
            await QueryRedisAsync(async db => await db.StringSetAsync(key, JsonConvert.SerializeObject(value), expiry ?? TimeSpan.FromHours(12)));
            return;
        }
        catch (Exception)
        {
            if (currentRetry >= 3) throw;
            await Task.Delay(3000);
            currentRetry++;
        }
    }
}

(4)DI注册优化

原注册方式直接实例化Library1,没有利用DI容器的依赖注入能力,改为让Library1通过构造函数注入缓存服务:

// 先注册缓存服务
services.AddSingleton<LibraryRedisCacheService>();
// 注册类库,让容器自动注入依赖
services.AddSingleton<ILibrary1, Library1>(sp => 
    new Library1(sp.GetRequiredService<IConfiguration>(), "KeyvaultReference", sp.GetRequiredService<LibraryRedisCacheService>()));

// 修改Library1的构造函数
public class Library1 : ILibrary1
{
    private readonly LibraryRedisCacheService _redisClient;

    public Library1(IConfiguration configuration, string azureOptionsKey, LibraryRedisCacheService redisClient)
    {
        configuration.Bind(azureOptionsKey, azureOptions);
        _redisClient = redisClient;
    }
}

3. 替代方案(如果MultiplexerPool不再维护)

如果StackExchange.Redis.MultiplexerPool已经停止维护,建议直接使用StackExchange.Redis原生的ConnectionMultiplexer:

  • ConnectionMultiplexer本身是线程安全的,单实例即可支撑高并发场景,大部分情况下不需要额外的连接池。
  • 若确实需要多连接实例,可以自己封装一个简单的连接池,基于List<IConnectionMultiplexer>实现轮询或其他选择策略。

内容的提问来源于stack exchange,提问作者user3501613

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 00:10:20