Redis连接池需设合理PoolSize、IdleTimeout和MinIdleConns;session key应为UUID,用hash管理用户多会话;JSON序列化须显式加小写下划线tag;并发登录需用SETNX或HSet+扫描保障一致性。

Redis 连接池配置不当导致 Set 超时或连接耗尽
Go 的 redis.Client 本身不带连接池,必须用 redis.NewClient + &redis.Options{PoolSize: ...} 显式控制。默认 PoolSize 是 10,高并发下很容易卡住——尤其 Session 写入频繁时,SET 命令堆积,报错常是 read tcp: i/o timeout 或 connection refused。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
PoolSize至少设为预期 QPS 的 2–3 倍(比如 500 QPS,起始配 1000);但别盲目拉到 10000,OS 文件描述符和 Redismaxclients会先扛不住 - 务必设置
IdleTimeout(如5 * time.Minute)和MinIdleConns(如10),避免空闲连接长期占着不放 - 用
client.Ping(ctx).Err()在启动时验连,别等第一个Set才发现地址写错
Set 和 Get 的 key 设计影响 session 失效与并发安全
Session key 不能只拼 "session:" + userID。用户登出、密码变更、设备切换时,旧 session 必须立即失效,而 Redis 的 DEL 是 O(1),但遍历匹配前缀(如 KEYS session:user123*)是 O(N),线上禁用。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- key 格式用
"session:" + sessionID(由服务端生成 UUID),登录成功后把userID → []string{sessionID1, sessionID2}存另一条 hash,登出时查 hash 再批量DEL - 写 session 时用
client.Set(ctx, key, value, ttl),别漏ttl参数——Redis 默认永不过期,内存爆掉前你都收不到告警 - 读 session 用
client.Get(ctx, key)后立刻调result.Val(),别直接传result给下游;如果 key 不存在,result.Err()是redis.Nil,不是nil
Go 结构体序列化成 JSON 存 Redis,反序列化时字段名大小写不一致
Go 默认用 struct tag json:"xxx" 控制字段名,但新手常忘记加 tag,或写成 json:"UserID",结果存进去是 {"UserID": "u1"},而前端或下游服务期望的是 {"user_id": "u1"},一读就 json.Unmarshal 失败,result.Val() 返回空结构体也不报错。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有要存 Redis 的 struct,显式加
jsontag,小写下划线风格(如UserID int `json:"user_id"`),和常见 API 规范对齐 - 存之前先
json.Marshal一次,打印日志看输出是否符合预期;别依赖“应该没问题” - 反序列化用
json.Unmarshal([]byte(result.Val()), &s),别用result.Scan(&s)——后者是 redis-go 的二进制协议解析,不走 JSON
并发登录踢人逻辑没加锁,导致新旧 session 同时有效
用户 A 在设备 1 登录,又在设备 2 登录,按需求应使设备 1 的 session 失效。但如果两个请求几乎同时到达,都查到 “A 当前无活跃 session”,然后各自生成新 session 并写入,就变成双 session 共存。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用 Redis 的
SET key value EX seconds NX(即client.SetNX)做分布式锁:先尝试写一个临时锁 key(如"lock:login:userA"),成功才继续后续流程 - 锁的 TTL 必须明显短于业务超时(比如设 5 秒),防止死锁;且每次操作完必须
DEL锁 key,别靠过期自动清理 - 更稳妥的做法是:登录成功后,用
client.HSet(ctx, "user_sessions:userA", sessionID, time.Now().Unix())记录,再HGetAll扫描过期项批量清理——比锁更平滑,也避免单点锁瓶颈
最麻烦的从来不是怎么存进 Redis,而是怎么让不同实例、不同时间点写进去的 session,在登出、续期、踢人这些动作里行为一致。哪怕用了原子命令,也要盯住时钟漂移、网络分区、客户端重试这些现实问题。










