必须显式配置poolsize和minidleconns,否则高并发下易触发redis: connection pool timeout错误;poolsize按qps×平均rt估算并设20–50起步,minidleconns建议设5以避免冷启动频繁建连。

redis.NewClient() 必须显式配置 PoolSize 和 MinIdleConns
不设连接池参数,上线后第一波流量就可能触发 redis: connection pool timeout 错误,延迟陡增但日志里看不到 Redis 连接失败,只看到超时或 goroutine 堆积。
-
PoolSize别信默认值 10 —— 按 QPS × 平均 RT 粗估:比如接口 800 QPS、平均耗时 120ms,理论并发连接约 96,PoolSize至少设 30,建议 20–50 区间起步 -
MinIdleConns必须显式设(如 5),否则冷启动时每个请求都新建 TCP 连接,首屏慢 + 日志刷满redis: dial tcp - 别指望“自动扩容”——
go-redis/v8的连接池是静态的,超限就排队,不是拒绝或重建
所有 Redis 操作必须带 context.WithTimeout
用 context.Background() 或不设超时,等于把整个 HTTP 请求绑死在 Redis 上;一次网络抖动或 Redis 响应慢,就会卡住 goroutine,runtime.NumGoroutine() 持续上涨,错误日志只有模糊的 context deadline exceeded,根本看不出是缓存层拖垮的。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- Gin handler 中统一用
ctx, cancel := context.WithTimeout(r.Context(), 300*time.Millisecond),300ms 是缓存读场景合理上限 - 写操作(
Set、Incr、分布式锁)同样要超时,否则锁假死风险极高 - 包级变量里提前声明
ctx = context.Background()是典型反模式——它不可取消,也不携带请求生命周期
Key 类型与命令必须严格匹配,否则报 WRONGTYPE
本地调试只看 Go 层 val, err := rdb.Get(ctx, "user:1001").Result() 返回值,会掩盖真实问题。Redis 里 user:1001 实际可能是 hash 或 list,但代码用 Get() 就直接报 WRONGTYPE Operation against a key holding the wrong kind of value。
- 终端手动验证:
redis-cli -p 6379 TYPE user:1001确认类型,TTL user:1001查是否真有过期时间(TTL=0 或负数等价于立即删除) - 结构体存 JSON 时,确保字段有
json:"xxx"tag,且反序列化目标类型与存入时一致,否则Get()成功但json.Unmarshal()panic - 缓存穿透/击穿/雪崩无法靠 Redis 自身解决,Go 层必须兜底:空值缓存、布隆过滤器、互斥锁等逻辑得自己写
缓存预热不能放 init() 或 goroutine
预热失败最常见原因是执行时机错位:放在 init() 里,DB 和 Redis 客户端还没初始化,一查库就 panic;用 go preloadCache() 异步启动,主 goroutine 在 http.ListenAndServe() 后退出,预热中途被强制终止,Redis pipeline 只写了一半。
- 正确顺序只能是:
InitDB()→InitRedis()→preloadCache()→http.ListenAndServe() - MySQL 查热点数据必须分页、限字段、走游标(
WHERE id > ? ORDER BY id LIMIT 100),禁用OFFSET和SELECT * - Redis 写入必须用
pipe := redisClient.Pipeline(),每批 ≤100 条,pipe.Exec(ctx)一次性提交
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










