gcache 与 Redis 缓存的选型与配合

结论:gcache 是进程内缓存(默认内存 Adapter、单例 g.Cache()),快但各实例不共享;Redis 是分布式共享缓存;常见做法是“gcache 一级 + Redis 二级 + DB 兜底”的旁路缓存,并可配合 ORM 查询缓存使用。

一、选型对比

维度gcacheRedis
存储位置进程内存独立服务
访问速度最快快(有网络开销)
共享性单实例内多实例共享
一致性实例间不一致全局一致
适用单机热点、进程内状态分布式共享、锁、计数等
容量/持久化进程重启即失可配持久化、容量大

二、配合套路(旁路缓存)

  1. 读:先查 gcache(L1)→ 未命中查 Redis(L2)→ 未命中查 DB 并回填两级。
  2. 写:先更新 DB,再删/失效缓存(推荐“删缓存”降低并发不一致窗口)。
  3. TTL 加随机抖动防雪崩;热点键注意穿透问题。

代码示例

func GetUser(ctx context.Context, id int64) (*User, error) {
    key := fmt.Sprintf("user:%d", id)

    // L1 进程内
    if v := g.Cache().MustGet(ctx, key); !v.IsNil() {
        var u User
        _ = v.Struct(&u)
        return &u, nil
    }
    // L2 分布式缓存(示意,可走 g.Redis().Do GET/SET)
    // L3 DB
    var u User
    if err := dao.User.Ctx(ctx).WherePri(id).Scan(&u); err != nil {
        return nil, err
    }
    _ = g.Cache().Set(ctx, key, u, 5*time.Minute)
    return &u, nil
}

// ORM 查询缓存(默认基于 gcache,可配置 Redis Adapter)
var users []User
err := dao.User.Ctx(ctx).Cache(time.Minute, "user:list").Scan(&users)

常见追问 / 记忆点

  • 追问:多级缓存一致性如何保证?→ 一般只追求最终一致:短 TTL + 更新后删缓存 + 必要时失效广播(以官方文档/中间件方案为准)。
  • 追问:缓存更新与删除选哪个?→ 写多场景优先删缓存,避免并发写旧值覆盖。
  • 记忆点:一级内存二级 Redis 三级 DB;“先更库、后删缓存、TTL 加抖动”。
笔记加载中…