如何使用Golang实现本地缓存系统_Golang缓存模块快速搭建

推荐用 sync.Map 或封装 LRU(如 hashicorp/golang-lru)实现轻量可控本地缓存;sync.Map 适合读多写少无淘汰场景,LRU 支持容量限制与淘汰,可扩展 TTL 和监控。

用 Go 实现本地缓存系统,核心是轻量、可控、无依赖——推荐直接使用 sync.Map 或封装 LRU 缓存(如 github.com/hashicorp/golang-lru),避免过早引入 Redis 等外部组件。关键不在“快”,而在“够用+线程安全+可淘汰”。

用 sync.Map 做简单键值缓存

适合读多写少、无需淘汰策略、生命周期与程序一致的场景(比如配置项、静态映射表)。

  • 天然并发安全,不用额外加锁
  • 不支持容量限制和自动淘汰,需自行控制 size(例如用原子计数器 + 定期清理)
  • 示例:缓存解析后的 JSON 配置
var cache = sync.Map{}
cache.Store("config:v1", configObj)
if val, ok := cache.Load("config:v1"); ok { /* 使用 val */ }

用 lru.Cache 实现带淘汰的内存缓存

更贴近真实业务需求:固定容量、最近最少使用淘汰、支持带 TTL 的封装(需自己扩展)。

  • go get github.com/hashicorp/golang-lru
  • 初始化时指定容量(如 1000 条),超出自动驱逐旧条目
  • 注意:原生 lru.Cache 不带过期时间,如需 TTL,可组合 time.Now() + 自定义结构体存储过期时间,Get 时判断
lru, _ := lru.New(1000)
lru.Add("user:1001", &User{ID: 1001, Name: "Alice"})
if val, ok := lru.Get("user:1001"); ok { /* 类型断言后使用 */ }

封装一个带 TTL 的本地缓存模块

把过期逻辑收拢,对外提供类似 Redis 的 Set/Get 接口,提升复用性。

  • 内部用 lru.Cache 存 key→value,另起 goroutine 定期扫描清理过期项(或惰性清理:Get 时检查)
  • 结构体字段建议包含:value interface{}、expireAt time.Time
  • Set(key, val, ttl time.Duration) 方法中计算 expireAt = time.Now().Add(ttl)
  • Get(key) 返回 (val, found, expired),由调用方决定是否刷新

注意事项和避坑点

  • 不要在缓存里存指针指向的可变对象(如 *[]byte),修改原数据会导致缓存内容意外变化
  • 大对象(>1MB)缓存要考虑 GC 压力,可考虑 mmap 或分块处理
  • sync.Map 在高写场景下性能可能不如 RWMutex + map,压测验证再选型
  • 上线前务必加 metrics(命中率、size、平均耗时),用 expvar 或 Prometheus client 暴露指标

基本上就这些。本地缓存不复杂但容易忽略淘汰和并发细节,从 sync.Map 或 lru 开始,按需叠加 TTL 和监控,就能快速跑起来一个稳定可用的模块。