ASP.NET Core 6+ 应使用 Microsoft.Extensions.Caching.StackExchangeRedis 封装的 IDistributedCache,而非直连 StackExchange.Redis;需显式序列化、设过期时间、防穿透/击穿/雪崩,并用 redis-stack-server 本地开发。

ASP.NET Core 6+ 默认用 IDistributedCache 接 Redis,别自己封装 StackExchange.Redis 客户端
直接暴露 ConnectionMultiplexer 容易导致连接泄漏、序列化不一致、超时配置错乱。微软的 Microsoft.Extensions.Caching.StackExchangeRedis 包已封装好线程安全、连接复用和异常重试逻辑,且与 ILogger、IOptions 深度集成。
常见错误现象:Timeout performing GET 频发、缓存键大小写不一致导致命中失败、JSON序列化后类型丢失。
- 注册时必须用
AddStackExchangeRedisCache,而非手动AddSingleton - 连接字符串里不要硬编码
connectTimeout=5000—— 它会被ConfigurationOptions.ConnectTimeout覆盖,而后者默认是 5s,生产环境建议设为 10–15s - 避免在
Startup.ConfigureServices中调用GetDatabase()获取实例 —— 这会提前触发连接,且破坏 DI 生命周期管理
IDistributedCache.SetAsync 存的是字节数组,不是对象,别漏了序列化
它底层不做任何序列化,传入 new byte[] { 1, 2, 3 } 就存什么,取出来也一样。如果你直接传 JsonSerializer.SerializeToUtf8Bytes(obj),那读取时就得对应 JsonSerializer.Deserialize,否则就是 NullReferenceException 或 JSON 解析失败。
使用场景:存 DTO、配置片段、计算结果等短生命周期数据;不适合存大文件或未压缩的二进制流(Redis 单 key 建议 ≤ 1MB)。
- 推荐统一用
System.Text.Json,避免Newtonsoft.Json引入额外依赖和兼容性问题 - 设置过期时间必须显式传
new DistributedCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(10)),不传就永不过期 - 注意
SetAsync不会自动处理 null 值 —— 传 null 会存空字节数组,读出来也是非 null 的空数组,业务层要主动判空
Redis 缓存穿透、击穿、雪崩,在 C# 层能做的只有“缓存空值 + 逻辑过期”
Redis 本身不解决这三类问题,得靠代码逻辑兜底。比如查数据库返回 null,你不能跳过缓存直接返回,而应把 "" 或特殊标记(如 {"exists":false})连同短 TTL(如 2 分钟)一起写入缓存。
性能影响:空值缓存会略微增加内存占用,但比反复穿透 DB 强得多;逻辑过期需额外字段(如 expiredAt),读取时先判断是否过期再异步刷新,避免并发重建缓存。
- 穿透防护:对非法 ID(如负数、超长字符串)在进入缓存前就拦截,别让它走到
GetAsync - 击穿防护:热点 key 加互斥锁(
MemoryCache+SemaphoreSlim)比 Redis Lua 脚本更轻量,适合 .NET 环境 - 雪崩防护:不同 key 的过期时间加随机偏移(
TimeSpan.FromMinutes(10 + new Random().Next(0, 5))),别全设成整点失效
本地开发用 redis-stack-server,别连生产集群或 Docker Desktop 自带的老版 Redis
Docker Desktop 内置的 Redis 是 6.x 且无 Stack 模块,不支持 JSON.GET、FT.SEARCH 等现代功能;而 redis-stack-server 是官方维护的一体包,含 Redis + RedisJSON + RediSearch + RedisGraph,开箱即用,还自带 Web UI。
兼容性影响:用 StackExchange.Redis 调 JSON.SET 时,如果服务端没启 JSON 模块,会抛出 NotSupportedException: Unknown command 'JSON.SET'。
- 本地启动命令:
docker run -d -p 6379:6379 -p 8001:8001 --name redis-stack -d docker.io/redis/redis-stack:latest - 连接字符串写
localhost:6379,abortConnect=false,allowAdmin=true,allowAdmin=true是为了支持FLUSHDB等调试命令 - CI/CD 流水线里别用
redis:alpine镜像做集成测试 —— 缺模块、版本碎片化,容易上线后才发现命令不支持
缓存键设计、序列化策略、空值治理这些事,不写进代码里就不会自动发生。Redis 只是存储,真正的分布式逻辑还在你写的那几行 SetAsync 和 GetAsync 里。











