Redis客户端初始化必须设PoolSize为20–50、MinIdleConns≥5,初始化后立即Ping验证,并所有操作带context超时;key需统一前缀与序列化方式,穿透/击穿/雪崩须在Go层兜底。

redis.NewClient() 初始化必须配 PoolSize 和 Ping 验证
不设连接池参数、不验连通性,线上一压就报 redis: connection pool timeout 或 goroutine 卡死——这不是 Redis 慢,是 Go 层没兜住。
-
PoolSize设为 20–50:QPS 超 300 就别用默认值(10);设太高(如 >100)可能打满 Redis 的maxclients -
MinIdleConns必须 ≥5:防 SLB/NAT 断连后首请求重连失败 - 初始化后立刻用带超时的
ctx调rdb.Ping(ctx).Err(),别等第一个Get才暴露地址错或密码错 - 地址、密码、DB 从环境变量读,别硬编码
"localhost:6379"
所有 Redis 操作必须带 context.WithTimeout
在 HTTP handler 里传 context.Background() 给 client.Get(),等于把请求生命周期交给 Redis 响应时间——它卡 2 秒,你的 handler 就卡 2 秒,监控看到的是 goroutine 数暴涨、QPS 断崖下跌。
- HTTP handler 中统一用:
ctx, cancel := context.WithTimeout(r.Context(), 300*time.Millisecond) - 写操作(
Set、Del、分布式锁)同样要超时;锁逻辑缺超时,会导致后续请求永久等待 - 别在
init()里声明全局ctx = context.Background()——它没有取消信号,不是“默认”,是“永生”
缓存 key 必须加服务前缀,结构体序列化方式需全局统一
多个服务共用一个 Redis 实例但没前缀,或同一结构体在不同模块混用 json.Marshal 和 gob.Encode,结果就是读出来 invalid character 或直接 panic,日志里搜不到源头。
- key 推荐格式:
"user:profile:123"、"order:summary:20260424:uid_789",前缀明确业务域 - 结构体必须字段导出 +
json:"field"tag,存取都走json.Marshal/json.Unmarshal - 拼 key 时避免裸接用户输入,先做
strings.ReplaceAll(username, ":", "_")
穿透/击穿/雪崩得在 Go 层兜底,Redis 自身不解决
靠 Redis 自带命令或配置扛不住这三类问题,必须在业务代码里加轻量策略。
- 穿透:查 DB 为空时,存
rdb.Set(ctx, key, "null", 60*time.Second);解包前判if val == "null" { return nil, nil } - 击穿:热点 key 过期瞬间大量请求打穿 DB,需加本地锁(如
singleflight.Group)或提前刷新过期时间 - 雪崩:避免大量 key 同一时间过期,设置过期时间时加随机偏移(如
time.Now().Add(30*time.Minute + time.Duration(rand.Intn(600))*time.Second))
实际部署时最容易被忽略的是:**缓存键生成逻辑分散在多个 service 文件里,没人维护前缀规则,也没人检查序列化方式是否一致**。一旦出现数据污染或反序列化失败,排查成本远高于初期加几行约束。











