.NET Core 2.0中IDistributedCache结合Redis哨兵主从配置的技术问询
我刚好在.NET Core 2.0项目里配置过Redis哨兵+主从结合IDistributedCache的场景,给你详细说说怎么配置以及它是怎么处理主从和故障转移的:
配置Redis哨兵与主从的IDistributedCache
首先得明确,.NET Core 2.0中IDistributedCache的Redis实现依赖Microsoft.Extensions.Caching.Redis包,它底层基于StackExchange.Redis客户端,而这个客户端原生支持Redis哨兵和主从模式。
1. 安装依赖包
先在你的项目中安装对应版本的NuGet包:
Install-Package Microsoft.Extensions.Caching.Redis -Version 2.0.0
(这个版本和.NET Core 2.0匹配,会自动引入StackExchange.Redis的兼容版本)
2. 配置哨兵连接信息
在appsettings.json中添加Redis相关配置,重点是指定哨兵节点地址和监控的主节点名称:
"RedisCache": { "Configuration": "sentinel-node-1:26379,sentinel-node-2:26379,sentinel-node-3:26379,serviceName=my-redis-master", "InstanceName": "MyWebAPI:" }
sentinel-node-x:26379:你的哨兵集群节点地址和端口(默认哨兵端口是26379)serviceName=my-redis-master:哨兵集群监控的主节点名称,必须和你Redis主从集群中配置的名称一致InstanceName:缓存键的前缀,避免不同应用的缓存键冲突
3. 注册IDistributedCache服务
在Startup.cs的ConfigureServices方法中,注册分布式Redis缓存服务:
public void ConfigureServices(IServiceCollection services) { // 注册Redis分布式缓存 services.AddDistributedRedisCache(options => { options.Configuration = Configuration.GetSection("RedisCache")["Configuration"]; options.InstanceName = Configuration.GetSection("RedisCache")["InstanceName"]; }); // 其他服务注册,比如Mvc services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_0); }
主从场景的处理逻辑
配置完成后,客户端会自动处理主从节点的路由:
- 写操作(Set、Remove、Refresh等):所有写入类的操作都会被自动路由到主节点,保证数据的一致性,主节点会异步将数据同步到各个从节点
- 读操作(Get、GetAsync等):默认情况下,读请求会被分发到各个从节点,实现读负载均衡,减轻主节点的压力
- 你不需要手动指定操作的节点,StackExchange.Redis客户端会自动完成路由逻辑
故障转移的处理
当主节点发生故障时,整个流程对你的Web API是近乎透明的:
- 哨兵集群检测故障:哨兵节点会定期监控主节点状态,当发现主节点不可达时,会发起故障转移流程
- 选举新主节点:哨兵集群会从当前的从节点中选举出一个新的主节点,并更新集群的主从关系
- 客户端自动感知:StackExchange.Redis的
ConnectionMultiplexer会定期和哨兵通信,获取最新的主节点信息,自动切换后续写操作的目标节点 - 读写恢复正常:读操作会继续路由到剩余的从节点,新主节点会接管所有写操作,数据同步会在新的主从之间重新建立
注意事项
- 故障转移过程中可能会有几秒的短暂不可用,客户端会自动重试,你可以在配置中添加
connectRetry=3(重试次数)、connectTimeout=5000(连接超时,单位毫秒)等参数优化体验 - 哨兵集群至少要部署3个节点,避免出现脑裂问题,保证集群的高可用
- 如果需要强制某些读操作走主节点(比如需要读取刚写入的数据),可以通过自定义
IDistributedCache实现,手动指定CommandFlags.PreferMaster来路由请求
自定义读写路由(可选)
如果你需要更精细的控制读写策略,比如某些场景下强制读主节点,可以自定义一个IDistributedCache的实现:
public class CustomRedisCache : IDistributedCache { private readonly IDistributedCache _innerCache; private readonly ConnectionMultiplexer _connectionMultiplexer; private readonly string _instanceName; public CustomRedisCache(IDistributedCache innerCache, IConnectionMultiplexer connectionMultiplexer, IConfiguration configuration) { _innerCache = innerCache; _connectionMultiplexer = connectionMultiplexer; _instanceName = configuration.GetSection("RedisCache")["InstanceName"]; } // 示例:强制Get操作读取主节点 public byte[] Get(string key) { var fullKey = $"{_instanceName}{key}"; var db = _connectionMultiplexer.GetDatabase(); return db.StringGet(fullKey, CommandFlags.PreferMaster); } // 其他方法直接复用原生实现 public Task<byte[]> GetAsync(string key, CancellationToken token = default) { return _innerCache.GetAsync(key, token); } public void Set(string key, byte[] value, DistributedCacheEntryOptions options) { _innerCache.Set(key, value, options); } // 实现剩余的IDistributedCache方法... }
然后在Startup.cs中替换原生服务:
// 先注册ConnectionMultiplexer services.AddSingleton<IConnectionMultiplexer>(sp => { var configString = Configuration.GetSection("RedisCache")["Configuration"]; var config = ConfigurationOptions.Parse(configString); return ConnectionMultiplexer.Connect(config); }); // 注册原生Redis缓存 services.AddDistributedRedisCache(options => { options.Configuration = Configuration.GetSection("RedisCache")["Configuration"]; options.InstanceName = Configuration.GetSection("RedisCache")["InstanceName"]; }); // 替换为自定义实现 services.AddSingleton<IDistributedCache, CustomRedisCache>();
内容的提问来源于stack exchange,提问作者Abhay
相关产品推荐
相关产品推荐

