golang Ristretto v2使用

Ristretto v2 是目前 Go 生态中最先进的高性能、并发安全、支持泛型和智能淘汰策略的内存缓存库,由 Dgraph Labs 开发。它在 v2 版本中引入了 原生泛型支持,大幅提升了类型安全性和开发体验。

✅ 一、安装

go get github.com/dgraph-io/ristretto/v2

要求:Go 1.18+(因使用泛型)

二、快速入门(带完整示例)

场景:缓存用户信息(key: string, value: User struct)

package main

import (
    "fmt"
    "time"

    "github.com/dgraph-io/ristretto/v2"
)

type User struct {
    ID   int
    Name string
    Age  int
}

func main() {
    // 1. 创建缓存:最多缓存 1000 个用户(每个 cost=1)
    cache, err := ristretto.NewCache[string, User](&ristretto.Config[string, User]{
       MaxCost:     1000,   // 最多 1000 个条目
       NumCounters: 10_000, // 预估唯一 key 数 × 10
       BufferItems: 64,     // 写缓冲区大小
       Metrics:     true,   // 启用命中率统计
    })
    if err != nil {
       panic(err)
    }
    defer cache.Close()

    // 2. 写入缓存(cost=1 表明占 1 个“槽位”)
    user1 := User{ID: 1, Name: "Alice", Age: 30}
    cache.Set("user:1", user1, 1)

    // 3. 带 TTL 写入(5 分钟后过期)
    user2 := User{ID: 2, Name: "Bob", Age: 25}
    cache.SetWithTTL("user:2", user2, 1, 5*time.Minute)

    // wait for value to pass through buffers
    cache.Wait()
    // 4. 读取(类型安全!无需断言)
    if val, ok := cache.Get("user:1"); ok {
       fmt.Printf("Found: %+v
", val) // 直接是 User 类型
    }

    // 5. 读取不存在的 key
    if _, ok := cache.Get("user:999"); !ok {
       fmt.Println("User not found")
    }

    // 6. 删除
    cache.Del("user:1")

    // 7. 查看缓存指标
    metrics := cache.Metrics
    fmt.Printf("命中率: %.2f%%
", metrics.Ratio()*100)
}

输出示例:

Found: {ID:1 Name:Alice Age:30}
User not found
命中率: 50.00%

⚙️ 三、核心配置详解(ristretto.Config)

字段

类型

说明

推荐值

MaxCost

int64

缓存总“成本”上限

按条目数:设为最大条目数;按字节:设为字节数

NumCounters

int64

键计数器数量(用于 LFU)

≈ 预期唯一 key 数 × 10

BufferItems

int64

每个写缓冲区大小

默认 64,高并发写可增至 128/256

Metrics

bool

是否收集命中率等指标

开发/监控时开启

OnEvict

func(K, V, int64)

淘汰回调(可选)

用于日志、埋点

示例:限制内存为 50MB(按 JSON 序列化大小计算 cost)

import "encoding/json"
func getUserCost(u User) int64 {
data, _ := json.Marshal(u)
return int64(len(data))
}
cache, _ := ristretto.NewCache[string, User](&ristretto.Config[string, User]{
MaxCost: 50 << 20, // 50MB
NumCounters: 1_000_000,
})
user := User{...}
cache.Set("u1", user, getUserCost(user))

四、常用 API(泛型版)

方法

签名

说明

Set

Set(key K, value V, cost int64) bool

写入缓存

SetWithTTL

SetWithTTL(key K, value V, cost int64, ttl time.Duration) bool

带过期时间写入

Get

Get(key K) (value V, ok bool)

读取(类型安全)

Del

Del(key K)

删除

Wait

Wait()

等待所有 pending 写入完成

Metrics

Metrics() *ristretto.Metrics

获取统计信息

Close

Close()

关闭缓存(flush + 停止后台任务)

✅ 所有方法都是 并发安全 的。

五、淘汰策略与 TTL

  • 淘汰算法:基于 TinyLFU 的采样 LFU,能高效识别热点数据。
  • TTL 行为
  • 过期 key 不会立即删除。
  • 当调用 Get(key) 时,若已过期,返回 (zeroValue, false) 并标记为可淘汰。
  • 后台 goroutine 会定期清理过期和低频数据。

TTL 是“软过期”,适合大多数场景。如需准确过期,提议结合外部定时器。

六、监控与指标

m := cache.Metrics()
fmt.Println("Hits:", m.Hits())
fmt.Println("Misses:", m.Misses())
fmt.Println("Hit Ratio:", m.Ratio()) // 0.0 ~ 1.0
fmt.Println("Current Cost:", m.CostAdded() - m.CostEvicted())

可用于 Prometheus 监控或日志告警。

⚠️ 七、注意事项

  • Key 必须是 comparable 类型✅ 支持:string, int, int64, struct{}(不含 slice/map)❌ 不支持:[]byte, map, slice, func
  • Value 是值拷贝修改外部变量不会影响缓存中的值。
  • Cost 设计决定内存行为

若按“条目数”限制 → cost = 1

若按“内存大小”限制 → cost = len(serialize(value))

  • TTL 不保证实时性适合“最终一致性”场景,不适合金融级准确过期。

八、适用场景推荐

场景

是否推荐

API 响应缓存

✅ 强烈推荐

数据库查询结果缓存

会话(Session)存储

✅(配合 TTL)

高频计数器

⚠️ 可用,但思考 bigcache

或 sync.Map

超大对象缓存(>10MB)

❌ 不适合(提议用磁盘或 Redis)

✅ 总结

  • Ristretto v2 = 泛型 + 高性能 + 智能 LFU + TTL + 内存可控
  • 使用简单,类型安全,适合现代 Go 项目。
  • 配置关键:合理设置 MaxCost 和 NumCounters。
  • 新项目缓存首选,尤其适合需要高命中率的场景。

小贴士:如果只是缓存少量配置,用 sync.Map 更轻量;如果是热点数据、高频访问,选 Ristretto v2

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
明明是包租婆呀呀的头像 - 鹿快
评论 共1条

请登录后发表评论

    暂无评论内容