StackExchange.Redis 是当前 C# 项目最该用的 Redis 客户端,因其线程安全、高性能、支持连接池且被 .NET 生态广泛验证;微软示例、AspNetCore IDistributedCache 及 Ocelot、CAP 等框架均默认采用它。

为什么 StackExchange.Redis 是当前 C# 项目里最该用的 Redis 客户端
因为它是线程安全、高性能、支持连接池、且被 .NET 生态广泛验证的首选。微软官方示例、AspNetCore 的 IDistributedCache 实现、以及主流微服务框架(如 Ocelot、CAP)默认都基于它。别用 ServiceStack.Redis —— 商业授权模糊,社区版功能受限;也别手写 Socket 封装 —— 连接复用、超时重试、管道批处理这些细节够你调三天。
安装只需:
dotnet add package StackExchange.Redis
常见踩坑点:
- 直接 new ConnectionMultiplexer("localhost") 而不复用实例 → 内存泄漏 + 连接数爆满
- 没配置
abortConnect=false→ Redis 临时不可用时整个应用抛RedisConnectionException - 用
GetDatabase().StringGet("key")却忘了返回值可能是RedisValue.Null→ 直接 ToString() 得到空字符串,不是 null
如何安全初始化并复用 ConnectionMultiplexer
ConnectionMultiplexer 是重量级对象,必须全局单例(或按连接串分组单例),不能每次操作都 new。它内部维护连接池、心跳检测、自动重连逻辑。
推荐做法:
private static readonly Lazy<connectionmultiplexer> LazyConnection = new(() =>
{
var options = ConfigurationOptions.Parse("localhost:6379");
options.AbortOnConnectFail = false;
options.ConnectTimeout = 5000;
options.SyncTimeout = 5000;
return ConnectionMultiplexer.Connect(options);
});
<p>public static ConnectionMultiplexer Connection => LazyConnection.Value;</p></connectionmultiplexer>
关键参数说明:
-
AbortOnConnectFail = false:首次连接失败不抛异常,后续自动重试 -
ConnectTimeout和SyncTimeout必须显式设,否则默认是 -1(无限等待) - 如果用 Docker 或云 Redis,记得把
localhost换成真实地址,并确认端口开放、防火墙放行
StringSet/StringGet 怎么避免空值陷阱和类型混淆
StringSet 和 StringGet 是最常用的操作,但返回值类型容易误判:StringGet 返回 RedisValue,它是个 struct,支持隐式转 string/int/bool,但对 null 值不敏感。
正确判断是否存在 key:
var db = Connection.GetDatabase();
var value = db.StringGet("user:1001");
if (!value.IsNull) // ✅ 别用 value == null 或 string.IsNullOrEmpty(value)
{
var userJson = value;
}
存取复杂对象建议:
- 不要直接
StringSet("key", obj)——RedisValue没内置序列化 - 先用
System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(obj)序列化为 byte[],再传给StringSet(key, bytes) - 读取时用
StringGet拿到 byte[],再反序列化 - 如果项目已用 Newtonsoft.Json,注意
JsonConvert.SerializeObject返回 string,需转 UTF8 byte[] 再存
缓存失效策略怎么配才不翻车
Redis 本身只支持 TTL(过期时间),没有“主动失效”或“依赖变更”机制。C# 层必须自己协调。
典型组合方案:
- 写数据时:先
StringSet("user:1001", json, TimeSpan.FromMinutes(30)),再删掉相关列表缓存(如db.KeyDelete("users:all")) - 读数据时:若
StringGet返回IsNull,查 DB,成功后立刻StringSet回 Redis(注意加锁防缓存击穿,可用LockTake+LockRelease) - 慎用
KeyExpire单独设过期 —— 容易和StringSet的过期冲突,优先在StringSet里带TimeSpan参数
特别注意:Redis 的过期是惰性+定期删除混合策略,EXPIRE 不等于“精确到秒失效”,高并发下可能延迟几秒。业务强时效场景(如支付倒计时),得靠应用层二次校验或用 Redis 的 PEXPIREAT + 时间戳控制。










