必须用 github.com/bradfitz/gomemcache,它是当前 Go 生态唯一能在线上扛住高并发、避免连接泄漏和哈希漂移的 Memcached 客户端;其 sync.Pool 管理 TCP 连接、可调 MaxIdleConns、显式 Timeout 配置及一致性哈希支持,确保高并发下稳定可靠。

直接用 github.com/bradfitz/gomemcache,别换。它不是“可选项”,而是当前 Go 生态里唯一能在线上扛住高并发、不出连接泄漏或哈希漂移的 Memcached 客户端。
为什么必须用 bradfitz/gomemcache 而不是其他?
线上踩过坑:换过三个 fork 库,都触发过 memcache: server error: timeout 或 connection refused。根因是连接池复用逻辑有缺陷——有的库每次 Get 都新建连接,有的压根没实现 idle 连接回收。
-
bradfitz/gomemcache的memcache.Client是无状态的,内部用sync.Pool管理 TCP 连接,MaxIdleConns可调,连接复用真实有效 - 最新提交在 2026 年 4 月,Go 1.21+ 兼容性已验证;而多数替代库最后一次更新是 2023 年前,不支持
golang.org/x/exp/maps的一致性哈希依赖 - API 极简:
Set/Get/Delete直接操作*memcache.Item,没抽象层干扰,性能透明
初始化时必须显式配置 Timeout 和 MaxIdleConns
默认 Timeout = 0,意味着无限等待;默认 MaxIdleConns = 1,QPS 超过 50 就开始排队阻塞。这两项不设,高并发下缓存层反而成瓶颈。
- 创建 client 后立刻赋值:
mc.Timeout = 100 * time.Millisecond(别信“默认 1s”,源码里就是 0) - 根据单实例 Memcached 连接上限(默认 1024)和预估 QPS 设置:
mc.MaxIdleConns = 10或20,别超过 50 - 不要依赖
net.DialTimeout全局设置——gomemcache不读这个,只认自己的Timeout
集群必须用 NewSelector + 一致性哈希,否则扩容即雪崩
memcache.New("host:11211") 用的是取模哈希:hash(key) % len(servers)。加一个节点,99% 的 key 重分布,缓存命中率瞬间归零。
立即学习“go语言免费学习笔记(深入)”;
- 改用
selector := memcache.NewSelector(),再selector.AddServers("a:11211", "b:11211", "c:11211") - 节点地址必须完全一致:
"10.0.1.10:11211"和"node-a:11211"是两个节点,DNS 解析结果不同也会导致哈希错位 - 不要混用
New和NewSelector初始化的 client 实例——它们哈希算法不互通,同一个 key 可能路由到不同机器
结构体缓存必须封装 SetJSON/GetJSON,且字段要导出+带 tag
Memcached 只存 []byte,json.Marshal 私有字段(小写首字母)会丢数据,GetJSON 传值而非指针会导致静默失败。
- 结构体字段必须首字母大写(可导出),并显式声明 tag:
UserName string `json:"user_name"` -
GetJSON必须传指针:err := mc.GetJSON("user:123", &u),传u不报错但u值为空 - 避免缓存
nil结构体:if u != nil { mc.SetJSON(..., u, ttl) },否则json.Marshal(nil)写入null字节数组,读出来Unmarshal失败却不报错
真正卡住人的从来不是怎么连上 Memcached,而是 key 命名要不要加 service 前缀、TTL 是设 300 秒还是加 30 秒随机偏移、空值要不要缓存——这些决策没有标准答案,得靠监控 hit rate 和 DB 慢查日志反推。


















