Fiber中直接new redis.Client会炸连接数,因为每个请求新建Client独占TCP连接,而Linux默认单进程文件描述符上限仅1024,几百并发即触发ConnectionRefusedError或timeout;根本原因是Go进程耗尽系统资源,而非Redis服务瓶颈,必须全局复用redis.ConnPool。

为什么Fiber里直接new redis.Client会炸连接数
因为Fiber是高并发模型,每个请求若都新建redis.Client,就会独占一个TCP连接;而Linux默认单进程文件描述符上限通常只有1024,几百并发就触发ConnectionRefusedError或timeout。这不是Redis服务扛不住,是你的Go进程把系统资源耗尽了。
- 必须全局复用
redis.ConnectionPool,初始化一次,所有handler共享 - 推荐配置:
MaxActive: 20(中小型项目够用)、IdleTimeout: 30 * time.Second、ReadTimeout: 1 * time.Second - 别把
redis.Client塞进ctx.Locals或fiber.Ctx——生命周期错配,goroutine可能访问已关闭连接 - 正确挂载方式:在
app.Use()中间件外初始化,存到app.Config().// 自定义字段或包级变量(确保init顺序)
如何让@cache.cached在Fiber里真正生效
Fiber没有原生@cache.cached装饰器——那是Flask的写法。你在Fiber里想缓存HTTP响应,得手动控制读写逻辑,且必须区分GET/POST语义。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 对GET接口:用
ctx.Params+ctx.Queries()拼出唯一cacheKey,先client.Get(ctx.Context(), cacheKey);命中则ctx.SendString()并return;未命中则执行业务逻辑,再client.Set(ctx.Context(), cacheKey, result, 5*time.Minute) - 对POST/PUT:禁止按URL缓存——body内容不同但URL相同,会导致结果污染。必须解析
ctx.BodyBytes()后哈希生成key,或改用主动刷新策略 - 注意空值陷阱:
client.Get()返回redis.Nil才表示键不存在;返回""或"null"可能是你之前存了空数据,需显式判断err == redis.Nil - 别用
client.Keys("*")查缓存——O(N)阻塞操作,压测时Redis直接卡死;调试用redis-cli --scan --pattern "myapp:prod:*"
缓存键设计不带环境前缀会出什么问题
本地开发连着localhost:6379/0,测试环境连redis-test:6379/0,生产连redis-prod:6379/1——如果所有环境都用f"user:{id}"作key,测试脚本一跑FLUSHDB,线上用户头像全变空白。
- 强制约定格式:
fmt.Sprintf("%s:%s:%s:%d", app.Name(), os.Getenv("ENV"), "user", id),例如"myfiber:staging:user:123" - 避免在key里存JSON或结构体——Redis key只支持字符串,序列化后不可读、无法用
scan排查 - 高频更新字段(如商品库存)优先用
client.Incr()/client.Decr()原生命令,绕过Go层反序列化开销 - 删除缓存时别只删key,要同步清理相关衍生key(如
"user:123:profile"和"user:123:posts"),否则出现数据陈旧
Fiber+Redis组合下最容易被忽略的一致性风险
用户修改头像后,你删了user:123:avatar,但10个并发请求同时发现缓存失效,全部打到后端查库、生成新图、写回Redis——这就是缓存雪崩+重复计算,数据库和图片服务瞬间被打穿。
- 主动刷新优于被动删除:更新DB后立刻
client.Set(..., newAvatarData, ttl),而不是等下次请求来重建 - 必须加分布式锁:用
client.SetNX(ctx.Context(), "lock:user:123", "1", 5*time.Second),成功才执行查库逻辑,失败则time.Sleep(50ms); goto retry - 空值也要缓存:查库返回空结果,写入
"__EMPTY__"并设较短TTL(如60秒),防止穿透攻击 - 别依赖
validate_timestamps=false这类PHP式思路——Redis没文件时间戳概念,它的“过期”靠内存标记+惰性删除+定期抽样,TTL必须设,且要留缓冲余量


















