Documentation
¶
Overview ¶
Package twolevel 是 oekit 的两级缓存组合件:L1 本地缓存 + L2 任意 CacheAside 远端缓存(典型为 redisx/cache.RedisCache)的读穿写透装饰器, 以及跨实例 L1 失效广播(Bus,Redis pubsub)。
TwoLevelCache 语义分层 ¶
- L1 只缓存真值(命中即返回,不打 L2);null 防穿透完全委托 L2 的 null marker(Source 返回 (nil, nil) 时 marker 落在 L2,后续 GetOrLoad 每次 L1 miss 后查一跳 L2 即被 marker 挡住,不回源);
- GetOrLoad/Get 在 L2 命中后回填 L1(TTL 归 L1 自身配置);
- Set/SetWithTTL 写穿两级;SetWithTTL 的显式 TTL 同时作用于 L1 与 L2(否则 L1 长驻会吞掉显式短 TTL 的过期语义);
- Del/DelBatch 双删两级,顺序固定先远端后本地:远端失败时本地已删, 读路径回填的是远端旧值(短窗口,TTL 兜底);反序则本地旧值会活过 整个 L1 TTL;
- Refresh 走 L2 删除重载(marker 一并清除),新值回填 L1。
Bus 失效广播(多实例部署必备) ¶
单实例的 Del 只能删掉自己的 L1——其他实例的 L1 副本要靠 TTL 才能过期。 Bus 在 Del/DelBatch 时向 Redis 频道发布失效消息,各实例的订阅循环收到 后驱逐自己的 L1 副本(含发布者自身,幂等)。只广播失效、不广播回填: Set/回填意味着 L2 有了新值,他实例旧 L1 由下一次写路径广播驱逐或 TTL 兜底——这与 cache-aside 的整体语义一致。
与 cached 编排的组合 ¶
TwoLevelCache 实现 CacheAside[T],可直接作为 cached.NewRepository 后端 工厂的产物:cached 管「写后失效编排」,twolevel 管「后端形态」——
repo := cached.NewRepository[User](rawRepo, func(src cache.SourceFunc[User]) cache.CacheAside[User] {
return twolevel.NewTwoLevelCache(localL1, redisL2With(src), twolevel.WithBus[User](bus))
}, ...)
cached 写路径的 DelBatch 会经 TwoLevelCache 双删两级并广播给全部实例。
值语义沿用 pkg/cache 实现契约:返回值一律只读对待(L1 共享内部引用, L2 序列化型后端每次新副本);回填 best-effort,失败记日志不阻断。
TTL 前提(务必遵守) ¶
上述一切"短窗口 + TTL 兜底"的论证都建立在 **L1/L2 TTL 均为有限值** 之上:LocalCache 的 TTL=0 表示永不过期——多实例部署下丢失一条失效 广播,该键的 L1 陈旧就不再有界。两级缓存场景禁止 TTL=0。
Index ¶
- type Bus
- type CachedOption
- type TwoLevelCache
- func (c *TwoLevelCache[T]) Close(ctx context.Context) error
- func (c *TwoLevelCache[T]) Del(ctx context.Context, key string) error
- func (c *TwoLevelCache[T]) DelBatch(ctx context.Context, keys ...string) error
- func (c *TwoLevelCache[T]) Exists(ctx context.Context, key string) (bool, error)
- func (c *TwoLevelCache[T]) Get(ctx context.Context, key string) (*T, error)
- func (c *TwoLevelCache[T]) GetOrLoad(ctx context.Context, key string) (*T, error)
- func (c *TwoLevelCache[T]) MGet(ctx context.Context, keys ...string) (map[string]*T, error)
- func (c *TwoLevelCache[T]) Refresh(ctx context.Context, key string) (*T, error)
- func (c *TwoLevelCache[T]) Set(ctx context.Context, key string, value *T) error
- func (c *TwoLevelCache[T]) SetWithTTL(ctx context.Context, key string, value *T, ttl time.Duration) error
- func (c *TwoLevelCache[T]) Start(ctx context.Context) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bus ¶
type Bus struct {
// contains filtered or unexported fields
}
Bus 是跨实例 L1 失效广播:Del/DelBatch 时向 Redis 频道发布失效消息, 订阅循环收到后驱逐本实例的 L1 副本(含发布者自身,幂等)。
只广播失效、不广播回填:Set/回填意味着 L2 有了新值,他实例旧 L1 由 下一次写路径广播驱逐或 TTL 兜底——与 cache-aside 的整体语义一致。 发布是 best-effort:失败记日志不阻断删除(远端实例靠 TTL 兜底)。
生命周期由 TwoLevelCache 管理(WithBus 挂接 + Start/Close),不单独 Start/Stop;单生命周期(Close 后复用需新建 Bus——ctx watcher 的 done 通道一次性)。
type CachedOption ¶
type CachedOption[T any] func(*config[T])
CachedOption 配置 TwoLevelCache(命名对齐仓内硬规则,避免裸 Option)。
func WithBus ¶
func WithBus[T any](bus *Bus) CachedOption[T]
WithBus 挂接失效广播:Del/DelBatch 时向 Redis 频道发布失效消息, Start 后订阅循环驱逐本实例(及其他实例)的 L1 副本。多实例部署必备; 单实例可不挂。
type TwoLevelCache ¶
type TwoLevelCache[T any] struct { // contains filtered or unexported fields }
TwoLevelCache 是两级缓存装饰器:L1 本地缓存 + L2 远端 CacheAside (如 redisx/cache.RedisCache)读穿写透组合。实现 cache.CacheAside[T], 可作为 cached.NewRepository 的后端工厂产物,也可独立使用。
语义分层见包文档;Del 先远后本的理由、null marker 委托 L2 的机制、 SetWithTTL 双层传导的必要性均在类型与包文档中固化。
func NewTwoLevelCache ¶
func NewTwoLevelCache[T any]( local cache.Cache[T], remote cache.CacheAside[T], opts ...CachedOption[T], ) (*TwoLevelCache[T], error)
NewTwoLevelCache 创建两级缓存。local/remote 均必填,构造期 nil 检查 fail-fast(而非首个操作时深层 panic);remote 必须自带 Source (Cache-Aside 回源配置在远端实现上,本类型不重复持有回源函数)。
func (*TwoLevelCache[T]) Close ¶
func (c *TwoLevelCache[T]) Close(ctx context.Context) error
Close 停止订阅循环(若有)并透传 L1 的 Close(ctx) error(Once 幂等, 重复调用安全;L1 不实现 Close 时为 no-op)。
func (*TwoLevelCache[T]) Del ¶
func (c *TwoLevelCache[T]) Del(ctx context.Context, key string) error
Del 双删两级(先远端后本地,理由见包文档);挂 bus 时发布失效消息 (best-effort,发布失败由远端实例 TTL 兜底)。key 不存在时幂等不报错。
func (*TwoLevelCache[T]) DelBatch ¶
func (c *TwoLevelCache[T]) DelBatch(ctx context.Context, keys ...string) error
DelBatch 双删两级(批量口径同 Del)。空 keys 为幂等 no-op。
func (*TwoLevelCache[T]) Get ¶
func (c *TwoLevelCache[T]) Get(ctx context.Context, key string) (*T, error)
Get 读穿获取:L1 命中直接返回;L2 命中后回填 L1 并返回。
func (*TwoLevelCache[T]) GetOrLoad ¶
func (c *TwoLevelCache[T]) GetOrLoad(ctx context.Context, key string) (*T, error)
GetOrLoad 读穿回源:L1 命中直接返回;L1 miss 时 L2 负责回源与 null marker 防穿透,拿到真值后回填 L1。Source 返回 (nil, nil) 时透传 (nil, nil),L1 不缓存 null。
func (*TwoLevelCache[T]) MGet ¶ added in v0.8.0
MGet 跨层批量读:L1 具备批量能力则单次锁区间取回,缺席键交 L2 单次 批量(两层都不具备时退化为逐键读),L2 命中逐键回填 L1。缺席语义与 (nil, nil) 双关一致:不存在与 null marker 一律缺席——L2 的 marker 短路 不参与 MGet(纯读),缺席键的消费方应回退 GetOrLoad。
func (*TwoLevelCache[T]) Refresh ¶
func (c *TwoLevelCache[T]) Refresh(ctx context.Context, key string) (*T, error)
Refresh 刷新:清 L1 后走 L2 的删除重载(null marker 一并清除),新值回填 L1。
func (*TwoLevelCache[T]) Set ¶
func (c *TwoLevelCache[T]) Set(ctx context.Context, key string, value *T) error
Set 写穿两级(各自使用实现的默认 TTL)。
func (*TwoLevelCache[T]) SetWithTTL ¶
func (c *TwoLevelCache[T]) SetWithTTL(ctx context.Context, key string, value *T, ttl time.Duration) error
SetWithTTL 写穿两级,显式 TTL 同时作用于 L1 与 L2(否则 L1 长驻会 吞掉显式短 TTL 的过期语义)。