正确初始化 redis.Client 必须全局复用单例、显式配置 PoolSize(10–50)、MinIdleConns(5)、MaxConnAge(30min)、地址从配置中心读取、所有操作带 context.WithTimeout,并在进程退出前调用 rdb.Close()。

直接用 redis.NewClient 初始化并开始 Set/Get,90% 的线上缓存故障就埋在这一步里——连接池没调、context 没设超时、键没加前缀、结构体序列化不一致,全在初始化阶段漏掉。
如何正确初始化 redis.Client 并复用
全局复用一个 *redis.Client 实例是底线,每次请求都 redis.NewClient 等于主动制造连接风暴。但只复用还不够,必须显式配置关键参数:
-
PoolSize必须设(建议 10–50),默认值是 10,高并发下极易阻塞;设太小会排队,太大可能打满 Redis 的maxclients - 务必调
rdb.Ping(ctx).Err()验证连通性,否则第一次Get失败才暴露问题,排查成本翻倍 - 所有连接都应设
MinIdleConns: 5和MaxConnAge: 30 * time.Minute,防止中间网络设备静默断连 - 别硬编码
"localhost:6379",从环境变量或配置中心读取地址,微服务部署下这是必选项
为什么 context.WithTimeout 是强制项,不是可选项
用 context.Background() 或不带超时的 context.TODO() 调 client.Get 或 client.Set,一旦 Redis 响应慢或网络抖动,goroutine 就卡死,日志里看不到 Redis 错误,只看到 redis: connection pool timeout 或 goroutine 数持续上涨。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- HTTP handler 中统一用
ctx, cancel := context.WithTimeout(r.Context(), 300*time.Millisecond),优先继承 request 生命周期 - 写操作(如
Set、Del)同样要超时,尤其涉及分布式锁逻辑时,超时缺失会导致锁假死 - 不要在 init 函数里提前声明全局
ctx = context.Background(),它不是“默认上下文”,而是“无约束上下文”
缓存穿透/击穿/雪崩:Go 层必须自己兜底
Redis 自身不解决这三类问题,必须在 Go 业务代码里加判断和策略。靠加锁、布隆过滤器容易过度设计,多数场景用轻量级手段更稳:
- 穿透:查不到时存
client.Set(ctx, key, "null", 60*time.Second),后续读到"null"直接跳过 DB;注意业务层解包时判if val == "null" { return nil, nil } - 击穿:热点 key 过期瞬间大量请求打穿 DB,用
singleflight.Group包一层Do,同一 key 的并发请求只放行一个去查 DB - 雪崩:避免所有 key 同一时刻过期,TTL 加随机扰动:
baseTTL + time.Duration(rand.Int63n(int64(2*time.Minute)));别用全局rand.Seed(),每次生成前用time.Now().UnixNano()做 seed
结构体存 Redis 的坑:json.Marshal 不是万能的
把 struct 直接传给 client.Set,Redis 存进去的是空字符串或 &{},因为客户端不认 Go 类型,必须先序列化。但 json.Marshal 有隐性陷阱:
- 字段必须首字母大写(可导出),且显式加
json:"field_name"tag,否则json.Unmarshal静默失败,字段保持零值 - 别存
time.Time,JSON 默认转 RFC3339 字符串,gob 存纳秒整数,跨服务或升级后解析不一致;统一转成int64时间戳再存 - 多语言或对外 API 场景禁用
gob,它只限 Go 内部;纯 Go 微服务可用,但需提前gob.Register,否则字段增删导致反序列化失败 - 存之前先
json.Marshal一次检查错误,比上线后查redis-cli GET key更早发现问题
最易被忽略的一点:进程退出前必须调 rdb.Close()。连接池不会自动释放底层 TCP 连接,长时间运行的服务(比如常驻 HTTP server)会慢慢耗尽文件描述符,最终报 too many open files 或 dial tcp: lookup xxx: no such host。这不是 Redis 的问题,是 Go 客户端生命周期管理没到位。

















