应选用 gomemcache 客户端,即 github.com/bradfitz/gomemcache/memcache,因其是事实标准,支持连接池、超时控制、SASL 认证及主流云服务兼容,而旧版 memcache 已废弃且不维护。

Memcached 客户端选哪个:gomemcache 还是 memcache?
直接用 github.com/bradfitz/gomemcache/memcache,别碰 memcache(那个是旧版、无维护、不支持 SASL 认证)。gomemcache 是事实标准,支持连接池、超时控制、故障自动剔除,且与主流 Memcached 服务(包括 AWS ElastiCache、阿里云 Memcache 版)完全兼容。
常见错误:用错 import 路径导致编译失败,或误装 go get github.com/dustin/go-memcached(这是服务端库,不是客户端)。
- 安装命令必须是:
go get github.com/bradfitz/gomemcache/memcache - 初始化时建议显式设置
Timeout和MaxIdleConns,否则默认无超时、无连接复用,高并发下容易耗尽 socket - 如果 Memcached 启用了 SASL(如阿里云默认开启),需调用
mc.Auth方法传入用户名密码,否则会返回memcache: connect error: authentication required
缓存 key 设计要避开空格和控制字符
Memcached 协议对 key 有严格限制:不能含空格、换行、回车、制表符、\0,长度不超过 250 字节。Golang 里如果直接用结构体字段拼接(比如 "user:" + strconv.Itoa(id) + ":profile"),一旦 id 是负数或含非法字符,写入会静默失败或返回 memcache: bad key 错误。
- 推荐统一用
fmt.Sprintf("user:%d:profile", id),避免字符串拼接引入不可见字符 - 对用户输入的字段(如用户名、邮箱)做简单清洗:
strings.Map(func(r rune) rune { if unicode.IsLetter(r) || unicode.IsDigit(r) { return r } else { return -1 } }, input) - key 建议加业务前缀(如
svc-user:),方便运维时按前缀批量清理
Set 和 Get 的典型用法与超时陷阱
Memcached 的 Set 第三个参数是「相对过期时间(秒)」,不是 Unix 时间戳。写成 time.Now().Add(5 * time.Minute).Unix() 是错的,会导致缓存立刻失效或永久不过期(取决于数值大小)。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- 正确写法:
&memcache.Item{Key: "user:123", Value: data, Expiration: 300}(5 分钟) -
Expiration: 0表示永不过期(但受服务端内存淘汰策略影响) -
Get返回*memcache.Item或nil,**不会报错**;判断缓存未命中应检查返回值是否为nil,而非捕获 error - 反序列化时记得用
json.Unmarshal(item.Value, &dst),别漏掉&地址符
如何优雅降级:缓存失败时不阻塞主链路
Memcached 不可用时,mc.Get 或 mc.Set 会返回 error(如 read tcp: i/o timeout),但你不该让整个请求失败——微服务必须保障最终一致性,而不是强一致性。
- 对读操作:捕获 error 后直接查 DB,然后异步尝试写缓存(失败也不再重试)
- 对写操作(如更新用户资料):先更新 DB,再异步
mc.Delete("user:123")清缓存,避免 Set 失败导致脏数据残留 - 建议加一个全局开关(如配置项
cache.enabled),上线灰度或压测时可一键关闭缓存层
最易被忽略的是连接池泄漏:每次新建 memcache.New 实例却不复用,短生命周期服务(如 Lambda)会快速打满 FD。务必把 client 当全局变量初始化一次,复用到底。

















