cache

package
v0.0.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2026 License: MIT Imports: 3 Imported by: 0

README

cache

简介

cache 包提供了一个统一的缓存接口和多种缓存实现,适用于需要高性能内存缓存的 Go 应用程序。默认使用 Ristretto 作为底层实现,提供高效、可靠的缓存功能。

主要特性
  • 支持多种缓存后端(默认使用 ristretto)
  • 提供统一的缓存接口
  • 支持泛型和类型安全
  • 支持 TTL(生存时间)设置
  • 支持全局缓存实例
  • 线程安全
  • 高并发性能
设计理念

cache 包的设计遵循以下原则:

  1. 简单性:提供简洁易用的 API,使缓存操作尽可能直观
  2. 灵活性:支持多种缓存用例,从简单到复杂
  3. 类型安全:通过泛型支持类型安全的缓存操作,减少运行时错误
  4. 可扩展性:通过统一接口支持不同的缓存后端
  5. 性能优先:所有实现都注重性能和效率

包内部使用了适配器模式将不同的缓存后端实现适配到统一的 Cache 接口,同时提供了函数选项模式进行灵活配置。此外,利用泛型特性提供了类型安全的缓存操作,可以避免手动类型断言的麻烦。

安装

前置条件
  • Go 版本要求:Go 1.18+ (支持泛型)
  • 依赖要求:
    • github.com/dgraph-io/ristretto v0.2.0
安装命令
go get -u github.com/fsyyft-go/kit/cache

快速开始

基础用法
// 创建缓存实例
cache, err := cache.NewCache()  // 使用默认配置
if err != nil {
    panic(err)
}
defer cache.Close()

// 基本操作
cache.Set("key", "value")                    // 设置永不过期的值
cache.SetWithTTL("temp", "value", time.Hour) // 设置 1 小时后过期的值

// 获取值
if val, exists := cache.Get("key"); exists {
    fmt.Println(val)
}

// 获取带 TTL 的值
if val, exists, ttl := cache.GetWithTTL("temp"); exists {
    fmt.Printf("值:%v,剩余时间:%v\n", val, ttl)
}
配置选项
// 使用自定义配置
cache, err := cache.NewCache(
    cache.WithNumCounters(1e7),  // 跟踪 1000 万个条目
    cache.WithMaxCost(1<<30),    // 最大内存使用 1GB
    cache.WithBufferItems(64),   // 默认缓冲区大小
)
if err != nil {
    panic(err)
}
defer cache.Close()

详细指南

核心概念
  1. 缓存接口Cache 接口定义了所有缓存实现必须提供的基本操作
  2. 过期时间:通过 TTL (Time-To-Live) 控制缓存项的生存时间
  3. 驱逐策略:当缓存达到容量限制时,最不经常使用的项目将被自动移除
  4. 类型安全TypedCache[T] 提供类型安全的缓存操作,避免类型断言
  5. 全局缓存:通过全局函数可以方便地访问共享的缓存实例
常见用例
1. 使用全局缓存
// 初始化全局缓存
if err := cache.InitCache(); err != nil {
    panic(err)
}
defer cache.Close()

// 使用全局缓存函数
cache.Set("key", "value")
if val, exists := cache.Get("key"); exists {
    fmt.Println(val)
}

// 清理全局缓存
cache.Clear()
2. 类型安全的缓存操作
// 定义结构体
type User struct {
    ID   int
    Name string
    Age  int
}

// 创建缓存实例
baseCache, _ := cache.NewCache()
userCache := cache.AsTypedCache[User](baseCache)

// 存储用户对象
user := User{ID: 1, Name: "张三", Age: 30}
userCache.Set("user:1", user)

// 获取用户对象(无需类型断言)
if user, exists := userCache.Get("user:1"); exists {
    fmt.Printf("找到用户: %s, 年龄: %d\n", user.Name, user.Age)
}
最佳实践
  • 合理设置配置参数

    • NumCounters 建议设置为预期条目数的 10 倍
    • MaxCost 根据实际内存限制设置
    • BufferItems 默认值 64 适合大多数场景
  • 使用类型安全的接口

    • 优先使用 TypedCache 避免类型断言
    • 为不同类型的数据创建专门的缓存实例
  • 性能优化

    • 合理设置缓存大小避免频繁驱逐
    • 注意及时清理不需要的缓存项
    • 使用 Close 释放资源
  • 错误处理

    • 总是检查 InitCache 的返回错误
    • 使用 defer Close() 确保资源释放
    • 检查 Get 操作的 exists 返回值

API 文档

主要类型
// Cache 定义了统一的缓存接口
type Cache interface {
    Get(key interface{}) (value interface{}, exists bool)
    GetWithTTL(key interface{}) (value interface{}, exists bool, remainingTTL time.Duration)
    Set(key interface{}, value interface{}) bool
    SetWithTTL(key interface{}, value interface{}, ttl time.Duration) bool
    Delete(key interface{})
    Clear()
    Close() error
}

// TypedCache 是一个泛型包装器,提供类型安全的缓存操作
type TypedCache[T any] struct {
    // 内部字段
}

// CacheOptions 定义了缓存的配置选项
type CacheOptions struct {
    NumCounters int64
    MaxCost     int64
    BufferItems int64
}
关键函数
NewCache

创建一个新的缓存实例,默认使用 Ristretto 实现。

func NewCache(options ...Option) (Cache, error)

示例:

cache, err := cache.NewCache(
    cache.WithNumCounters(1e7),
    cache.WithMaxCost(1<<30),
)
InitCache

初始化全局缓存实例,确保只被初始化一次。

func InitCache(options ...Option) error

示例:

if err := cache.InitCache(); err != nil {
    panic(err)
}
AsTypedCache

将缓存转换为类型安全的包装器。

func AsTypedCache[T any](cache Cache) *TypedCache[T]

示例:

strCache := cache.AsTypedCache[string](baseCache)
错误处理

cache 包的大多数操作都会返回一个 bool 值表示操作是否成功,但创建和初始化函数会返回详细的错误信息。建议始终检查这些错误:

cache, err := cache.NewCache()
if err != nil {
    // 处理错误:日志记录、返回错误或中止
    log.Fatalf("创建缓存失败: %v", err)
}

对于获取操作,应始终检查 exists 返回值:

if value, exists := cache.Get(key); exists {
    // 使用 value
} else {
    // 处理键不存在的情况
}

性能指标

基于最近的基准测试结果:

操作 性能指标 说明
Set ~1930 ns/op, 442 B/op, 6 allocs/op 设置缓存项的基本性能
Get ~46.43 ns/op, 17 B/op, 1 allocs/op 获取缓存项的基本性能,非常快
SetWithTTL ~2414 ns/op, 674 B/op, 6 allocs/op 设置带TTL的性能,稍慢于基本Set
GetWithTTL ~278.1 ns/op, 22 B/op, 1 allocs/op 获取带TTL的性能,慢于基本Get
TypedCache Set ~1947 ns/op, 615 B/op, 7 allocs/op 类型安全的Set操作
TypedCache Get ~62.22 ns/op, 18 B/op, 1 allocs/op 类型安全的Get操作
Global Cache Set ~78.10 ns/op, 40 B/op, 2 allocs/op 全局缓存Set性能
Global Cache Get ~14.66 ns/op, 16 B/op, 1 allocs/op 全局缓存Get性能,非常快

测试覆盖率

覆盖率
github.com/fsyyft-go/kit/cache 71.1%

调试指南

日志级别

cache 包本身不输出日志,建议在应用程序中集成适当的日志记录:

  • 记录缓存初始化和配置
  • 记录缓存相关的重要操作
  • 监控缓存命中率和性能指标
常见问题排查
内存使用过高

确保设置了合理的 MaxCost 值,这会限制缓存使用的最大内存。

项目过早被驱逐

如果缓存项被过早驱逐,考虑增加 NumCounters 和 MaxCost 值。NumCounters 应该是预期独特项数的约 10 倍。

性能问题

如果遇到性能瓶颈,请确保:

  • 缓存配置适合您的使用场景
  • 避免在热路径上频繁调用 SetWithTTL
  • 考虑使用批量操作而不是多次单个操作

相关文档

贡献指南

我们欢迎任何形式的贡献,包括但不限于:

  • 报告问题
  • 提交功能建议
  • 提交代码改进
  • 完善文档

请参考我们的贡献指南了解详细信息。

许可证

本项目采用 MIT License 许可证。查看 LICENSE 文件了解更多信息。

Documentation

Overview

Package cache 提供统一的内存缓存接口、Ristretto 默认实现、类型安全包装器和包级默认缓存函数。

本包的 Cache 常规 Get、GetWithTTL、Set、SetWithTTL 和 Delete 操作遵循具体实现的并发能力; 内置 Ristretto 后端支持这些常规读写操作并发调用。Clear 非原子,调用方应避免将其与读写操作并发执行; Close 后不得继续使用缓存,且不应与其它操作并发调用。NewCache 创建独立缓存实例,未显式传入配置时使用包内默认 Ristretto 参数;调用方在实例不再使用时应调用 Close 释放底层资源。SetWithTTL 的非正 ttl 表示永不过期, GetWithTTL 使用 -1 表示永不过期,使用 0 表示键不存在或已过期。

AsTypedCache 在现有 Cache 上提供泛型类型断言包装,类型不匹配时按未命中处理。InitCache、Get、Set 等 包级函数操作进程内默认缓存;默认缓存由 sync.Once 控制只初始化一次,首次调用使用的 Option 会固定为后续 全局访问配置,首次初始化失败后也不会自动重试。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Clear

func Clear()

Clear 清空包级默认缓存中的所有缓存项。

默认缓存未初始化时该操作无效果。默认缓存已初始化时,该操作委托底层 Cache;Clear 非原子,调用方应避免 将其与读写操作并发调用,除非底层实现明确提供更强保证。

参数:无。

func Close

func Close() error

Close 关闭包级默认缓存并释放相关资源。

默认缓存未初始化时 Close 直接返回 nil。Close 不会重置 sync.Once 或清空 defaultCache 引用,且不应与其它 默认缓存操作并发调用;关闭后的包级默认缓存不应继续用于读写操作。

参数:无。

返回:

  • error: 默认缓存已初始化且底层 Close 失败时返回错误;默认缓存未初始化时返回 nil。

func Delete

func Delete(key interface{})

Delete 从包级默认缓存中删除 key 对应的缓存项。

参数:

  • key: 待删除的缓存键,具体可接受类型由默认缓存实现决定;默认缓存未初始化或 key 不存在时该操作无效果。

func Get

func Get(key interface{}) (interface{}, bool)

Get 从包级默认缓存中获取 key 对应的值。

参数:

  • key: 待查询的缓存键,具体可接受类型由默认缓存实现决定。

返回:

  • value: 默认缓存已初始化且 key 命中、未过期时返回缓存值;未初始化、未命中或已过期时返回 nil。
  • exists: 默认缓存已初始化且 key 存在、未过期时为 true。

func GetWithTTL

func GetWithTTL(key interface{}) (interface{}, bool, time.Duration)

GetWithTTL 从包级默认缓存中获取 key 对应的值及剩余过期时间。

参数:

  • key: 待查询的缓存键,具体可接受类型由默认缓存实现决定。

返回:

  • value: 默认缓存已初始化且 key 命中、未过期时返回缓存值;未初始化、未命中或已过期时返回 nil。
  • exists: 默认缓存已初始化且 key 存在、未过期时为 true。
  • remainingTTL: 剩余过期时间,0 表示默认缓存未初始化、key 不存在或已过期,-1 表示永不过期,正值表示实际剩余时间。

func InitCache

func InitCache(options ...Option) error

InitCache 初始化包级默认缓存实例。

InitCache 通过 sync.Once 只尝试初始化一次默认缓存。首次初始化失败时,只有当前调用会返回该错误; 后续调用不会重试,且当前实现也不会再次返回首次错误。无论首次是否成功,后续调用都不会替换默认实例, 也不会重新应用新的 Option。

参数:

  • options: 用于首次初始化默认缓存的可选配置项;后续调用即使传入新选项也不会重新应用。

返回:

  • error: 仅在首次初始化调用中返回 NewCache 失败产生的错误。

func Set

func Set(key interface{}, value interface{}) bool

Set 向包级默认缓存写入永不过期的值。

参数:

  • key: 待写入的缓存键,具体可接受类型由默认缓存实现决定。
  • value: 待缓存的值,可以为任意默认缓存实现支持的类型。

返回:

  • bool: 默认缓存已初始化且底层实现接受或排队该写入请求时返回 true;默认缓存未初始化时返回 false。 true 是否保证最终保留由底层实现决定。

func SetWithTTL

func SetWithTTL(key interface{}, value interface{}, ttl time.Duration) bool

SetWithTTL 向包级默认缓存写入带过期时间的值。

参数:

  • key: 待写入的缓存键,具体可接受类型由默认缓存实现决定。
  • value: 待缓存的值,可以为任意默认缓存实现支持的类型。
  • ttl: 缓存有效期;ttl 小于等于 0 时表示永不过期。

返回:

  • bool: 默认缓存已初始化且底层实现接受或排队该写入请求时返回 true;默认缓存未初始化时返回 false。 true 是否保证最终保留由底层实现决定。

Types

type Cache

type Cache interface {
	// Get 获取 key 对应的缓存值。
	//
	// 参数:
	//   - key: 待查询的缓存键,具体可接受类型由实现决定。
	//
	// 返回:
	//   - value: 命中且未过期时返回缓存值;未命中或已过期时返回 nil。
	//   - exists: key 存在且未过期时为 true。
	Get(key interface{}) (value interface{}, exists bool)

	// GetWithTTL 获取 key 对应的缓存值及剩余过期时间。
	//
	// 参数:
	//   - key: 待查询的缓存键,具体可接受类型由实现决定。
	//
	// 返回:
	//   - value: 命中且未过期时返回缓存值;未命中或已过期时返回 nil。
	//   - exists: key 存在且未过期时为 true。
	//   - remainingTTL: 剩余过期时间,0 表示 key 不存在或已过期,-1 表示永不过期,正值表示实际剩余时间。
	GetWithTTL(key interface{}) (value interface{}, exists bool, remainingTTL time.Duration)

	// Set 写入永不过期的缓存值。
	//
	// 参数:
	//   - key: 待写入的缓存键,具体可接受类型由实现决定。
	//   - value: 待缓存的值,可以为任意实现支持的类型。
	//
	// 返回:
	//   - bool: 底层实现接受或排队该写入请求时返回 true;是否最终保留由具体实现决定。
	Set(key interface{}, value interface{}) bool

	// SetWithTTL 写入带过期时间的缓存值。
	//
	// 参数:
	//   - key: 待写入的缓存键,具体可接受类型由实现决定。
	//   - value: 待缓存的值,可以为任意实现支持的类型。
	//   - ttl: 缓存有效期;ttl 小于等于 0 时表示永不过期。
	//
	// 返回:
	//   - bool: 底层实现接受或排队该写入请求时返回 true;是否最终保留由具体实现决定。
	SetWithTTL(key interface{}, value interface{}, ttl time.Duration) bool

	// Delete 删除 key 对应的缓存项。
	//
	// 参数:
	//   - key: 待删除的缓存键,具体可接受类型由实现决定;key 不存在时该操作无效果。
	Delete(key interface{})

	// Clear 清空当前缓存中的所有缓存项。
	//
	// Clear 非原子;调用方应避免将其与读写操作并发调用,除非具体实现明确提供更强保证。
	//
	// 参数:无。
	Clear()

	// Close 关闭缓存并释放相关资源。
	//
	// Close 不应与其它缓存操作并发调用,关闭后的缓存实例也不应继续用于读写操作。
	//
	// 参数:无。
	//
	// 返回:
	//   - error: 关闭底层资源失败时返回错误;具体错误语义由实现决定。
	Close() error
}

Cache 定义缓存访问接口。

常规 Get、GetWithTTL、Set、SetWithTTL 和 Delete 操作遵循具体实现的并发能力;本包内置实现使用 Ristretto 作为后端。Clear 非原子,调用方应避免将其与读写操作并发执行;Close 属于生命周期操作, 关闭后不得继续使用缓存,且不应与其它操作并发调用。键和值的可接受类型由具体实现决定。

func NewCache

func NewCache(options ...Option) (Cache, error)

NewCache 使用当前内置的 Ristretto 后端创建独立缓存实例。

未提供 Option 时会使用包内默认的 NumCounters、MaxCost 和 BufferItems。多个 Option 会按传入顺序应用, 后传入的选项可以覆盖先前写入的同一字段。调用方在实例不再使用时应调用 Close。

参数:

  • options: 可选配置项;为空时使用默认的 NumCounters、MaxCost 和 BufferItems。

返回:

  • Cache: 创建成功后的缓存实例。
  • error: 底层 Ristretto 初始化失败时返回错误,通常由无效配置触发。

type CacheOptions

type CacheOptions struct {
	// NumCounters 指定用于跟踪访问频率的计数器数量,通常应约为预期最大独立键数量的 10 倍。
	//
	// 该值应使用正值;0 会导致当前 Ristretto 初始化失败。值越大,驱逐准确度通常越高,但会占用更多内存。
	NumCounters int64

	// MaxCost 指定缓存允许的最大成本。
	//
	// 本包内置实现写入每个缓存项时传入成本 1,但未设置 IgnoreInternalCost,底层可能计入内部存储成本,
	// 因此该值不能作为严格最大条目数。该值应使用正值;0 会导致当前 Ristretto 初始化失败。
	MaxCost int64

	// BufferItems 指定 Ristretto 读写缓冲使用的条目数量。
	//
	// 该值应使用正值;0 会导致当前 Ristretto 初始化失败。较大的缓冲区可能提升并发性能,但会增加内存使用。
	BufferItems int64
}

CacheOptions 定义创建缓存实例时使用的容量与缓冲配置。

这些配置会直接传递给底层 Ristretto 构造过程。零值 CacheOptions 会使当前 Ristretto 初始化失败, 调用方通常应通过 NewCache 的默认值或 WithNumCounters、WithMaxCost、WithBufferItems 组合生成正值配置; 其它非法值由底层 Ristretto 返回错误或决定具体表现。

type Option

type Option func(*CacheOptions)

Option 定义修改 CacheOptions 的函数式选项。

参数:

  • *CacheOptions: 待修改的缓存配置实例,NewCache 和 InitCache 在应用选项时传入非 nil 指针。

func WithBufferItems

func WithBufferItems(bufferItems int64) Option

WithBufferItems 设置 Ristretto 读写缓冲使用的条目数量。

参数:

  • bufferItems: 缓冲条目数量,通常应使用正值;0 会导致当前 Ristretto 初始化失败,默认值 64 适用于大多数场景。

返回:

  • Option: 应用于 CacheOptions.BufferItems 的函数式选项。

func WithMaxCost

func WithMaxCost(maxCost int64) Option

WithMaxCost 设置缓存允许的最大成本。

参数:

  • maxCost: Ristretto 成本容量,通常应使用正值;0 会导致当前 Ristretto 初始化失败。内置实现写入成本为 1, 但底层可能计入内部存储成本,因此该值不能作为严格最大条目数。

返回:

  • Option: 应用于 CacheOptions.MaxCost 的函数式选项。

func WithNumCounters

func WithNumCounters(numCounters int64) Option

WithNumCounters 设置缓存跟踪访问频率使用的计数器数量。

参数:

  • numCounters: 计数器数量,通常应使用正值并约为预期最大独立键数量的 10 倍;0 会导致当前 Ristretto 初始化失败。

返回:

  • Option: 应用于 CacheOptions.NumCounters 的函数式选项。

type TypedCache

type TypedCache[T any] struct {
	// contains filtered or unexported fields
}

TypedCache 在 Cache 上提供泛型类型安全包装。

TypedCache 与底层 Cache 共享同一批缓存项和生命周期。零值 TypedCache 不可直接使用;调用方应通过 AsTypedCache 传入非 nil Cache 创建实例。读取时如果底层值无法断言为 T,会按缓存未命中处理。

func AsTypedCache

func AsTypedCache[T any](cache Cache) *TypedCache[T]

AsTypedCache 将已有 Cache 包装为类型安全缓存。

包装器不复制数据,也不改变底层缓存的关闭责任;类型安全读取仅在取出的值可断言为 T 时命中。

参数:

  • cache: 待包装的底层缓存实例,调用方应保证其非 nil。

返回:

  • *TypedCache[T]: 与 cache 共享存储和生命周期的类型安全缓存包装器。

func (*TypedCache[T]) Clear

func (tc *TypedCache[T]) Clear()

Clear 清空底层 Cache 中的所有缓存项。

Clear 非原子;调用方应避免将其与读写操作并发调用,除非底层 Cache 明确提供更强保证。

参数:无。

func (*TypedCache[T]) Close

func (tc *TypedCache[T]) Close() error

Close 关闭底层 Cache 并释放相关资源。

Close 不会修改 TypedCache 自身状态,不应与其它缓存操作并发调用;关闭后的包装器不应继续用于读写操作。

参数:无。

返回:

  • error: 底层 Cache 关闭失败时返回错误。

func (*TypedCache[T]) Delete

func (tc *TypedCache[T]) Delete(key interface{})

Delete 删除 key 对应的缓存项。

参数:

  • key: 待删除的缓存键,具体可接受类型由底层 Cache 决定;key 不存在时该操作无效果。

func (*TypedCache[T]) Get

func (tc *TypedCache[T]) Get(key interface{}) (value T, exists bool)

Get 获取 key 对应的 T 类型缓存值。

参数:

  • key: 待查询的缓存键,具体可接受类型由底层 Cache 决定。

返回:

  • value: 命中且类型匹配时返回缓存值;未命中、已过期或类型不匹配时返回 T 的零值。
  • exists: key 存在、未过期且底层值可断言为 T 时为 true。

func (*TypedCache[T]) GetWithTTL

func (tc *TypedCache[T]) GetWithTTL(key interface{}) (value T, exists bool, remainingTTL time.Duration)

GetWithTTL 获取 key 对应的 T 类型缓存值及剩余过期时间。

参数:

  • key: 待查询的缓存键,具体可接受类型由底层 Cache 决定。

返回:

  • value: 命中且类型匹配时返回缓存值;未命中、已过期或类型不匹配时返回 T 的零值。
  • exists: key 存在、未过期且底层值可断言为 T 时为 true。
  • remainingTTL: 剩余过期时间,0 表示 key 不存在、已过期或类型不匹配,-1 表示永不过期,正值表示实际剩余时间。

func (*TypedCache[T]) Set

func (tc *TypedCache[T]) Set(key interface{}, value T) bool

Set 写入永不过期的 T 类型缓存值。

参数:

  • key: 待写入的缓存键,具体可接受类型由底层 Cache 决定。
  • value: 待缓存的 T 类型值。

返回:

  • bool: 底层 Cache 接受或排队该写入请求时返回 true;是否保证最终保留由底层实现决定。

func (*TypedCache[T]) SetWithTTL

func (tc *TypedCache[T]) SetWithTTL(key interface{}, value T, ttl time.Duration) bool

SetWithTTL 写入带过期时间的 T 类型缓存值。

参数:

  • key: 待写入的缓存键,具体可接受类型由底层 Cache 决定。
  • value: 待缓存的 T 类型值。
  • ttl: 缓存有效期;ttl 小于等于 0 时表示永不过期。

返回:

  • bool: 底层 Cache 接受或排队该写入请求时返回 true;是否保证最终保留由底层实现决定。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL