golang支持泛型的带过期时间内存缓存插件库ttlcache的使用

golang支持泛型的带过期时间内存缓存插件库ttlcache的使用

TTLCache - 带项目过期和泛型的内存缓存

TTLCache是一个支持泛型的带过期时间的内存缓存库,具有以下特性:

  • 简单API
  • 类型参数
  • 项目过期和自动删除
  • 每次Get调用自动延长过期时间
  • Loader接口可用于加载/懒初始化缺失的缓存项
  • 线程安全
  • 事件处理器(插入、更新和驱逐)
  • 指标

安装

go get github.com/jellydator/ttlcache/v3

使用

基本用法

func main() {
    // 创建缓存实例,指定键类型为string,值类型为string
    cache := ttlcache.New[string, string]()
    
    // 插入数据
    cache.Set("key1", "value1", ttlcache.DefaultTTL) // 使用默认TTL
    cache.Set("key2", "value2", ttlcache.NoTTL)      // 永不过期
    cache.Set("key3", "value3", 10 * time.Minute)    // 自定义TTL
    
    // 获取数据
    if item := cache.Get("key1"); item != nil {
        fmt.Println(item.Value(), item.ExpiresAt())
    }
    
    // 检查键是否存在
    exists := cache.Has("key2")
    
    // 删除数据
    cache.Delete("key3")
    cache.DeleteExpired() // 删除所有过期项
    cache.DeleteAll()     // 删除所有项
}

自动过期删除

func main() {
    // 创建带TTL的缓存
    cache := ttlcache.New[string, string](
        ttlcache.WithTTL[string, string](30 * time.Minute),
    )

    // 启动自动过期项删除
    go cache.Start() 
    
    // 或者手动控制过期项删除
    for {
        time.Sleep(1 * time.Hour)
        cache.DeleteExpired()
    }
}

事件监听

func main() {
    cache := ttlcache.New[string, string](
        ttlcache.WithTTL[string, string](30 * time.Minute),
        ttlcache.WithCapacity[string, string](300), // 设置容量
    )

    // 插入事件
    cache.OnInsertion(func(ctx context.Context, item *ttlcache.Item[string, string]) {
        fmt.Println("插入:", item.Key(), item.Value())
    })
    
    // 更新事件
    cache.OnUpdate(func(ctx context.Context, item *ttlcache.Item[string, string]) {
        fmt.Println("更新:", item.Key(), item.Value())
    })
    
    // 驱逐事件
    cache.OnEviction(func(ctx context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, string]) {
        fmt.Printf("驱逐: %s (原因: %v)\n", item.Key(), reason)
    })
    
    cache.Set("event", "test", ttlcache.DefaultTTL)
    cache.DeleteAll()
}

自定义加载器

func main() {
    // 创建自定义加载器
    loader := ttlcache.LoaderFunc[string, string](
        func(c *ttlcache.Cache[string, string], key string) *ttlcache.Item[string, string] {
            // 模拟从数据库或其他来源加载数据
            value := "loaded-value-for-" + key
            return c.Set(key, value, ttlcache.DefaultTTL)
        },
    )
    
    // 创建带加载器的缓存
    cache := ttlcache.New[string, string](
        ttlcache.WithLoader[string, string](loader),
    )
    
    // 获取不存在的键会自动调用加载器
    item := cache.Get("some-key")
    fmt.Println(item.Value()) // 输出: loaded-value-for-some-key
}

限制缓存大小

func main() {
    // 创建带最大内存限制的缓存
    cache := ttlcache.New[string, string](
        ttlcache.WithMaxCost[string, string](5120, func(item ttlcache.CostItem[string, string]) uint64 {
            // 计算每个项的"成本"(这里简单使用键值长度之和)
            return uint64(len(item.Key()) + len(item.Value()))
        }),
    )
    
    // 添加数据
    cache.Set("large", strings.Repeat("a", 1024), ttlcache.DefaultTTL)
}

完整示例

package main

import (
	"context"
	"fmt"
	"time"
	
	"github.com/jellydator/ttlcache/v3"
)

func main() {
	// 创建缓存实例
	cache := ttlcache.New[string, string](
		ttlcache.WithTTL[string, string](30 * time.Minute),
		ttlcache.WithCapacity[string, string](100),
	)
	
	// 设置事件处理器
	cache.OnInsertion(func(ctx context.Context, item *ttlcache.Item[string, string]) {
		fmt.Printf("插入项: %s=%s (过期时间: %v)\n", 
			item.Key(), item.Value(), item.ExpiresAt())
	})
	
	cache.OnEviction(func(ctx context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, string]) {
		fmt.Printf("驱逐项: %s (原因: %v)\n", item.Key(), reason)
	})
	
	// 启动自动清理
	go cache.Start()
	defer cache.Stop()
	
	// 添加数据
	cache.Set("name", "张三", ttlcache.DefaultTTL)
	cache.Set("age", "30", 10 * time.Second) // 10秒后过期
	
	// 获取数据
	if item := cache.Get("name"); item != nil {
		fmt.Println("获取到name:", item.Value())
	}
	
	// 等待过期
	time.Sleep(11 * time.Second)
	if item := cache.Get("age"); item == nil {
		fmt.Println("age已过期")
	}
	
	// 使用加载器
	loader := ttlcache.LoaderFunc[string, string](
		func(c *ttlcache.Cache[string, string], key string) *ttlcache.Item[string, string] {
			return c.Set(key, "default-value", ttlcache.DefaultTTL)
		},
	)
	
	cache = ttlcache.New[string, string](
		ttlcache.WithLoader[string, string](loader),
	)
	
	fmt.Println("自动加载的值:", cache.Get("auto-loaded").Value())
}

这个库非常适合需要内存缓存且支持过期时间的场景,如API响应缓存、会话存储等。通过泛型支持,可以确保类型安全,同时提供了丰富的配置选项和事件机制。


更多关于golang支持泛型的带过期时间内存缓存插件库ttlcache的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang支持泛型的带过期时间内存缓存插件库ttlcache的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 中使用 ttlcache 实现带过期时间的缓存

ttlcache 是一个流行的 Go 语言内存缓存库,支持基于时间的自动过期功能。下面我将详细介绍如何使用它。

安装 ttlcache

首先安装 ttlcache 库:

go get github.com/jellydator/ttlcache/v3

基本使用示例

package main

import (
	"fmt"
	"time"
	
	"github.com/jellydator/ttlcache/v3"
)

func main() {
	// 创建一个带过期时间的缓存
	cache := ttlcache.New[string, string](
		ttlcache.WithTTL[string, string](5 * time.Minute), // 默认5分钟过期
	)
	
	// 设置缓存项,带自定义过期时间
	cache.Set("key1", "value1", ttlcache.DefaultTTL)
	cache.Set("key2", "value2", 10*time.Minute) // 单独设置10分钟过期
	
	// 获取缓存值
	if item := cache.Get("key1"); item != nil {
		fmt.Println("key1:", item.Value())
	}
	
	// 删除缓存项
	cache.Delete("key2")
	
	// 检查是否存在
	if !cache.Has("key2") {
		fmt.Println("key2 已不存在")
	}
}

高级功能

1. 设置全局默认过期时间

cache := ttlcache.New[string, int](
	ttlcache.WithTTL[string, int](30 * time.Minute),
)

2. 自动删除过期项

cache := ttlcache.New[string, interface{}](
	ttlcache.WithTTL[string, interface{}](1 * time.Hour),
	ttlcache.WithDisableTouchOnHit[string, interface{}](), // 访问时不重置过期时间
)

// 启动自动清理协程
go cache.Start() 
defer cache.Stop()

3. 设置缓存大小限制

cache := ttlcache.New[string, float64](
	ttlcache.WithTTL[string, float64](15 * time.Minute),
	ttlcache.WithCapacity[string, float64](1000), // 最多1000个条目
)

4. 事件监听

loader := ttlcache.LoaderFunc[string, string](
	func(c *ttlcache.Cache[string, string], key string) *ttlcache.Item[string, string] {
		// 当缓存未命中时自动加载
		value := "auto-loaded-value-for-" + key
		item := c.Set(key, value, ttlcache.DefaultTTL)
		return item
	},
)

cache := ttlcache.New[string, string](
	ttlcache.WithLoader[string, string](loader),
	ttlcache.WithTTL[string, string](10 * time.Minute),
)

// 设置事件回调
cache.OnInsertion(func(ctx context.Context, i *ttlcache.Item[string, string]) {
	fmt.Println("插入:", i.Key(), i.Value())
})
cache.OnEviction(func(ctx context.Context, r ttlcache.EvictionReason, i *ttlcache.Item[string, string]) {
	fmt.Println("淘汰:", i.Key(), "原因:", r)
})

5. 复杂类型缓存示例

type User struct {
	ID    int
	Name  string
	Email string
}

func main() {
	userCache := ttlcache.New[int, *User](
		ttlcache.WithTTL[int, *User](1 * time.Hour),
	)
	
	// 存储用户对象
	userCache.Set(1, &User{ID: 1, Name: "张三", Email: "zhangsan@example.com"}, ttlcache.DefaultTTL)
	
	// 获取用户对象
	if item := userCache.Get(1); item != nil {
		user := item.Value()
		fmt.Printf("用户ID: %d, 姓名: %s\n", user.ID, user.Name)
	}
}

注意事项

  1. ttlcache 是线程安全的,可以在多个 goroutine 中并发使用
  2. 对于大量缓存项,建议设置合理的 Capacity 限制
  3. 过期时间是粗略的,不保证精确到毫秒级
  4. 考虑使用 Start()Stop() 来管理后台清理协程的生命周期
  5. 对于生产环境,建议添加监控来跟踪缓存命中率和内存使用情况

ttlcache 提供了简单而强大的内存缓存功能,特别适合需要自动过期特性的场景。根据你的具体需求,可以选择合适的配置选项来优化缓存行为。

回到顶部