Help us shape the future of Go! Take the 2026 Go Developer Survey

cache

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package cache 提供泛型缓存门面。

定义 Cache[T] 和 CacheAside[T] 接口(实现契约统一收拢在 interface.go 的接口 godoc:值语义、(nil, nil) 双关、回填 best-effort、TTL 来源、 生命周期、null marker),支持多种后端实现:

  • LocalCache[T](本包): 基于内存的本地缓存(写序淘汰——FIFO + 重写 提升,读命中不提升;MaxSize、TTL、空值防穿透)
  • SingleFlightCache[T](本包): 装饰器,并发回源合并防击穿
  • RedisCache[T](独立模块 github.com/oekit/redis): 基于 go-redis 的 分布式缓存——本包零 Redis 编译依赖,用 LocalCache 的服务无需引入 Redis SDK

新增后端(etcd/consul/...)实现 CacheAside[T] 后必须通过 github.com/oekit/data/cachetest 契约测试套件(Run 全绿,含 -race) 方可接入。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HashKey

func HashKey(prefix string, args ...any) string

HashKey 基于参数生成 hash key,适用于复杂参数的缓存 key。 哈希取 SHA-256 前 16 位 hex(2026-09-15 治理轮:md5 → sha256,缓存 key 属非加密场景但无需为弱哈希留误用空间;摘要值较 v0.28.x 变化,key 为 进程/缓存生命周期内临时值,无持久化契约)。

cache.HashKey("search", "keyword", 1, 20) // "search:a1b2c3d4e5f6g7h8"

func Key

func Key(parts ...string) string

Key 用冒号连接各部分生成缓存 key。

cache.Key("user", "123", "profile") // "user:123:profile"

func TenantKey

func TenantKey(tenantID, suffix string) string

TenantKey 生成租户维度的缓存 key。

cache.TenantKey("tenant1", "config") // "tenant:tenant1:config"

func UserKey

func UserKey(userID int64, suffix string) string

UserKey 生成用户维度的缓存 key。

cache.UserKey(123, "profile") // "user:123:profile"

Types

type Cache

type Cache[T any] interface {
	// Get 获取缓存。
	// 返回 (nil, nil) 表示数据不存在(见包级"实现契约")。
	Get(ctx context.Context, key string) (*T, error)

	// Set 设置缓存(使用实现构造时的默认 TTL)。
	Set(ctx context.Context, key string, value *T) error

	// SetWithTTL 设置缓存(显式 TTL)。
	SetWithTTL(ctx context.Context, key string, value *T, ttl time.Duration) error

	// Del 删除缓存。key 不存在时不得报错(幂等)。
	Del(ctx context.Context, key string) error

	// DelBatch 批量删除缓存。同 Del 幂等。
	DelBatch(ctx context.Context, keys ...string) error

	// Exists 检查缓存是否存在。
	// 对 null marker 返回 true("缓存知道该 key 不存在"也是一种存在)。
	Exists(ctx context.Context, key string) (bool, error)
}

Cache 是泛型缓存接口,面向接口编程。 只定义通用的缓存操作,不绑定具体实现或模式。

实现契约(所有 Cache[T]/CacheAside[T] 实现必须遵守)

值语义(别名警告):

实现**可以**返回缓存内部共享引用(零拷贝热路径,如 LocalCache),
调用方**禁止改写**返回的 *T 指向的值——改写会直接污染缓存条目,
并与并发读构成 data race;需要可变副本时调用方自行拷贝。
序列化型实现(如 Redis 后端)每次反序列化返回新副本,天然无别名。
同一接口允许两种别名语义,因此调用方一律按"只读"对待返回值。
Set/SetWithTTL 传入的 value 同理:实现不拷贝时调用方此后不得改写。

(nil, nil) 双关:

Get/GetOrLoad 返回 (nil, nil) 表示"数据不存在"——key miss 或命中
null marker(见 SourceFunc)二者之一;error 非 nil 时值无效。
miss 不是 error,不应记错误日志。

回填 best-effort:

GetOrLoad/Refresh 从 Source 取到数据后的回填写入失败**不阻断**返回
已取到的数据(实现自行记日志);下次请求会重新回源。

TTL 来源:

  • Set:使用实现构造时配置的默认 TTL;
  • SetWithTTL:显式传参;
  • GetOrLoad 回填:使用默认 TTL。

TTL<=0 的语义(0 = 不过期还是实现默认值)由各实现的配置文档定义 (LocalCache:0 = 不过期;Redis 后端见各自 Config)。

生命周期:

接口不含 Close——生命周期属于具体实现的资源管理,不由接口约束。
需要停止后台资源的实现自行提供 Close,并遵循仓库硬规则签名
Close(ctx context.Context) error + sync.Once 幂等。

type CacheAside

type CacheAside[T any] interface {
	Cache[T]

	// GetOrLoad 获取缓存,未命中时通过 Source 加载并回填。
	// Source 返回 (nil, nil) 时缓存 null marker(防穿透,TTL 见 SourceFunc);
	// 后续调用命中 null marker 直接返回 (nil, nil),不再调用 Source。
	GetOrLoad(ctx context.Context, key string) (*T, error)

	// Refresh 刷新缓存(删除后重新从 Source 加载)。
	Refresh(ctx context.Context, key string) (*T, error)
}

CacheAside 是 Cache-Aside 模式扩展接口。 在 Cache 基础上增加数据源回填、刷新等能力。

GetOrLoad/Refresh 遵循包级"实现契约":miss 非 error、回填 best-effort、 null marker 防穿透。

新增后端(etcd/consul/...)必须实现本接口并通过 github.com/oekit/data/cachetest 契约测试套件(Run 全绿)方可接入。

type LocalCache

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

LocalCache 是基于内存的本地缓存实现。 适用于单实例场景或作为二级缓存。 淘汰策略为写序淘汰(FIFO + 重写提升,读命中不提升——非严格 LRU): 达到 MaxSize 后淘汰最早写入(且未被重写刷新)的条目。 使用 Close(ctx) 方法停止后台清理 goroutine;Close 可安全重复调用, 签名对齐仓库硬规则 Close(ctx context.Context) error。

func NewLocalCache

func NewLocalCache[T any](cfg LocalConfig[T]) *LocalCache[T]

NewLocalCache 创建一个本地缓存实例。

func (*LocalCache[T]) Clear

func (c *LocalCache[T]) Clear()

Clear 清空缓存。

func (*LocalCache[T]) Close

func (c *LocalCache[T]) Close(ctx context.Context) error

Close 停止后台清理 goroutine(TTL>0 时构造启动的那个)。 sync.Once 保证幂等:重复 Close 不 panic、不返回错误。

ctx 预留:当前实现同步返回 nil,ctx 不阻塞——本实现无外部资源需要 排空,仅关闭内部 done channel 通知 cleanup goroutine 退出。

func (*LocalCache[T]) Del

func (c *LocalCache[T]) Del(ctx context.Context, key string) error

Del 删除缓存。

func (*LocalCache[T]) DelBatch

func (c *LocalCache[T]) DelBatch(ctx context.Context, keys ...string) error

DelBatch 批量删除缓存。

func (*LocalCache[T]) Exists

func (c *LocalCache[T]) Exists(ctx context.Context, key string) (bool, error)

Exists 检查缓存是否存在。

func (*LocalCache[T]) Get

func (c *LocalCache[T]) Get(ctx context.Context, key string) (*T, error)

Get 获取缓存。 返回 (nil, nil) 表示数据不存在 —— 包括 key 不存在和命中 null marker 两种情况;GetOrLoad 会区分二者实现防穿透。

⚠️ 返回的是缓存内部的 *T(零拷贝,热路径设计):调用方不得修改指向的 值——会污染缓存并与并发读形成 data race。需要可变副本时自行拷贝。 (RedisCache 每次反序列化返回新副本,两实现语义差异见各自身文档。)

func (*LocalCache[T]) GetOrLoad

func (c *LocalCache[T]) GetOrLoad(ctx context.Context, key string) (*T, error)

GetOrLoad 获取缓存,未命中时通过 Source 加载(Cache-Aside 模式)。 Source 返回 (nil, nil) 时缓存 null marker(默认 1 分钟,可用 NullTTL 调整,负值禁用);命中 null marker 时直接返回 (nil, nil),**不会**再调 Source,避免对不存在的 key 形成 thundering-herd 击穿。

func (*LocalCache[T]) Refresh

func (c *LocalCache[T]) Refresh(ctx context.Context, key string) (*T, error)

Refresh 刷新缓存(删除后重新从 Source 加载)。

func (*LocalCache[T]) Set

func (c *LocalCache[T]) Set(ctx context.Context, key string, value *T) error

Set 设置缓存(使用默认 TTL)。

func (*LocalCache[T]) SetWithTTL

func (c *LocalCache[T]) SetWithTTL(ctx context.Context, key string, value *T, ttl time.Duration) error

SetWithTTL 设置缓存(自定义 TTL)。

func (*LocalCache[T]) Size

func (c *LocalCache[T]) Size() int

Size 返回当前缓存条目数。

type LocalConfig

type LocalConfig[T any] struct {
	// TTL 缓存过期时间。0 表示不过期。
	TTL time.Duration

	// MaxSize 最大缓存条目数。0 表示不限制。
	MaxSize int

	// Source 缓存未命中时的数据获取函数(Cache-Aside 模式)。
	Source SourceFunc[T]

	// NullTTL 空值缓存过期时间(防穿透)。
	//   - 0(未设置):使用默认值 1 分钟;
	//   - 负值:显式禁用空值缓存(Source 返回 nil 时不写 null marker,
	//     下次 GetOrLoad 会重新调用 Source);
	//   - 正值:按指定时长缓存 null marker。
	NullTTL time.Duration
}

LocalConfig 配置本地缓存实例。

type SingleFlightCache

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

SingleFlightCache 是带 singleflight 保护的缓存装饰器。 同一个 key 的并发请求只会有一个实际调用 Source,其他请求等待共享结果。 防止缓存击穿(热点 key 过期时的雷群效应)。

可以包装任何 CacheAside[T] 实现(Redis、本地缓存等)。

func NewSingleFlightCache

func NewSingleFlightCache[T any](inner CacheAside[T]) *SingleFlightCache[T]

NewSingleFlightCache 创建带 singleflight 保护的缓存装饰器。 inner 可以是 RedisCache、LocalCache 或任何实现 CacheAside[T] 的缓存。

func (*SingleFlightCache[T]) Del

func (sf *SingleFlightCache[T]) Del(ctx context.Context, key string) error

Del 删除缓存。

func (*SingleFlightCache[T]) DelBatch

func (sf *SingleFlightCache[T]) DelBatch(ctx context.Context, keys ...string) error

DelBatch 批量删除缓存。

func (*SingleFlightCache[T]) Exists

func (sf *SingleFlightCache[T]) Exists(ctx context.Context, key string) (bool, error)

Exists 检查缓存是否存在。

func (*SingleFlightCache[T]) Get

func (sf *SingleFlightCache[T]) Get(ctx context.Context, key string) (*T, error)

Get 获取缓存(纯查询,不触发 Source)。

func (*SingleFlightCache[T]) GetOrLoad

func (sf *SingleFlightCache[T]) GetOrLoad(ctx context.Context, key string) (*T, error)

GetOrLoad 获取缓存,带 singleflight 保护。 同一个 key 的并发请求只会有一个实际调用 Source。

流程:

  1. 查缓存,命中则直接返回
  2. 未命中时通过 singleflight 去重,只有一个 goroutine 调用 Source
  3. Source 返回后回填缓存
  4. 其他 goroutine 共享同一份结果

func (*SingleFlightCache[T]) Refresh

func (sf *SingleFlightCache[T]) Refresh(ctx context.Context, key string) (*T, error)

Refresh 刷新缓存(带 singleflight 保护)。

func (*SingleFlightCache[T]) Set

func (sf *SingleFlightCache[T]) Set(ctx context.Context, key string, value *T) error

Set 设置缓存。

func (*SingleFlightCache[T]) SetWithTTL

func (sf *SingleFlightCache[T]) SetWithTTL(ctx context.Context, key string, value *T, ttl time.Duration) error

SetWithTTL 设置缓存(自定义 TTL)。

type SourceFunc

type SourceFunc[T any] func(ctx context.Context, key string) (*T, error)

SourceFunc 缓存未命中时的数据获取函数。

返回 (nil, nil) 表示数据不存在——实现会缓存 null marker 防穿透: 后续 GetOrLoad 命中 null marker 时直接返回 (nil, nil),不再调用 Source; Exists 对 null marker 返回 true。

null 标记的 TTL 语义由各实现的配置定义 (LocalCache:NullTTL 0 = 默认 1 分钟,负值 = 显式禁用空值缓存)。

Source 返回的 *T 所有权随值语义契约:实现回填后调用方与实现共享引用 或各持副本,取决于实现(同"实现契约"的值语义,调用方一律只读对待)。

Jump to

Keyboard shortcuts

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