Redis缓存设计必须规范key命名、正确处理nil错误、严格设置TTL、复用连接池并防范缓存穿透与雪崩;错误示例包括裸拼URL作key、整数传TTL、未判redis.Nil、重复创建client等,否则500QPS即抖动或打穿DB。

直接用 redis.Client.Set() 往 Redis 写接口返回值,不加封装、不控 key、不处理空值,线上扛不住 500 QPS 就开始抖动或打穿 DB。
缓存 key 必须带业务前缀 + 参数哈希,不能拼接原始 URL
常见错误是把 req.RequestURI 或未转义的 req.URL.Query().Encode() 当 key —— 空格、编码差异、Header 差异(比如 Accept: application/json vs application/xml)会让同一个逻辑请求生成多个 key,缓存命中率暴跌。
- 正确做法:固定前缀 + 显式语义标识 + 参数哈希,例如
api:user:get_by_id:7a2b3c,其中7a2b3c是sha256(userID)[:6]截取 - userID 必须是原始值(
int64或string),别传指针或 struct,避免序列化歧义 - 禁止用
fmt.Sprintf("user:%s", username),用户名含特殊字符会污染 key 空间;需先url.PathEscape()或用strconv.FormatInt() - 所有 key 建议统一加
v1:版本前缀,升级缓存结构时可批量清理:redis-cli --scan --pattern "v1:api:*" | xargs redis-cli del
Get 之后必须显式判断 redis.Nil,不能只看 error 是否为 nil
client.Get(ctx, key).Result() 返回 (string, error),但 error 可能是 redis.Nil(key 不存在)、context.DeadlineExceeded(超时)、或真实网络错误。混为一谈会导致缓存穿透或静默失败。
- 正确分支写法:
if errors.Is(err, redis.Nil) { /* 缓存未命中,查 DB */ } - 如果是
err != nil && !errors.Is(err, redis.Nil),说明 Redis 不可用,应跳过写缓存,直连 DB 并只写本地 cache(如有) - 别在 handler 里裸调
Get(),抽一层cache.Get(ctx, key, &dst),内部统一做errors.Is(err, redis.Nil)分流
Set() 的 TTL 参数必须是 time.Duration,传整数等于纳秒级过期
client.Set(ctx, key, value, 60) 这种写法会让缓存 60 纳秒后就失效 —— 因为 Go 把 60 当作 time.Duration 的底层类型(纳秒),不是秒。
立即学习“go语言免费学习笔记(深入)”;
- ✅ 正确写法:
client.Set(ctx, key, value, 60*time.Second) - ❌ 错误写法:
client.Set(ctx, key, value, 60)(立刻过期)、client.Set(ctx, key, value, "60s")(编译报错) - TTL 建议设为随机偏移:比如基础 5 分钟,再
+ time.Duration(rand.Int63n(60)) * time.Second,防雪崩 - 空结果(DB 查无此 ID)也要缓存,但 TTL 缩短到 30~60 秒,用
cache.Set(ctx, key, nilUser, 60*time.Second)防击穿
别在 HTTP handler 里初始化 redis.Client,连接池必须复用
每次请求都 redis.NewClient(),不出三天就会报 too many open files —— 连接池没复用,每个 client 开一堆 TCP 连接,fd 耗尽。
- 全局单例初始化,用
sync.Once或依赖注入框架管理生命周期 - 初始化后务必调
client.Ping(ctx).Err(),否则第一次读写才暴露连通性问题 - 进程退出前(如
main()结尾或http.Server.Shutdown()后)调client.Close() - 不要用
redigo手写Do(),go-redis/v9的Get().Result()和错误分类更稳,调试时也更容易定位是 key 不存在还是连接断了
最易被忽略的是两级缓存的 TTL 对齐:本地 cache(如 github.com/patrickmn/go-cache)的过期时间必须 ≤ Redis 的 TTL,否则 Redis 已更新、本地还在返回旧值,业务就感知到“延迟一致”。


















