应直接使用github.com/redis/go-redis/v9或github.com/bradfitz/gomemcache/memcache,避免自行封装底层连接逻辑;Redis初始化必须传redis.Options并填全Addr等必填项,否则panic,且需显式设置ContextTimeout、ReadTimeout及PoolSize(默认10,高并发建议20–50),全局复用单个redis.Client实例;Memcached需手动处理[]byte序列化、ErrCacheMiss判断及多节点一致性哈希。

直接用 github.com/redis/go-redis/v9 或 github.com/bradfitz/gomemcache/memcache,别自己封装底层连接逻辑——90% 的缓存需求靠这两个库加几行配置就能跑起来,自己造轮子反而容易漏掉 context 超时、连接池复用、错误分类等关键点。
Redis 集成必须传 *redis.Options 且填全必填字段
不填 Addr 会 panic;只填 Addr 但没设 ContextTimeout,网络卡住时 goroutine 就永远挂起。实际初始化要像这样:
opt := &redis.Options{
Addr: "localhost:6379",
ContextTimeout: 5 * time.Second,
ReadTimeout: 3 * time.Second,
PoolSize: 20,
}
client := redis.NewClient(opt)
-
PoolSize默认是 10,QPS 过千时建议调到 20–50,具体看平均响应时间和并发量 - 全局复用一个
*redis.Client实例,别每次请求都 new - 所有操作必须带
context.Context,比如client.Get(ctx, key).Result(),否则超时控制失效
Memcached 需手动处理 []byte 和 ErrCacheMiss
它不支持自动序列化,也不把“key 不存在”当正常流程返回 nil error,而是返回明确的 memcache.ErrCacheMiss。写法上容易出错:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
item, err := client.Get("user:123")
if err == memcache.ErrCacheMiss {
// 缓存未命中,走回源逻辑
} else if err != nil {
// 真正的错误,比如网络失败
}
- 存结构体前必须
json.Marshal,取回后json.Unmarshal,没有中间层帮你做 - 批量 Get 要自己开 goroutine 并发调用,客户端不提供 pipeline
- 多个节点需自行封装一致性哈希或分片逻辑,
gomemcache只负责发请求
缓存中间件里最常被忽略的状态码捕获问题
HTTP 缓存中间件若只监听 Write 方法,WriteHeader(500) 就会被跳过,结果把错误响应当成 200 缓存下来。正确做法是实现自定义 ResponseWriter:
立即学习“go语言免费学习笔记(深入)”;
type cacheResponseWriter struct {
http.ResponseWriter
statusCode int
body []byte
mu sync.Mutex
}
<p>func (w *cacheResponseWriter) WriteHeader(statusCode int) {
w.statusCode = statusCode
w.ResponseWriter.WriteHeader(statusCode)
}</p><p>func (w *cacheResponseWriter) Write(b []byte) (int, error) {
w.mu.Lock()
w.body = append(w.body, b...)
w.mu.Unlock()
return w.ResponseWriter.Write(b)
}
- 必须同时重写
WriteHeader和Write,缺一不可 - 只缓存
statusCode == 200且Content-Type == "application/json"的响应 - key 必须含
r.Method + ":" + r.URL.EscapedPath() + "?" + r.URL.RawQuery + "|" + r.Header.Get("Accept"),否则 Accept 不同的请求会互相污染
真正难的不是连上 Redis 或 Memcached,而是缓存策略和 HTTP 协议细节的咬合——比如状态码捕获时机、key 构建维度、过期检查是否在 Load 时做,这些地方错一点,缓存就变成“稳定误返器”。

















