必须异步初始化ConnectionMultiplexer并延迟加载,禁用abortOnConnectFail以避免启动失败;StringGet返回RedisValue需用IsNull判断存在性,批量操作须用MGET或Pipeline减少RTT。

别用 ConnectionMultiplexer.Connect() 同步初始化,也别每次操作都 new 一个连接——这会让 ASP.NET Core 启动卡死、线程池饥饿,Redis 临时不可达时整个服务 hang 住。
ConnectionMultiplexer 必须异步初始化 + 延迟加载 + 显式超时
默认 Connect() 在 DNS 解析失败、端口不通或防火墙拦截时会阻塞 5 秒(实际是 connectTimeout=5000),而 Web 应用启动阶段根本等不起。必须改用 ConnectAsync(),并显式设超时参数。
- 连接字符串里硬编码
connectTimeout=2000和syncTimeout=1000,禁用默认无限等待 -
abortOnConnectFail=false是保命开关:首次连不上不抛异常,后台自动重试;设为true(默认)会导致应用直接启动失败 - 用
Lazy<ConnectionMultiplexer>实现延迟加载,避免程序一启动就强行连 Redis - Docker 或云环境务必把
localhost换成真实 IP 或服务名,并确认宿主机能 ping 通、6379 端口已放行
IDatabase.StringGet 返回值不是 string,是 RedisValue 结构体
StringGet("key") 返回的是 RedisValue,它隐式转 string 时,对不存在的 key 会返回空字符串,而不是 null——你会误判“缓存命中”,实际是 key 根本没设过。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 正确判断是否存在:用
if (!value.IsNull),别用value == null或string.IsNullOrEmpty(value) - 想存真正的
null字符串?StringSet("k", null)会静默失败(返回false),必须传RedisValue.Null才能触发 DEL 行为 - 反序列化前先检查
value.HasValue,否则JsonConvert.DeserializeObject<T>(value)遇到空值直接炸
批量读写必须用 MGET / Pipeline,别手写 for 循环
连续调用 10 次 StringGet("k1")、StringGet("k2")…是 10 次网络往返(RTT),哪怕 Redis 就在本地。真正省时间的方式只有两种:
- 同类型批量:用
StringGet(new RedisKey[] { "k1", "k2", "k3" })→ 底层走 Redis 的MGET命令,1 次 RTT 拿回全部 - 跨类型或带逻辑:用
db.ScriptEvaluate(luaScript, keys, values),把“查 A → 若存在则删 B → 再设 C”这种原子操作压进 Lua,否则 CAS 场景下必现竞态 -
GetDatabase()开销极小,但反复调用不如提前提取到局部变量里复用
StackExchange.Redis 不内置读写分离,主从必须手动拆分连接
配置字符串里写多个地址(如 "192.168.1.10:6379,192.168.1.11:6380")不会自动分流读写,只是高可用兜底,所有写操作仍全走第一个可连上的节点。
- 真要读写分离,得维护两个独立的
ConnectionMultiplexer实例:一个连主(写),一个(或多个)连从(读) - 从节点连接必须设
abortConnect=false,否则某台从宕机时整个应用启动失败 -
IDatabase.GetDatabase(dbIndex)的dbIndex参数只影响 Redis 内部数据库编号(0~15),和物理节点完全无关 - 有多台从节点时,别手写轮询逻辑——用数组存实例,读操作时随机取一个,避免单点压力
最常被忽略的其实是 RedisValue 的语义:它不是引用类型,不能用 == null 判断;它也不是字符串,隐式转换会掩盖 key 不存在这个关键事实。这点一旦写错,缓存穿透、空值污染、序列化崩溃全跟着来。

















