必须在应用启动时初始化全局*redis.Client并显式健康检查,禁止在handler中新建或关闭;PoolSize设20、Password置""、用errors.Is(err, redis.Nil)判未命中;优先SetEX、手动处理序列化与TTL。

启动时初始化全局 *redis.Client,别在 handler 里 new
Redis 客户端必须在应用启动阶段一次性创建,挂为全局变量或结构体字段——Fiber 不帮你管理连接生命周期,也不会自动复用 client。每次请求都 redis.NewClient() 会导致连接爆炸、TIME_WAIT 堆积、认证失败。
-
PoolSize显式设为20(默认 10 在高并发下易阻塞) -
Password字段不能为nil:没密码也得写"",否则 Redis 认证直接拒绝 - 必须立刻执行
client.Ping(ctx).Err(),err != nil就log.Fatal—— 健康检查不是可选项 - 别在
app.Use()或中间件里初始化 client:那是处理请求的逻辑,不是资源准备时机
handler 中用闭包捕获 client,别塞进 c.Locals
把 *redis.Client 传进 handler 的最安全方式是闭包捕获(比如 func(client *redis.Client) fiber.Handler),而不是存到 c.Locals。后者会让 client 跟随每个请求上下文存活,GC 压力陡增,且容易误触发 defer client.Close()。
- 读缓存:用
client.Get(c.Context(), key).Result(),判断未命中必须用errors.Is(err, redis.Nil),不是err == nil - 写缓存:优先用
client.SetEX(c.Context(), key, value, ttl),比Set+Expire少一次网络往返 -
value必须可序列化:存 struct 要字段首字母大写 +json:tag;取出来是 string,得自己json.Unmarshal([]byte(s), &v) - 绝对不要在 handler 里写
defer client.Close():client 是全局复用的,关了整个服务就断连
差异化 TTL 只能靠业务分支,没有 @Cacheable 注解
Go 没有运行时反射注解能力,Fiber 更不解析函数签名。所谓“按方法自动设 TTL”是伪需求,硬封装只会让缓存逻辑不可控、难调试。
- 推荐查表模式:
ttlMap := map[string]time.Duration{"user": 2*time.Hour, "config": 10*time.Minute} - 或前缀匹配:
if strings.HasPrefix(key, "user:") { ttl = 2*time.Hour } - 别写通用 cache 中间件去“自动识别 key 语义”——它迟早会漏判、误判,还掩盖真实业务意图
别碰第三方 “Fiber-Redis” 包,github.com/go-redis/redis/v9 是唯一选择
官方不提供、也不维护任何 Redis 扩展包。“fiber-redis”“fiber-cache” 这类第三方库多数已归档、API 不兼容 v9、或强行往 fiber.Ctx 塞 client 导致内存泄漏。你真正需要的只有两样东西:
- 一个干净的
go get github.com/go-redis/redis/v9 - 一个你自己 hold 住的
*redis.Client实例,显式调Get/SetEX等方法
复杂点在于 TTL 和序列化策略要跟业务强耦合,而不是寄希望于某个 magic 中间件自动搞定——那部分永远得你亲手写清楚。











