连不上或超时主因是地址错误、未启连接池、DNS失败;需显式配置Options、用Context控制超时、合理设PoolSize;缓存操作要防panic、穿透、击穿;handler中须透传ctx防goroutine堆积。

Go 用 redis.Client 连 Redis 时,为什么连不上或超时?
常见原因是没设对地址、没开连接池、或没处理 DNS 解析失败。默认 redis.NewClient 不会主动拨号验证,直到第一次 Get 或 Set 才报错。
- 用
redis.Options{Addr: "localhost:6379", Password: "", DB: 0}显式指定,别依赖环境变量或空字符串 fallback - 加
Context超时控制:比如ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second),再传给client.Ping(ctx)主动探测 - 连接池大小建议从
PoolSize: 10起调,高并发 Web 服务可设到 50–100,但注意 Redis 本身maxclients限制(默认 10000)
缓存用户数据时,Set 和 Get 怎么写才安全?
直接序列化结构体进 Redis 容易出问题:字段变动、类型不一致、JSON tag 错漏都会导致反序列失败,且没有类型保护。
- 用
json.Marshal+json.Unmarshal是最稳妥的通用方案,别用gob(跨语言/版本不兼容) -
Set必须带过期时间:client.Set(ctx, "user:123", dataBytes, 30*time.Minute),避免脏数据长期滞留 -
Get后先检查val.Err() == redis.Nil,再解码;别直接val.Val(),否则命中空值会 panic
val := client.Get(ctx, "user:123")
if val.Err() == redis.Nil {
// 缓存未命中,查 DB 并写入
} else if val.Err() != nil {
// 网络或 Redis 错误
} else {
json.Unmarshal(val.Val(), &user)
}
如何避免缓存穿透和击穿?
穿透(查不存在的 ID)和击穿(热点 key 过期瞬间大量请求打到 DB)在 Go Web 中必须主动防御,Redis 客户端本身不提供自动兜底。
Destoon B2B网站管理系统是一套完善的B2B(电子商务)行业门户解决方案。系统基于PHP+MySQL开发,采用B/S架构,模板与程序分离,源码开放。模型化的开发思路,可扩展或删除任何功能;创新的缓存技术与数据库设计,可负载千万级别数据容量及访问。 系统特性1、跨平台。支持Linux/Unix/Windows服务器,支持Apache/IIS/Zeus等2、跨浏览器。基于最新Web标准构建,在
- 穿透:对空结果也缓存,比如
client.Set(ctx, "user:999999", "null", 2*time.Minute),读到 "null" 字符串就跳过 DB 查询 - 击穿:用
SET key value EX 300 NX原子操作(即client.SetNX),只在 key 不存在时设值;配合双检锁(double-checked locking)逻辑 - 更稳的做法是用
redislock库或基于EVAL的 Lua 脚本实现分布式锁,但要注意锁释放失败会导致死锁
HTTP handler 里嵌 Redis 调用,性能瓶颈在哪?
不是 Redis 本身慢,而是 Go HTTP server 默认每请求一个 goroutine,若每个 handler 都同步阻塞等 Redis 返回,goroutine 会堆积,尤其当 Redis 响应延迟升高时。
立即学习“go语言免费学习笔记(深入)”;
- 别在 handler 里做重试逻辑(如反复
Get直到成功),这会卡住整个 goroutine - 用
WithTimeout和WithCancel控制单次 Redis 调用生命周期,超时立即返回错误,让上层决定降级(比如返回旧缓存或默认值) - 高频 key 可考虑本地缓存(如
freecache)+ Redis 二级缓存,但要注意本地缓存失效一致性——简单场景用短 TTL + 主动刷新即可
ctx 必须透传给所有 client.* 调用,否则请求被 Cancel 后,goroutine 仍可能卡在 Redis read 上。









