go-redis/v9初始化必须显式配置addr(如"localhost:6379"),否则panic;所有操作须传带超时的context,禁用context.background();结构体存前需json.marshal;穿透防护需go层空值占位,雪崩防护需随机ttl。

go-redis/v9 初始化必须传 *redis.Options 且 Addr 不可为空
不填 Addr 会 panic,不是静默失败。GoLand 里跑单元测试或 main 启动时,如果只写了 redis.NewClient(&redis.Options{}) 就运行,立刻 crash 报 panic: redis: address is required。
常见错误写法:
client := redis.NewClient(&redis.Options{}) // ❌ Addr 缺失
正确写法(开发期建议用环境变量):
-
Addr必须显式指定,如"localhost:6379"或os.Getenv("REDIS_ADDR") -
Password留空字符串"",别传nil,否则连接时可能报invalid password -
DB显式设为0,避免依赖 Redis 默认库号(不同环境可能不同)
GoLand 调试时别用 context.Background(),改用 context.WithTimeout
GoLand 的 Debug 模式下,context.Background() 看似能跑通,但一压测就暴露问题:goroutine 卡死、连接池耗尽、日志里全是 context deadline exceeded 却找不到源头。
调试阶段就得养成习惯:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- HTTP handler 中统一用
ctx, cancel := context.WithTimeout(r.Context(), 300*time.Millisecond),结束后defer cancel() - 单元测试里别手写
context.Background(),改用context.WithTimeout(context.Background(), 2*time.Second) - GoLand 的 Run Configuration 里不要勾选 “Allow running in background” —— 它会让 goroutine 在断点后继续跑,掩盖超时未 cancel 的泄漏
结构体存 Redis 前必须 json.Marshal,GoLand 里容易漏掉字段 tag
直接 client.Set(ctx, key, myStruct, ttl) 看似没报错,但 Redis 里存的是空字符串或乱码,因为 Go struct 默认不可序列化。
两个典型坑点:
- 字段没加
json:tag,比如Name string→Name string `json:"name"`,否则json.Marshal输出空对象{} - 嵌套 struct 里含
time.Time或指针字段,json.Marshal可能 panic,得提前转成字符串或用MarshalJSON方法 - GoLand 的代码补全不会提醒你加 tag,得靠静态检查工具(如
go vet -tags=json)或手动验证:终端执行redis-cli GET your:key看原始值
缓存穿透防护不能只靠 Redis TTL,Go 层必须写空值占位
GoLand 本地调试时,常误以为 “Redis 返回 nil 就代表 DB 该查了”,结果上线后流量突增,DB 直接被打垮 —— 因为 Redis 自身不解决穿透,它只忠实地返回 redis.Nil。
真实防护逻辑要写死在 Go 代码里:
- 查
client.Get(ctx, key)返回redis.Nil时,立刻client.Set(ctx, key, "null", 1*time.Minute) - 业务解包时判断
if val == "null" { return nil, nil },而不是把"null"当真实数据返回 - GoLand 的断点调试要覆盖这个分支:手动用
redis-cli DEL your:key清空 key,再触发请求,确认是否走了占位逻辑
随机 TTL 和空值占位这些逻辑,不写进 Go 代码里,光靠配置或中间件,上线第一天就会出事。










