一、为什么需要分布式缓存高可用

在互联网应用中,缓存是提升性能的利器。想象一下,每次用户请求都要从数据库查询数据,数据库的压力会有多大?尤其是高并发场景下,数据库很容易成为瓶颈。而分布式缓存可以将热点数据存放在内存中,减少数据库访问,提高响应速度。

但问题来了——如果缓存挂了怎么办?比如 Redis 某个节点宕机,或者网络抖动导致缓存不可用,这时候如果没有高可用方案,系统可能会直接崩溃。所以,我们需要一套高可用的分布式缓存架构,确保即使部分节点故障,系统仍能正常运行。

二、DotNetCore 中常用的分布式缓存方案

在 .NET Core 生态中,常用的分布式缓存方案有:

  1. Redis(最主流,支持集群和哨兵模式)
  2. Memcached(简单高效,但功能较少)
  3. SQL Server 分布式缓存(基于数据库,适合小规模应用)
  4. NCache(商业方案,性能优秀)

这篇文章我们以 Redis 为例,因为它功能强大、社区活跃,并且天然支持高可用架构。

三、Redis 高可用方案选型

Redis 的高可用方案主要有两种:

  1. Redis Sentinel(哨兵模式)

    • 自动监控主从节点,主节点宕机时自动切换
    • 适合中小规模应用
    • 配置简单,但集群管理能力较弱
  2. Redis Cluster(集群模式)

    • 数据分片存储,支持横向扩展
    • 自动故障转移,适合大规模应用
    • 配置复杂,但扩展性强

我们选择 Redis Sentinel 作为示例,因为它更贴合大多数 .NET Core 应用的需求。

四、在 DotNetCore 中集成 Redis Sentinel

4.1 环境准备

假设我们已经搭建了 Redis Sentinel 环境:

  • 1 个主节点(Master)
  • 2 个从节点(Slave)
  • 3 个哨兵节点(Sentinel)

4.2 安装必要的 NuGet 包

dotnet add package StackExchange.Redis

4.3 配置 Redis Sentinel 连接

using StackExchange.Redis;
using System;

public class RedisService
{
    private static ConnectionMultiplexer _redis;

    public static IDatabase GetDatabase()
    {
        if (_redis == null || !_redis.IsConnected)
        {
            // Sentinel 节点地址
            var sentinelEndPoints = new[]
            {
                new { Host = "sentinel1", Port = 26379 },
                new { Host = "sentinel2", Port = 26379 },
                new { Host = "sentinel3", Port = 26379 }
            };

            // 配置连接
            var options = new ConfigurationOptions
            {
                ServiceName = "mymaster",  // Sentinel 监控的主节点名称
                TieBreaker = "",           // 禁用 TieBreaker
                DefaultVersion = new Version("6.2.0"), // Redis 版本
                CommandMap = CommandMap.Sentinel,      // 使用 Sentinel 模式
                AbortOnConnectFail = false,            // 连接失败不抛出异常
                AllowAdmin = true                      // 允许执行管理命令
            };

            // 添加 Sentinel 节点
            foreach (var ep in sentinelEndPoints)
            {
                options.EndPoints.Add(ep.Host, ep.Port);
            }

            _redis = ConnectionMultiplexer.Connect(options);
        }

        return _redis.GetDatabase();
    }
}

4.4 使用示例

// 写入缓存
var db = RedisService.GetDatabase();
db.StringSet("user:1001", "John Doe", TimeSpan.FromMinutes(10));

// 读取缓存
var userName = db.StringGet("user:1001");
Console.WriteLine($"User name: {userName}");

五、高可用架构的优化策略

5.1 多级缓存(本地缓存 + Redis)

如果 Redis 不可用,可以短暂降级到本地缓存:

using Microsoft.Extensions.Caching.Memory;

public class HybridCacheService
{
    private readonly IDatabase _redis;
    private readonly IMemoryCache _localCache;

    public HybridCacheService(IDatabase redis, IMemoryCache localCache)
    {
        _redis = redis;
        _localCache = localCache;
    }

    public string GetUser(string userId)
    {
        // 先查本地缓存
        if (_localCache.TryGetValue($"user:{userId}", out string userName))
        {
            return userName;
        }

        // 本地缓存没有,查 Redis
        userName = _redis.StringGet($"user:{userId}");

        if (userName != null)
        {
            // 写入本地缓存,有效期 1 分钟
            _localCache.Set($"user:{userId}", userName, TimeSpan.FromMinutes(1));
        }

        return userName;
    }
}

5.2 缓存雪崩防护

大量缓存同时失效会导致数据库压力激增,解决方案:

// 设置随机过期时间,避免同时失效
var random = new Random();
var expiry = TimeSpan.FromMinutes(10).Add(TimeSpan.FromSeconds(random.Next(0, 60)));
db.StringSet("cache_key", "value", expiry);

六、应用场景与注意事项

6.1 适用场景

  1. 电商秒杀:高并发读取商品信息
  2. 社交网络:热点数据(如用户资料)缓存
  3. 实时排行榜:利用 Redis 的 SortedSet 实现

6.2 技术优缺点

优点

  • 高性能(微秒级响应)
  • 高可用(Sentinel 自动故障转移)
  • 支持丰富的数据结构

缺点

  • 内存成本高
  • 集群配置较复杂

6.3 注意事项

  1. 监控:使用 INFO 命令监控 Redis 状态
  2. 持久化:配置 RDBAOF 防止数据丢失
  3. 内存优化:使用 Hash 结构节省内存

七、总结

分布式缓存高可用是 .NET Core 应用的必备技能。通过 Redis Sentinel,我们可以构建一个自动容错的缓存系统,再结合多级缓存、雪崩防护等策略,让系统更加健壮。

如果你的应用还在裸奔式使用单机 Redis,是时候考虑升级到高可用架构了!