GCache 学习笔记

GCache 学习笔记封面

GCache 简介

GCache(github.com/bluele/gcache)是 Go 的高性能内存缓存库:支持 LRU / LFU / ARC 三种淘汰策略、线程安全、内置 LoaderFunc 自动填充、过期时间与容量限制、API 简洁。相比 go-cache 多了淘汰策略,相比 BigCache 多了淘汰与自动加载,适合中小规模、需要精细控制的缓存场景。

基本使用

go get -u github.com/bluele/gcache
// 容量 100 的 LRU 缓存
cache := gcache.New(100).LRU().Build()

// 带 10 分钟过期
cache := gcache.New(100).LRU().Expiration(10 * time.Minute).Build()

// 基本操作
cache.Set("key1", "value1")
value, err := cache.Get("key1")
cache.Remove("key1")
cache.Purge()

三种淘汰策略

容量满时谁出局,由策略决定。选型就一句话:访问模式稳定看 LRU,长期热点看 LFU,模式频繁变化看 ARC。

LRU LFU ARC 三种淘汰策略对比
图 1:三种淘汰策略——LRU 踢最久未访问,LFU 踢访问最少,ARC 在两个区间间自适应
  • LRU:淘汰最近最少使用——通用场景首选;
  • LFU:淘汰使用频率最低——适合长期热点数据;
  • ARC:自适应替换,结合 LRU 与 LFU——适合访问模式频繁变化的场景。

高级功能

自动填充(LoaderFunc)

cache := gcache.New(100).
    LRU().
    LoaderFunc(func(key interface{}) (interface{}, error) {
        // 未命中时自动加载
        return loadFromDB(key), nil
    }).
    Build()
value, err := cache.Get("key1")   // 未命中会自动调用 LoaderFunc
GCache 读缓存流程 LoaderFunc 自动填充
图 2:读缓存流程——未命中时 LoaderFunc 加载并回填,LoaderFunc 返回 error 时不会回填

LoaderFunc 返回的 error 要妥善处理:DB 挂了是否穿透、查不到是否缓存空值,这些决策直接影响命中率和 DB 压力。

过期时间

// 全局过期
gcache.New(100).LRU().Expiration(10 * time.Minute).Build()
// 单键过期
cache.SetWithExpire("key1", "value1", 5 * time.Minute)

事件监听

gcache.New(100).
    LRU().
    AddedFunc(func(k, v interface{}) { fmt.Printf("added %v=%vn", k, v) }).
    EvictedFunc(func(k, v interface{}) { fmt.Printf("evicted %v=%vn", k, v) }).
    Build()

实战:数据库查询缓存

type UserCache struct {
    cache gcache.Cache
    db    *gorm.DB
}

func NewUserCache(db *gorm.DB) *UserCache {
    return &UserCache{
        cache: gcache.New(500).
            ARC().
            Expiration(30 * time.Minute).
            LoaderFunc(func(key interface{}) (interface{}, error) {
                var u User
                if err := db.First(&u, key).Error; err != nil {
                    return nil, err
                }
                return &u, nil
            }).
            Build(),
        db: db,
    }
}

func (uc *UserCache) GetUser(id uint) (*User, error) {
    v, err := uc.cache.Get(id)
    if err != nil { return nil, err }
    return v.(*User), nil
}
GCache 数据库查询缓存结构
图 3:数据库查询缓存——未命中才查库,结果回填,DB 只处理真正缺失的请求

注意事项

  • 内存监控:容量只是条目数,大对象缓存可能 OOM,注意观测内存;
  • 缓存穿透:查不到 DB 的 key 也要缓存(空值 + 短过期),否则恶意 key 会打穿到 DB;
  • 缓存雪崩:全局统一过期时间会让缓存同时失效,给过期时间加随机抖动;
  • 对象共享:缓存存的是指针时,外部修改对象会污染缓存——需要时存深拷贝;
  • 命中率监控:上线后记录命中率,判断容量与策略是否合适。

与其他库对比

特性GCachego-cacheBigCache
淘汰策略LRU/LFU/ARC无(纯过期)无
自动加载✅❌❌
事件监听✅❌❌
高并发性能良好良好极佳(无锁分片)
内存效率良好良好极佳

选型建议:需要淘汰策略和自动加载用 GCache;简单过期缓存用 go-cache;超高并发、大数据量用 BigCache。

滚动至顶部