tablecache

package module
v1.26.2 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

README

tablecache

tablecache 是一个框架无关的 Redis 表数据缓存管理库。它把缓存目标声明、读穿回源、批量写入、刷新锁、TTL 抖动、空值占位、前缀删除和管理页响应结构收口到一套稳定组件里,适合管理后台、定时预热任务和业务读取链路共同复用。

特性概览

能力 说明
读穿缓存 LoadThrough / GetOrRefresh 先读缓存,miss 后按注册的 Loader 回源并写回。
防击穿 同进程使用 singleflight 合并同 key 刷新,多实例通过 Lua 原子获取刷新锁并观察当前 owner。
防穿透 AllowEmptyMarker 对重复访问的不存在 key 写短 TTL 空值占位;随机高基数 miss 由 Loader 全局并发上限继续保护数据源。
防雪崩 TTL + Jitter 分散过期时间;Loader 默认 30 秒超时、单 Manager 默认最多并发 32 个回源。
安全提交 Manager 把当前锁的 LockGuard 传到底层提交;RedisStore 在 Lua 实际写删时原子校验 owner,锁已失效则不修改缓存。
前缀治理 单节点/哨兵支持普通前缀;Cluster 仅允许固定 hash tag 同槽前缀。
Redis 部署 支持单节点、哨兵主节点和 Cluster master 读取;Ring 因故障重映射可能复活旧值,在构造期整体拒绝。
集合治理 集合分页读取及全量读写默认限制 5000 个成员,避免大 Hash/List/Set/ZSet 一次性拉爆内存。
管理页响应 内置批量刷新、批量读穿响应;JSON 只输出稳定 code/message,原始错误仅保留在 Go 字段中。
可观测性 支持 Prometheus 指标、结构化事件日志和 key 脱敏。

版本要求

  • 源码兼容 Go 1.26+;生产构建使用 Go 1.26.5+
  • Redis 6.2+,推荐 Redis 7+
  • 依赖 go-redis、Prometheus client、go-utils 等基础库

安装

go get github.com/Is999/table-cache

快速开始

下面示例展示一个用户资料缓存:key 前缀为 a:,业务 key 为 a:user:1

package cache

import (
	"context"
	"fmt"
	"strconv"
	"time"

	tablecache "github.com/Is999/table-cache"
	"github.com/redis/go-redis/v9"
)

type User struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

type UserModel interface {
	FindOne(ctx context.Context, id int64) (*User, error)
}

func NewUserCache(client redis.UniversalClient, model UserModel) (*tablecache.Manager, error) {
	store := tablecache.NewRedisStore(client)

	return tablecache.NewManager(store, []tablecache.Target{
		{
			Index:            "user",
			Title:            "用户资料",
			Key:              "user:",
			KeyTitle:         "user:{id}",
			Type:             tablecache.TypeString,
			TTL:              time.Hour,
			Jitter:           10 * time.Minute,
			AllowEmptyMarker: true,
			Loader: func(ctx context.Context, params tablecache.LoadParams) ([]tablecache.Entry, error) {
				if len(params.KeyParts) != 1 {
					return nil, fmt.Errorf("user前缀全量刷新未实现")
				}
				id, err := strconv.ParseInt(params.KeyParts[0], 10, 64)
				if err != nil {
					return nil, err
				}
				user, err := model.FindOne(ctx, id)
				if err != nil {
					return nil, err
				}
				if user == nil {
					return nil, tablecache.ErrNotFound
				}
				return []tablecache.Entry{{
					Key:   params.Key,
					Type:  tablecache.TypeString,
					Value: user,
				}}, nil
			},
		},
	}, tablecache.WithKeyPrefix("a:"))
}

业务读取:

var user User
result, err := manager.LoadThrough(ctx, "a:user:1", &user, nil)
if err != nil {
	return err
}
if result.State == tablecache.LookupStateHit {
	// user 来自缓存命中或 miss 后回源写回。
}

管理页刷新:

if err := manager.RefreshByKey(ctx, "a:user:1"); err != nil {
	return err
}

批量预热:

results, summary, err := manager.RefreshByKeysWithSummary(ctx, []string{
	"a:user:1",
	"a:user:2",
})
response := tablecache.BuildRefreshBatchAdminResponseWithSummary(results, summary, err)
_ = response

完整可运行示例见 example/admin_integration

核心概念

Target

Target 描述一个缓存目标。Key / KeyTitle 必须是不含 WithKeyPrefix 的逻辑值,注册时始终拼接项目命名空间;预拼物理前缀会在构造期返回 ErrInvalidConfig。固定 key 用完整逻辑 key,前缀型 key 以冒号结尾。

字段 说明
Index 稳定索引名,用于管理页、指标和日志。
Title 展示名称。
Key 逻辑 key 或逻辑前缀,例如 user:
KeyTitle 展示模板,例如 user:{id}
Type Redis 类型:String、Hash、List、Set、ZSet。
TTL / Jitter 基础过期时间和最大抖动;Jitter=0 时 RedisStore 默认按 TTL 的 10% 抖动,只有 WithDefaultJitterRatio(0) 才会关闭。
EmptyTTL 空值占位过期时间。
LoaderTimeout 当前目标回源超时时间。
RefreshAll 是否允许被 RefreshAll 批量刷新。
AllowEmptyMarker 查无数据时是否写空值占位。
Loader 回源函数,返回要写入 Redis 的 Entry 列表。

Manager.Items() 返回管理列表展示契约,其中 key 是注册后真正用于操作的固定 key 或前缀,keyTitle 是展示模板;二者不会互相覆盖。结果还包含 indextitletyperemark

Key 前缀

默认业务 key 前缀是 tc:。生产项目建议显式传入以冒号结尾的短项目前缀,例如 WithKeyPrefix("a:")

内部锁、空值占位、前缀索引等元信息 key 使用短根前缀 tcm:,与业务 key 前缀分开管理。

  • Get / GetState 支持传逻辑 key,会自动补前缀后只读查询。
  • RefreshByKeyRefreshByKeysDeleteByKeyDeleteByPrefixLoadThroughGetOrRefresh 的写回路径必须传实际 key。
  • 未带前缀的 miss 请求只做只读查询,不会触发回源写入,避免误写非托管 key。
  • 构造期始终拒绝空前缀、未以冒号结尾的前缀、通配符、空白字符和内部保留根 tcm:;目标 key 会独立校验 Redis Cluster hash tag。
  • 内部前缀删除通过 RedisPrefixPattern 转义 Redis glob 字符;自定义 PrefixReplaceStore 也必须使用已经转义的 DeletePatterns
Entry

Entry 是 Loader 返回的写入单元。Loader 的写入范围按本次请求收紧:

  • 固定目标只能写固定 key。
  • 前缀目标的非全量请求只能返回 Entry.Key == params.Key;不能借一次单 key 回源顺带写入同前缀其它 key。
  • 只有 params.Key == params.Target.Key 的前缀全量请求可以返回该 Target 前缀内的多个 key,并且必须给出完整、权威快照。
  • Hash/List/Set/ZSet 的空集合会写内部元信息,使后续读取明确返回 hit,而不是反复 miss。
  • Overwrite=nil/true 使用可重试的覆盖写;Overwrite=false 只允许 Hash、Set、ZSet 的幂等增量写。String 没有独立增量语义,List 增量 RPUSH 在网络响应丢失重放时会重复成员,二者都会在构造写计划时返回 ErrInvalidConfig

并发与一致性

当多个请求同时读取一个不存在的缓存:

  1. 所有请求先查缓存。
  2. 同一进程内相同 key 通过 singleflight 合并。
  3. 多实例通过 Lua 原子竞争重建锁并观察 owner,只有持锁方执行 Loader。
  4. 未抢到锁的请求等待同一语义范围的短结果 marker;拿锁方还会二次检查缓存和刷新 generation,关闭快速 owner 窗口。
  5. Loader 查无数据时可写空值占位,避免热点空数据持续穿透数据库。
  6. 长 Loader 会自动续期锁;锁续期和 Go 侧预检只用于尽早发现失锁,不是最终正确性边界。

请求型读穿、显式刷新和 RefreshAll 的本地 flight 与分布式结果 marker 相互隔离,不能用 scheduled 空结果替代请求型空值语义。未使用单次 Loader、超时、marker 或 context policy 覆盖时,即使 AllowEmptyMarker=false,一次成功但为空的默认读穿也会发布短完成 generation,只合并已经进入同一轮的 waiter,不会把后续新请求变成持久负缓存。带单次覆盖的调用无法证明跨实例语义相同,不共享 generation;热点空值仍应开启 AllowEmptyMarkerLookupResult.Refreshed 表示本次 miss 参与了执行、等待或复用刷新结果,不等同于“当前 goroutine 一定执行了 Loader”。

DeleteByKey 与同 key 刷新共用刷新锁,失锁后的旧请求再由 Lua fencing 阻断写回,不额外维护重复的 key epoch。跨 key 的前缀全量刷新和前缀删除仍使用前缀提交锁及必要的 prefix/member epoch,避免旧单 key 刷新覆盖新全量结果,或旧全量快照复活已删除成员。刷新起始会在短提交锁内确保代际非空;提交时代际缺失、被淘汰或变化都按失效处理,不能把“首次为空”和“删除后被淘汰为空”误判成相等。

所有 Manager 可见的业务写入、删除、marker 切换和 ready 状态提交都会携带当前刷新锁或前缀锁的 LockGuard。RedisStore 在每批真实 Redis 写删所用的 Lua 内先校验 LockGuard.Key 对应的值仍等于 LockGuard.Owner,并在同一个原子执行边界内完成该批变更;任一 guard 不匹配时整批不落数据。索引新成员可以在业务写入前先登记,因为它只会把索引扩大为安全超集,不会让删除漏掉已可见数据。前缀全量操作可能分成多批,它保证的是“每一批都在仍持锁时提交”,不是把整个快照伪装成单个超大事务。自定义 Store 也必须提供等价的原子 guard 语义,不能只在 Go 中先 GET 再写删。

回源并发边界
  • Loader 默认超时为 30 秒,可用 WithLoaderTimeoutTarget.LoaderTimeout 调整;0 表示沿用上级默认值,负数或超过 24 小时会在启动期返回 ErrInvalidConfig
  • Loader 超时只包围等待 Loader 槽和 Loader 本身;锁、代际与 Redis 提交受完整刷新总预算约束。即使使用 RebuildContextIgnoreCancel,完整刷新和最终回读也保留内部截止时间,不会永久挂起。
  • Loader 及其 DB/RPC 调用必须透传并响应 ctx;Go context 不能强制终止忽略取消信号的业务函数,违反该约定仍会长期占用 goroutine 和刷新锁。
  • 刷新锁 TTL 至少 30ms,显式续期间隔至少 10ms;显式等待步长至少 1ms、最多 100000 次且总窗口不超过 24 小时。
  • 单个 Manager 默认最多同时执行 32 个 Loader,可用 WithLoaderConcurrency 调整;Loader、批量刷新和批量读穿并发硬上限均为 256,并按实际任务数分配并发槽。
  • 该上限是单进程、单 Manager 的数据源保护边界;多实例部署仍应结合数据库/RPC 容量设置每实例值。
  • 只有真实允许跨 key 前缀操作的目标,Loader 有效超时才必须不超过前缀代际 TTL 的一半;固定 key 和 Cluster 无 tag 的逐 key 路径不使用 prefix epoch,不受这项无关限制。
Hash fields 局部刷新

LoadThroughOptions.Fields 只允许用于 TypeHash,并要求 Store 同时实现 CollectionPageStoreHashFieldsStore;开启字段级空值占位时还要实现 FieldsEmptyStore

  • HMGET 缺少任一请求字段时按 miss 处理,不把半份结果当成 hit。
  • Loader 必须返回同一个 Hash key、恰好一条 Entry,并完整覆盖请求字段;返回额外字段或缺字段都会失败。
  • 局部刷新强制增量写入,显式 Overwrite=true 会返回 ErrPartialHashUnsupported,避免误删未请求字段。
  • Loader 返回不存在时始终通过同槽 Lua 原子删除本次请求字段;开启空值占位时再登记字段组合空值,关闭时同时清除该 Hash 的全部历史 fields registry。整 key 空刷新也会清除全部历史 registry。
  • 字段组合使用同槽 ZSET registry 保存独立到期时间,并按 Redis 服务器时间清理;单次最多渐进移除 256 个过期成员,全部过期时使用 UNLINK 异步释放。任一字段正向写回会在同一原子提交中清除该 Hash 的整个 registry,避免重叠组合保留错误负缓存;代价只是其它组合下次可能多回源一次。

单 key 刷新中的隐藏空值和真实空集合通过 MarkerReplaceStore.ReplaceWithMarker 在同一个 Redis hash slot 内先写 marker、再删除旧状态。前缀全量快照的 marker 与旧数据切换由 PrefixReplaceStore.ReplacePrefix 统一提交。自定义 Store 不支持对应能力时直接返回错误,不会退回可能暴露中间空窗的多次命令。

前缀全量替换

前缀目标执行全量刷新时,Manager 要求 Store 实现 PrefixReplaceStore。实现必须先校验并写入新快照,再删除不在 KeepKeys 中的旧 key;失败时可以暂时保留冗余旧数据,但不能先清空旧前缀。自定义 Store 未实现该接口时会返回 ErrPrefixReplaceUnsupported,不会破坏性降级。

DeleteByPrefix 只有在可信索引可用,或 Store 实现 GuardedPatternStore 时才能执行;缺少带锁 SCAN 能力会返回专用的 ErrPrefixDeleteUnsupported,不会复用全量替换错误或执行无 guard 删除。

WithScanFallback(false) 只控制 Manager.DeleteByPrefix 的在线降级。首次前缀 full refresh、索引证据丢失后的 full refresh,仍必须通过 ReplacePrefix 执行带 guard 的 SCAN 对账,才能建立权威快照和可信 ready;这类操作应放在维护窗口,并按整个 Redis keyspace、Cluster master 数量和连接池容量评估压力。

前缀 Loader 收到 params.Key == params.Target.Key 时表示全量刷新,此时 KeyParts 为空且不能携带 Fields。Loader 必须返回该前缀当前完整、权威的 Entry 快照;返回空切片会被解释为“当前快照为空”并安全删除旧成员,不会为前缀根生成空值 marker。全量 Entry 必须使用默认覆盖语义或显式 Overwrite=trueOverwrite=false 会被拒绝,避免旧 Hash 字段或集合成员混入新快照。若业务不支持全量刷新,必须返回普通错误明确拒绝,不能访问 KeyParts[0],也不能用 ErrNotFound 代替“不支持”。

前缀全量刷新和 DeleteByPrefix 还受 Redis 拓扑约束:

  • 单节点或哨兵当前主节点没有跨 slot 问题,普通前缀可以执行全量刷新和前缀删除。
  • Cluster 上不带固定 hash tag 的普通前缀会分散到多个 slot,无法让一个前缀锁与所有真实写删处于同一 Lua 原子边界,因此前缀全量刷新和 DeleteByPrefix 会快速失败(fail-fast),不执行 Loader、SCAN 或部分写删。
  • Cluster 上只有包含固定非空 hash tag 的前缀才允许这两个操作,例如 a:user:{all}:。该前缀下的业务 key、锁、marker 和在线索引都会集中到同一个 slot;这换取了原子 guard 能力,也会集中容量与热点,必须按单 slot 预算评估。
  • Ring 的故障摘除会重映射单 key,节点恢复后可能重新暴露刷新或删除前的旧值;该风险无法由逐 key 锁修复,因此 RedisStore 在构造校验期整体拒绝 Ring,而不只拒绝前缀操作。
  • 普通无固定 hash tag 的分布式前缀应使用 RefreshByKeysDeleteByKey 按实际 key 操作;每个 key 的业务值、锁和元信息会在自己的 slot 内安全提交。

Redis 配置建议

单节点
client := redis.NewClient(&redis.Options{
	Addr:     "127.0.0.1:6379",
	Password: "",
	DB:       0,
	PoolSize: 20,
})
store := tablecache.NewRedisStore(client)
Cluster
client := redis.NewClusterClient(&redis.ClusterOptions{
	Addrs: []string{
		"127.0.0.1:7001",
		"127.0.0.1:7002",
		"127.0.0.1:7003",
	},
	Password: "",
	PoolSize: 20,
	ReadOnly: false,
	RouteByLatency: false,
	RouteRandomly: false,
})
store := tablecache.NewRedisStore(client)

如果 Redis Cluster 返回的是容器 hostname,需要在业务 Redis 客户端层处理地址改写;真实集成测试可参考 redis_cluster_integration_test.goTABLECACHE_REDIS_ADDR_MAP。Redis 6.2 不支持 CLUSTER SHARDS 时,示例会回退到 CLUSTER SLOTS

RedisStore 接受 redis.UniversalClient,但生产支持范围只包括单节点、哨兵当前主节点和 Cluster master 路由:

  • 单节点和哨兵客户端按当前主节点执行。
  • Cluster 普通无固定 hash tag 的前缀全量刷新和 DeleteByPrefix 始终 fail-fast;即使客户端能遍历全部节点,也不会放宽原子提交边界。
  • Cluster 带固定 hash tag 的前缀允许执行,但全部相关 key 集中在同一个 slot;需要 SCAN 对账时,wrapper 仍须暴露可靠的 ForEachMaster 能力。
  • Cluster 的 ReadOnlyRouteByLatencyRouteRandomly 必须全部为 false。锁、marker、代际和业务值必须从 master 读取;副本延迟会破坏写后读与击穿判断,构造校验会直接拒绝这三种配置。
  • redis.NewClient 若实际连接到 Cluster seed,会在任何前缀 Loader、SCAN 或写入前拒绝,必须改用 redis.NewClusterClient,避免只处理一个 master。
  • 单节点/哨兵客户端首次执行前缀操作会通过 CLUSTER INFO 确认拓扑并缓存结果;ACL、网络错误或无法识别的响应都会 fail-close,生产账号需允许该探测命令。
  • Ring 当前版本完全不支持;请改用单节点、哨兵或 Cluster master 路由。
  • 无法确认拓扑或无法保证同槽时返回错误,不会扫描部分节点或提交部分结果后伪装成功。

生产配置

推荐起步配置:

store := tablecache.NewRedisStore(
	client,
	tablecache.WithUnlinkChunkSize(512),
	tablecache.WithMaxCollectionReadCount(5000),
	tablecache.WithMaxCollectionWriteCount(5000),
)

manager, err := tablecache.NewManager(
	store,
	targets,
	tablecache.WithKeyPrefix("a:"),
	tablecache.WithPrefixKeyIndex(true),
	tablecache.WithPrefixKeyIndexTTL(30*24*time.Hour),
	tablecache.WithScanFallback(false),
	tablecache.WithScanCount(2000),
	tablecache.WithPrefixDeleteConcurrency(1),
	tablecache.WithRefreshConcurrency(4),
	tablecache.WithLoaderTimeout(30*time.Second),
	tablecache.WithLoaderConcurrency(32),
	tablecache.WithLogKeyRedaction(true),
)
配置 建议
WithKeyPrefix 使用以冒号结尾的短项目前缀,例如 a:crm:,避免 Redis key 过长。
WithPrefixKeyIndex 默认开启,为允许执行前缀操作的 Target 维护安全 superset 索引,减少 SCAN。
WithScanFallback(false) 默认值;索引不可信时显式失败。仅维护窗口在容量评审后传 true,且不能绕过 Cluster 同槽要求。
WithScanCount 常见取值 1000 到 5000,硬上限 100000;越大单轮 Redis 压力越高。
WithUnlinkChunkSize 常见取值 500 到 1000,硬上限 10000,控制 Pipeline 大小。
WithPipelineRetries 默认 1、硬上限 10;只重试可证明幂等的 Pipeline。
WithPrefixDeleteConcurrency 高峰期保持 1 或 2;后台维护窗口可适当提高。
WithMaxCollectionReadCount 默认 5000 个成员;超限返回 ErrCollectionTooLarge,显式 0 才关闭。
WithMaxCollectionWriteCount 默认 5000 个成员;限制单 Entry 集合成员数,显式 0 才关闭。
WithLoaderTimeout 默认 30 秒;按数据源超时预算调小,0 保持默认,负数非法。
WithLoaderConcurrency 默认 32、硬上限 256;按单实例可分配的数据源并发预算设置。
WithDefaultJitterRatio 默认 0.1,只接受 0 到 1;0 关闭默认抖动。
WithLogKeyRedaction 默认开启;只有受控本地诊断才显式关闭。

集合上限只按成员数计算,不是序列化字节上限。不要把超大 blob 当表缓存;业务必须按 Redis proto-max-bulk-lenmaxmemory、网络和 Loader 超时控制单 Entry 字节数,以及一次 full Loader 的总条目和总字节。大对象应拆分、分页或放到对象存储;只有完成容量评审后才能显式传 0 关闭成员上限。

前缀索引

在线前缀索引是安全 superset,不承诺与当前业务 key 集合时刻完全相等。写入新业务 key 时先登记索引、再写业务值;在线删除不破坏性移除成员,陈旧成员由成员时间和 TTL 自然收敛。因此超时、进程退出或 Redis 部分失败最多留下可清理的陈旧成员,不会让一次成功可见的 Manager 提交产生“业务 key 已存在但索引漏记”的结果。按可信索引删除时遇到陈旧成员是安全的,因为删除不存在的 key 不会扩大操作范围。索引成员每 256 个组成一条 Lua 命令,每个 Pipeline 最多 64 条命令;过期成员每次最多渐进清理 256 个,避免大快照或过期积压制造客户端和 Redis 主线程尖峰。

DeleteByKeyDeleteByPrefix 成功后会删除真实业务状态,但保留索引成员、manifest 与 ready 证据;后续删除仍可继续走索引快路径,不会因为一次在线清理强制退化为全节点 SCAN。

索引的 manifest、ready 和完整性证据只用于证明这个 superset 可以安全作为删除候选集。重建过程的位图初始化、历史哨兵恢复、权威成员写入和 manifest 提交都受当前锁 owner 栅栏保护;首次成功且拓扑允许的前缀全量刷新会完成旧数据对账后建立 ready。证据缺失或不可信时立即撤销 ready,并按 WithScanFallback 选择 SCAN 或显式报错。Cluster 普通无固定 hash tag 仍直接 fail-fast,不能借索引或 SCAN 绕过拓扑边界;Ring 在 Store 校验期已整体拒绝。索引的内部拆分方式属于实现细节,不构成跨 slot 全量写删能力。

本版本不读取、迁移或清理旧格式索引,也不支持新旧实例混跑。升级或回滚时必须先停止全部实例,按 Target 清理原缓存与内部元信息或切换到新的 Redis namespace;启动目标版本后,只对单节点/哨兵普通前缀或 Cluster 固定 hash tag 前缀执行一次全量刷新。

API 选择

场景 推荐 API
只读缓存 Get / GetState
业务读穿 LoadThrough
读穿并临时覆盖 Loader、超时或 fields LoadThroughWithOptions
批量读穿 LoadThroughBatchWithSummaryOptions
管理页刷新单 key RefreshByKey
定时任务批量预热 RefreshByKeysWithSummary
管理页全量刷新 对拓扑允许的 Target 使用 RefreshAllWithSummary
精确删除 DeleteByKey
前缀删除 单节点/哨兵普通前缀或 Cluster 固定 hash tag 前缀使用 DeleteByPrefix;其它分布式场景使用 DeleteByKey
集合局部读取 CollectionPageStore.ReadPage

批量读穿示例:

var user1 User
var user2 User

results, summary, err := manager.LoadThroughBatchWithSummaryOptions(ctx, []tablecache.LoadThroughItem{
	{Key: "a:user:1", Dest: &user1},
	{Key: "a:user:2", Dest: &user2},
}, tablecache.LoadThroughBatchOptions{
	Concurrency: 4,
	DefaultOptions: tablecache.LoadThroughOptions{
		LoaderTimeout:    200 * time.Millisecond,
		AllowEmptyMarker: tablecache.Bool(true),
		ContextPolicy:    tablecache.RebuildPolicy(tablecache.RebuildContextIgnoreCancel),
	},
})
response := tablecache.BuildLoadThroughBatchAdminResponseWithSummary(results, summary, err)
_ = response

指标

PrometheusMetrics 同时实现基础指标、扩展指标、读穿指标、批量刷新指标和扫描降级指标。

metrics, err := tablecache.NewPrometheusMetrics(
	tablecache.WithPrometheusNamespace("admin"),
	tablecache.WithPrometheusSubsystem("tablecache"),
)
if err != nil {
	return err
}

manager, err := tablecache.NewManager(store, targets, tablecache.WithMetrics(metrics))

自定义 WithPrometheusRefreshBucketsWithPrometheusRefreshEntryBuckets 时,桶必须严格递增且不能包含 NaN;非法配置会由 NewPrometheusMetrics 直接返回错误,不会延迟到首次记录时 panic。

指标 说明
refresh_total / refresh_duration_seconds 刷新次数和耗时。
cache_hit_total / cache_miss_total 基础命中和 miss。
lock_failed_total 重建锁竞争失败次数。
loader_error_total Loader 回源错误次数。
empty_marker_write_total 空值占位写入次数。
wait_timeout_total 等待其它实例重建超时次数。
prefix_wait_total / prefix_retry_total 单 key 仅在 Redis 提交阶段等待前缀提交锁,以及因全量代际推进而重试的次数;Loader 本身不被前缀提交锁串行化。
prefix_delete_total / prefix_delete_keys_total 前缀删除次数和 Redis 实际删除 key 数;已经不存在的 key 不计数。
lookup_state_total 每次逻辑读取只记录一个最终状态:hit、miss、empty;miss 后回源成功不会再同时计一次 miss。
lookup_refresh_triggered_total 读穿触发回源次数。
scan_fallback_total 实际执行前缀降级扫描的次数;被 WithScanFallback(false) 拒绝时不计数。

日志

自定义 printf 风格日志使用 WithLogger(...),go-utils 日志使用 WithGoUtilsLogger(...);接入后统一输出稳定字段:

component=tablecache event="prefix_wait" index="user" key="sha1:7f7f...:len:8"

业务 key 默认通过 sha1:<摘要>:len:<长度> 脱敏;只有显式设置 WithLogKeyRedaction(false) 才会输出原始 key。

常见事件:

事件 含义
lock_lost 刷新过程中锁丢失,写回被中止。
lock_renew_failed 锁续期失败。
prefix_wait 单 key 已完成 Loader,正在等待同前缀的短提交锁。
prefix_retry 单 key 刷新发现前缀代际变化后主动重试。
prefix_scan_fallback 前缀索引不可用,降级为 SCAN。
refresh_batch_done / refresh_all_done 批量刷新或全量刷新完成。

管理后台接入

推荐按三层接入:

  1. svc 层创建 redis.UniversalClientStoreManager,并缓存 manager.Items() 供页面展示。
  2. logicservice 层封装 RefreshByKeyRefreshByKeysWithSummaryLoadThroughBatchWithSummaryOptions
  3. handler 层只做参数解析和响应输出,直接复用 BuildRefreshBatchAdminResponse...BuildLoadThroughBatchAdminResponse...

批量响应的顶层和逐项结果统一包含 success/code/messagecode/message 是稳定、安全的公开契约;Error 字段标记为 json:"-",只供调用方在受控日志中使用,未知下游错误统一输出 internal_error / 操作失败。不要把 Error.Error() 直接写入 HTTP JSON 或未脱敏日志。

公开 code 包括:okpartial_failureinvalid_requesttarget_not_foundloader_requiredwait_timeoutrefresh_unavailablecache_missdata_not_foundinvalid_keyscan_fallback_disabledcollection_too_large 和兜底 internal_error。配置或 fields 请求不符合约束时返回 invalid_request;Store 缺少安全刷新能力时返回 refresh_unavailable。调用方应按 code 分支,message 只用于展示。

HTTP JSON 不输出 error 字段,调用方只按稳定的 code 分支并展示 message。Go 调用方仍可通过顶层和逐项 Error 字段取得原始错误链。

完整接入示例见 example/admin_integration。它为了本地验证提供 HTTP 路由和内存数据源,并具备以下边界:

  • 默认仅监听 127.0.0.1:8080,显式使用 tc: key 前缀和严格前缀校验。
  • JSON 请求体最多 64 KiB,拒绝未知字段和多个 JSON 对象;批量用户 ID 最多 100 个并按顺序去重。
  • HTTP 配置了 header/read/write/idle 超时,日志不输出 Redis 地址、业务 key 或下游原始错误。
  • 示例没有业务鉴权、权限码、MFA、审计和限流契约,/metrics 也没有访问控制;不能直接绑定公网或作为生产服务部署。接入真实项目时必须复用项目现有鉴权和审计中间件。

测试

基础验证:

go test ./... -count=1
go test -race ./... -count=1
go vet ./...

真实 Redis 集成测试:

TABLECACHE_REDIS_SINGLE_ADDR='127.0.0.1:6380' \
TABLECACHE_REDIS_SINGLE_DB='0' \
TABLECACHE_REDIS_CLUSTER_ADDRS='127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003' \
go test -count=1 -run 'TestRedis(Single|Cluster)Integration' -v ./...

可选环境变量:

变量 说明
TABLECACHE_REDIS_SINGLE_ADDR 单节点 Redis 地址。
TABLECACHE_REDIS_SINGLE_PASSWORD 单节点 Redis 密码。
TABLECACHE_REDIS_SINGLE_DB 单节点 Redis DB。
TABLECACHE_REDIS_CLUSTER_ADDRS Cluster 种子节点,逗号分隔。
TABLECACHE_REDIS_CLUSTER_PASSWORD Cluster 密码。
TABLECACHE_REDIS_ADDR_MAP Cluster 返回内网 hostname 时的地址改写,格式 host=ip,host2=ip2

上线检查

  • 所有 Target 的 Index、逻辑 Key 不重复且不重叠,Key / KeyTitle 没有预拼 WithKeyPrefix
  • 生产项目显式配置以冒号结尾、短且不以 tcm: 开头的 WithKeyPrefix;危险前缀会在构造期直接失败。
  • 单节点/哨兵普通前缀可以执行前缀全量刷新 / DeleteByPrefix;Cluster 仅对固定 hash tag 前缀开放,并已评估单 slot 容量与热点。
  • Cluster 普通无固定 hash tag 使用 RefreshByKeys / DeleteByKey,没有尝试用索引或全节点 SCAN 绕过 fail-fast;Ring 已改用受支持拓扑。
  • 允许执行前缀操作的 Target 开启索引;生产默认 WithScanFallback(false),只有受控维护窗口才显式开启 SCAN。
  • 未混跑不同版本;升级或回滚前已停止全部实例,并清理旧缓存 namespace 或切换到新 namespace。
  • 自定义 Store 按使用能力实现 MarkerReplaceStoreHashFieldsStoreFieldsEmptyStorePrefixReplaceStoreGuardedPatternStore,并遵守 marker 状态切换与“先写新快照、后删旧 key”的失败语义;DeleteByPrefix 需要按可信索引走快路径时还要实现 PrefixIndexStore,否则只能通过 GuardedPatternStore 执行带 guard 的 SCAN。需要支持前缀操作时还应在 Loader 前完成等价的拓扑校验。
  • 自定义 Store 的 ApplyMutation 必须先登记新索引、再提交业务状态;在线删除可以保留陈旧索引成员,不能让旧 owner 延迟移除新成员。收到 LockGuard 的可见写删必须在实际变更的同一原子边界内校验 owner;需要构造期校验时实现专用 StoreValidator
  • 自定义 Store 的 AcquireRefreshLock 必须原子返回锁竞争时的当前 owner,避免快 Loader 在抢锁与读取 owner 之间完成所造成的重复回源窗口。
  • 需要前缀 SCAN 对账的 Cluster wrapper 暴露完整 ForEachMaster 能力,并已在真实环境验证所有 master 可达;该能力不放宽同槽限制。
  • 非 full Loader 只返回 Entry.Key == params.Key;只有前缀 full Loader 可以返回同 Target 前缀下的完整快照。
  • 根据单实例数据源预算设置 WithLoaderTimeoutWithLoaderConcurrency
  • 不存在数据的热点 key 开启 AllowEmptyMarker
  • 随机高基数 miss 另有网关限流、业务参数校验或数据源熔断,不能只依赖空值占位。
  • 大集合配置读写上限,并优先使用 ReadPage 做局部读取。
  • 指标、日志和告警至少覆盖 loader_error_totalwait_timeout_totallock_lostprefix_scan_fallback
  • 管理路由已接入业务鉴权、权限、审计和限流;示例路由未直接部署。

以上配置都在 NewManager / NewRedisStore 构造期生效,发布新版本或修改这些 Option 后需要重启进程。不需要 MySQL/业务数据迁移、回填或补偿;但本版本取消旧缓存兼容,升级和回滚都必须清理旧缓存 namespace,并仅对拓扑允许的前缀 Target 执行一次全量刷新建立可信 ready。Cluster 普通无固定 hash tag 继续使用逐 key API;Ring 必须先迁移到受支持拓扑。关闭索引后再次开启时,同样只对允许执行前缀操作的 Target 重建可信 ready。

Documentation

Index

Constants

View Source
const (
	// AdminCodeOK 表示管理页操作执行成功。
	AdminCodeOK = "ok"
	// AdminCodePartialFailure 表示批量操作中存在失败项。
	AdminCodePartialFailure = "partial_failure"
	// AdminCodeInvalidRequest 表示请求或配置不符合当前缓存操作约束。
	AdminCodeInvalidRequest = "invalid_request"
	// AdminCodeTargetNotFound 表示请求的缓存目标未注册。
	AdminCodeTargetNotFound = "target_not_found"
	// AdminCodeLoaderRequired 表示缓存目标缺少回源加载器。
	AdminCodeLoaderRequired = "loader_required"
	// AdminCodeWaitTimeout 表示等待缓存重建超时。
	AdminCodeWaitTimeout = "wait_timeout"
	// AdminCodeRefreshUnavailable 表示当前刷新结果不可继续使用。
	AdminCodeRefreshUnavailable = "refresh_unavailable"
	// AdminCodeCacheMiss 表示缓存最终仍未命中。
	AdminCodeCacheMiss = "cache_miss"
	// AdminCodeDataNotFound 表示源数据不存在。
	AdminCodeDataNotFound = "data_not_found"
	// AdminCodeInvalidKey 表示缓存 key 或前缀不符合约束。
	AdminCodeInvalidKey = "invalid_key"
	// AdminCodeScanDisabled 表示当前禁止前缀删除降级扫描。
	AdminCodeScanDisabled = "scan_fallback_disabled"
	// AdminCodeCollectionTooLarge 表示缓存集合超过安全上限。
	AdminCodeCollectionTooLarge = "collection_too_large"
	// AdminCodeInternalError 表示未公开内部细节的执行错误。
	AdminCodeInternalError = "internal_error"
)
View Source
const (
	// DefaultEmptyMarker 表示空值缓存占位符,用于缓存穿透保护。
	DefaultEmptyMarker = "__empty__"
)

Variables

View Source
var (
	// ErrTargetNotFound 表示没有找到匹配的缓存目标配置。
	ErrTargetNotFound = errors.New("tablecache target not found")
	// ErrLoaderRequired 表示缓存目标缺少数据加载函数。
	ErrLoaderRequired = errors.New("tablecache loader required")
	// ErrWaitRebuildTimeout 表示等待其它实例重建缓存超时。
	ErrWaitRebuildTimeout = errors.New("tablecache wait rebuild timeout")
	// ErrRefreshLockLost 表示当前实例在刷新过程中失去重建锁所有权。
	ErrRefreshLockLost = errors.New("tablecache refresh lock lost")
	// ErrCacheMiss 表示缓存未命中。
	ErrCacheMiss = errors.New("tablecache cache miss")
	// ErrNotFound 表示加载器确认源数据不存在,可触发空值占位。
	ErrNotFound = errors.New("tablecache data not found")
	// ErrKeyPrefixRequired 表示刷新、删除或写回操作必须使用已带 Manager 指定前缀的实际 Redis key。
	ErrKeyPrefixRequired = errors.New("tablecache key prefix required")
	// ErrInvalidClusterHashTag 表示 key 中的花括号无法安全生成 Redis Cluster 同槽元信息 key。
	ErrInvalidClusterHashTag = errors.New("tablecache invalid redis cluster hash tag key")
	// ErrDistributedPrefixHashTagRequired 表示分布式 Redis 的前缀全量写删缺少固定 hash tag。
	ErrDistributedPrefixHashTagRequired = errors.New("tablecache distributed prefix hash tag required")
	// ErrEntryKeyOutOfScope 表示加载器返回了不属于当前缓存目标管理范围的写入 key。
	ErrEntryKeyOutOfScope = errors.New("tablecache entry key out of target scope")
	// ErrRefreshInvalidated 表示刷新期间发生显式删除,当前刷新结果已失效。
	ErrRefreshInvalidated = errors.New("tablecache refresh invalidated")
	// ErrScanFallbackDisabled 表示 DeleteByPrefix 需要降级 SCAN,但当前配置禁止降级。
	ErrScanFallbackDisabled = errors.New("tablecache scan fallback disabled")
	// ErrCollectionTooLarge 表示集合读写超过配置上限。
	ErrCollectionTooLarge = errors.New("tablecache collection too large")
	// ErrInvalidKeyPrefix 表示 key 前缀不符合生产安全配置。
	ErrInvalidKeyPrefix = errors.New("tablecache invalid key prefix")
	// ErrInvalidConfig 表示 Manager 或 Target 配置存在不安全取值。
	ErrInvalidConfig = errors.New("tablecache invalid config")
	// ErrPartialHashUnsupported 表示当前 Store 或目标配置不支持安全的 Hash 局部刷新。
	ErrPartialHashUnsupported = errors.New("tablecache partial hash unsupported")
	// ErrPrefixReplaceUnsupported 表示 Store 不支持无破坏的前缀全量替换。
	ErrPrefixReplaceUnsupported = errors.New("tablecache prefix replace unsupported")
	// ErrPrefixDeleteUnsupported 表示 Store 不支持带锁校验的前缀删除。
	ErrPrefixDeleteUnsupported = errors.New("tablecache prefix delete unsupported")
	// ErrRedisTopologyUnsupported 表示当前 Redis 客户端拓扑不能安全满足 table-cache 一致性契约。
	ErrRedisTopologyUnsupported = errors.New("tablecache redis topology unsupported")
	// ErrMarkerReplaceUnsupported 表示 Store 不支持 marker 与旧缓存的安全切换。
	ErrMarkerReplaceUnsupported = errors.New("tablecache marker replace unsupported")
)
View Source
var ErrPrefixIndexUntrusted = errors.New("tablecache prefix index untrusted")

ErrPrefixIndexUntrusted 表示前缀索引完整性证据缺失,调用方必须撤销 ready 并降级全节点 SCAN。

Functions

func Bool

func Bool(value bool) *bool

Bool 返回布尔指针,便于 Entry.Overwrite 显式设置 false。

func EscapeRedisGlobLiteral added in v1.22.2

func EscapeRedisGlobLiteral(value string) string

EscapeRedisGlobLiteral 转义 Redis glob 元字符,避免业务前缀被解释成通配表达式。

func RedisPrefixPattern added in v1.22.2

func RedisPrefixPattern(prefix string) string

RedisPrefixPattern 把 Redis key 前缀转换成只匹配该字面前缀的 glob pattern。

Types

type CacheType

type CacheType string

CacheType 表示 Redis 目标数据结构类型。

const (
	// TypeString 表示 Redis String 缓存类型。
	TypeString CacheType = "string"
	// TypeHash 表示 Redis Hash 缓存类型。
	TypeHash CacheType = "hash"
	// TypeList 表示 Redis List 缓存类型。
	TypeList CacheType = "list"
	// TypeSet 表示 Redis Set 缓存类型。
	TypeSet CacheType = "set"
	// TypeZSet 表示 Redis ZSet 缓存类型。
	TypeZSet CacheType = "zset"
)

type CollectionPageStore

type CollectionPageStore interface {
	// ReadPage 按缓存类型分页读取 Redis 原始值。
	ReadPage(ctx context.Context, key string, typ CacheType, options ReadPageOptions) (ReadPageResult, error)
}

CollectionPageStore 表示可选的集合分页读取能力。 RedisStore 默认实现该接口;业务可用它替代 HGetAll/LRange 0 -1 等全量读取。

type Decoder

type Decoder func(data []byte, dest any) error

Decoder 定义缓存读取后的反序列化函数,默认使用 encoding/json。

type Encoder

type Encoder func(value any) (string, error)

Encoder 定义复杂缓存值的序列化函数,默认使用 encoding/json。

type Entry

type Entry struct {
	Key       string        // Key 是最终写入的 Redis key
	Type      CacheType     // Type 是最终写入的 Redis 数据结构类型
	Value     any           // Value 是写入值,类型由 Type 决定
	TTL       time.Duration // TTL 是当前 key 的基础过期时间
	Jitter    time.Duration // Jitter 是当前 key 的过期时间抖动范围
	Overwrite *bool         // Overwrite 控制是否覆盖旧值;nil 默认覆盖,String/List 不支持 false
}

Entry 表示一次写入 Redis 的标准缓存数据。

type ExtendedMetrics

type ExtendedMetrics interface {
	Metrics
	// RecordLoaderError 记录加载器回源错误次数与错误信息。
	RecordLoaderError(ctx context.Context, index string, err error)
	// RecordEmptyMarkerWrite 记录空值占位写入次数。
	RecordEmptyMarkerWrite(ctx context.Context, index string)
	// RecordWaitTimeout 记录等待其它实例重建超时次数。
	RecordWaitTimeout(ctx context.Context, index string)
	// RecordPrefixWait 记录前缀全量刷新阻塞单 key 刷新的次数。
	RecordPrefixWait(ctx context.Context, index string)
	// RecordPrefixRetry 记录单 key 刷新因前缀全量刷新而重试的次数。
	RecordPrefixRetry(ctx context.Context, index string)
	// RecordPrefixDelete 记录前缀删除次数与删除 key 数量。
	RecordPrefixDelete(ctx context.Context, index string, prefix string, count int64)
	// RecordRefreshEntryCount 记录单次刷新写入条数。
	RecordRefreshEntryCount(ctx context.Context, index string, count int)
}

ExtendedMetrics 定义可选的细分指标接口;实现后 Manager 会自动记录更丰富的生产排障指标。

type FieldsEmptyStore added in v1.22.2

type FieldsEmptyStore interface {
	// ReplaceFieldsWithEmpty 删除请求字段并按独立 TTL 登记字段组合为空。
	ReplaceFieldsWithEmpty(ctx context.Context, guards []LockGuard, key string, registryKey string, fieldsID string, fields []string, ttl time.Duration) error
	// HasFieldsEmpty 判断字段组合是否仍在有效期内。
	HasFieldsEmpty(ctx context.Context, registryKey string, fieldsID string) (bool, error)
}

FieldsEmptyStore 定义 Hash 字段组合空值的有界 registry 能力。

type GuardedPatternStore added in v1.22.2

type GuardedPatternStore interface {
	// DeletePatternGuarded 仅在全部 guard 仍归当前请求持有时删除每批匹配 key。
	DeletePatternGuarded(ctx context.Context, pattern string, count int64, guards []LockGuard) (int64, error)
}

GuardedPatternStore 定义带锁 owner 原子校验的 SCAN 删除能力。

type HashFieldsStore added in v1.22.2

type HashFieldsStore interface {
	// DeleteHashFields 仅在全部 guard 仍归当前请求持有时删除指定 Hash 字段,并清除该 Hash 的字段空值 registry。
	DeleteHashFields(ctx context.Context, guards []LockGuard, key string, registryKey string, fields []string) error
}

HashFieldsStore 定义带锁删除部分 Hash 字段的能力。 RedisStore 默认实现该接口;fields 回源为空时必须删除请求范围内的旧值,不能把过期字段继续当成命中。

type Item

type Item struct {
	Index    string `json:"index"`    // Index 是缓存目标索引
	Title    string `json:"title"`    // Title 是缓存目标展示名称
	Key      string `json:"key"`      // Key 是注册后的固定 Redis key 或 Redis key 前缀
	KeyTitle string `json:"keyTitle"` // KeyTitle 是 Redis key 展示模板
	Type     string `json:"type"`     // Type 是 Redis 数据类型
	Remark   string `json:"remark"`   // Remark 是缓存说明
}

Item 表示缓存管理页可展示的缓存目标。

type LoadParams

type LoadParams struct {
	Target   Target   // Target 是当前命中的缓存目标配置
	Key      string   // Key 是本次请求刷新或读取的 Redis key
	Index    string   // Index 是缓存目标索引
	KeyParts []string // KeyParts 是去掉目标前缀后的 key 片段
	Fields   []string // Fields 是 Hash 等二级索引字段,用于局部刷新
}

LoadParams 表示缓存目标加载时的上下文参数。

type LoadThroughBatchAdminItem

type LoadThroughBatchAdminItem struct {
	Key       string      `json:"key"`       // Key 是当前批量项的缓存 key
	Success   bool        `json:"success"`   // Success 表示当前批量项是否执行成功
	Code      string      `json:"code"`      // Code 是稳定且不包含内部细节的结果码
	Message   string      `json:"message"`   // Message 是可安全展示的结果文案
	State     LookupState `json:"state"`     // State 是当前批量项最终命中状态
	Refreshed bool        `json:"refreshed"` // Refreshed 表示当前批量项是否参与了执行、等待或复用刷新结果
	Error     error       `json:"-"`         // Error 保留原始错误,供调用方在受控日志中使用
}

LoadThroughBatchAdminItem 表示管理页可直接返回的单条批量读穿结果。

type LoadThroughBatchAdminResponse

type LoadThroughBatchAdminResponse struct {
	Success bool                        `json:"success"` // Success 表示整批是否全部成功
	Code    string                      `json:"code"`    // Code 是稳定且不包含内部细节的结果码
	Message string                      `json:"message"` // Message 是面向管理页展示的安全文案
	Error   error                       `json:"-"`       // Error 保留整批聚合错误,供调用方在受控日志中使用
	Summary LoadThroughBatchSummary     `json:"summary"` // Summary 是当前批量结果的汇总统计
	Items   []LoadThroughBatchAdminItem `json:"items"`   // Items 是当前批量每一项的明细结果
}

LoadThroughBatchAdminResponse 表示管理页批量读穿接口可直接返回的标准 JSON 结构。

func BuildLoadThroughBatchAdminResponse

func BuildLoadThroughBatchAdminResponse(results []LoadThroughBatchResult) LoadThroughBatchAdminResponse

BuildLoadThroughBatchAdminResponse 根据批量结果构建管理页标准响应结构。

func BuildLoadThroughBatchAdminResponseWithSummary

func BuildLoadThroughBatchAdminResponseWithSummary(results []LoadThroughBatchResult, summary LoadThroughBatchSummary, err error) LoadThroughBatchAdminResponse

BuildLoadThroughBatchAdminResponseWithSummary 根据批量结果、汇总信息和聚合错误构建管理页标准响应结构。

type LoadThroughBatchError

type LoadThroughBatchError struct {
	Summary LoadThroughBatchSummary // Summary 是当前批量结果的汇总信息
}

LoadThroughBatchError 表示批量读穿存在失败项的聚合错误。

func (*LoadThroughBatchError) Error

func (e *LoadThroughBatchError) Error() string

Error 返回批量读穿聚合错误描述。

type LoadThroughBatchOptions

type LoadThroughBatchOptions struct {
	Concurrency    int                // Concurrency 是本批次读穿的并发度,0 表示沿用 Manager 默认配置,有效范围为0到256
	DefaultOptions LoadThroughOptions // DefaultOptions 是本批次所有条目的默认读穿参数,条目级 Options 优先级更高
}

LoadThroughBatchOptions 表示一批读穿请求的批次级配置。

type LoadThroughBatchResult

type LoadThroughBatchResult struct {
	Key          string       `json:"key"`          // Key 是当前批量项的缓存 key
	LookupResult LookupResult `json:"lookupResult"` // LookupResult 是当前批量项的读取结果
	Error        error        `json:"-"`            // Error 是当前批量项的执行错误
}

LoadThroughBatchResult 表示单条批量读穿请求的执行结果。

type LoadThroughBatchSummary

type LoadThroughBatchSummary struct {
	Total      int      `json:"total"`      // Total 是批量请求总数
	Success    int      `json:"success"`    // Success 是执行成功的条数
	Failed     int      `json:"failed"`     // Failed 是执行失败的条数
	Hit        int      `json:"hit"`        // Hit 是最终命中缓存数据的条数
	Miss       int      `json:"miss"`       // Miss 是最终仍未命中的条数
	Empty      int      `json:"empty"`      // Empty 是命中空值占位的条数
	Refreshed  int      `json:"refreshed"`  // Refreshed 是批次中参与刷新流程的条数
	FailedKeys []string `json:"failedKeys"` // FailedKeys 是执行失败的 key 列表
}

LoadThroughBatchSummary 表示一批读穿请求的汇总结果。

func SummarizeLoadThroughBatchResults

func SummarizeLoadThroughBatchResults(results []LoadThroughBatchResult) LoadThroughBatchSummary

SummarizeLoadThroughBatchResults 汇总批量读穿结果,便于任务调度和批处理统一判断。

func (LoadThroughBatchSummary) HasError

func (s LoadThroughBatchSummary) HasError() bool

HasError 返回当前批量汇总是否包含失败项。

type LoadThroughItem

type LoadThroughItem struct {
	Key     string             // Key 是本次批量读穿的目标缓存 key
	Dest    any                // Dest 是当前 key 的反序列化目标对象
	Options LoadThroughOptions // Options 是当前 key 的读穿可选参数
}

LoadThroughItem 表示一条批量读穿请求。

type LoadThroughOptions

type LoadThroughOptions struct {
	Fields           []string              // Fields 是本次读穿时透传给 Loader 的字段列表,适用于 Hash 等局部刷新场景
	Loader           Loader                // Loader 是本次调用临时覆盖的回源加载器,nil 表示继续使用 Target.Loader
	LoaderTimeout    time.Duration         // LoaderTimeout 是本次读穿回源超时时间,优先级高于 Target.LoaderTimeout
	AllowEmptyMarker *bool                 // AllowEmptyMarker 控制本次 miss 回源是否允许写入空值占位,nil 表示沿用目标配置
	ContextPolicy    *RebuildContextPolicy // ContextPolicy 控制本次读穿是否忽略调用方取消信号,nil 表示沿用管理器配置
}

LoadThroughOptions 表示单次读穿缓存调用的可选参数。

type Loader

type Loader func(ctx context.Context, params LoadParams) ([]Entry, error)

Loader 表示缓存目标的数据加载函数,由业务项目自行适配数据库、RPC 或其它数据源。

type LockGuard added in v1.22.2

type LockGuard struct {
	Key   string // Key 是刷新锁 Redis key
	Owner string // Owner 是抢锁前生成且仅当前请求持有的随机标识
}

LockGuard 表示一次 Redis 提交必须仍持有的分布式锁 owner。

type Logger

type Logger interface {
	// Infof 输出信息日志。
	Infof(format string, args ...any)
	// Warnf 输出警告日志。
	Warnf(format string, args ...any)
}

Logger 定义可选的 printf 风格日志接口。 go-utils.Logger 应通过 WithGoUtilsLogger 接入。

type LookupMetrics

type LookupMetrics interface {
	Metrics
	// RecordLookupState 记录读取最终状态(hit/miss/empty)。
	RecordLookupState(ctx context.Context, index string, state LookupState)
	// RecordLookupRefreshTriggered 记录 GetOrRefresh/LoadThrough 在 miss 后触发回源刷新的次数。
	RecordLookupRefreshTriggered(ctx context.Context, index string)
}

LookupMetrics 定义读取链路细分指标接口,用于区分 hit/miss/empty 与读穿刷新触发次数。

type LookupResult

type LookupResult struct {
	State     LookupState `json:"state"`     // State 是本次读取最终状态
	Refreshed bool        `json:"refreshed"` // Refreshed 表示本次 miss 是否参与了刷新流程,包括执行、等待或复用同一轮结果
}

LookupResult 表示一次缓存读取或“读取后按需刷新”的结果。

type LookupState

type LookupState string

LookupState 表示缓存读取状态。

const (
	// LookupStateHit 表示缓存命中且已成功写入目标对象。
	LookupStateHit LookupState = "hit"
	// LookupStateMiss 表示缓存未命中,且当前没有空值占位。
	LookupStateMiss LookupState = "miss"
	// LookupStateEmpty 表示缓存已确认源数据为空,命中了空值占位。
	LookupStateEmpty LookupState = "empty"
)

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager 管理一组表数据缓存目标,负责刷新、锁保护、TTL 抖动与空值占位。

func NewManager

func NewManager(store Store, targets []Target, opts ...Option) (*Manager, error)

NewManager 创建通用表缓存管理器。

func (*Manager) DeleteByKey

func (m *Manager) DeleteByKey(ctx context.Context, key string) error

DeleteByKey 删除指定 Redis key;前缀删除请使用 DeleteByPrefix。

func (*Manager) DeleteByPrefix

func (m *Manager) DeleteByPrefix(ctx context.Context, prefix string) error

DeleteByPrefix 删除指定 Redis key 前缀下的所有缓存。

func (*Manager) Get

func (m *Manager) Get(ctx context.Context, key string, dest any) (bool, error)

Get 从缓存读取指定 key,并把缓存值反序列化到 dest。

func (*Manager) GetOrRefresh

func (m *Manager) GetOrRefresh(ctx context.Context, key string, dest any) (LookupResult, error)

GetOrRefresh 先读取缓存;仅当真实未命中时触发刷新,命中空值占位时直接返回 empty。

func (*Manager) GetOrRefreshWithLoader

func (m *Manager) GetOrRefreshWithLoader(ctx context.Context, key string, dest any, loader Loader) (LookupResult, error)

GetOrRefreshWithLoader 先读取缓存;miss 时使用本次传入的 Loader 回源、回填并返回最新结果。

func (*Manager) GetOrRefreshWithOptions

func (m *Manager) GetOrRefreshWithOptions(ctx context.Context, key string, dest any, options LoadThroughOptions) (LookupResult, error)

GetOrRefreshWithOptions 先读取缓存;miss 时按本次 options 配置执行回源、回填并返回最新结果。

func (*Manager) GetState

func (m *Manager) GetState(ctx context.Context, key string, dest any) (LookupResult, error)

GetState 从缓存读取指定 key,并返回命中、空值占位或未命中的明确状态。

func (*Manager) IsFixedKey

func (m *Manager) IsFixedKey(key string) bool

IsFixedKey 判断 key 是否为固定内置缓存 key,模板和前缀型 key 不纳入固定 key。

func (*Manager) Items

func (m *Manager) Items() []Item

Items 返回缓存管理页展示的目标列表。

func (*Manager) LoadThrough

func (m *Manager) LoadThrough(ctx context.Context, key string, dest any, loader Loader) (LookupResult, error)

LoadThrough 提供更贴近业务侧语义的读穿缓存入口,内部复用 GetOrRefreshWithLoader。

func (*Manager) LoadThroughBatch

func (m *Manager) LoadThroughBatch(ctx context.Context, items []LoadThroughItem) []LoadThroughBatchResult

LoadThroughBatch 批量执行读穿缓存;每个条目独立返回结果,单条失败不会中断整批处理。

func (*Manager) LoadThroughBatchWithBatchOptions

func (m *Manager) LoadThroughBatchWithBatchOptions(ctx context.Context, items []LoadThroughItem, options LoadThroughBatchOptions) []LoadThroughBatchResult

LoadThroughBatchWithBatchOptions 批量执行读穿缓存,并支持批次级默认参数和并发度覆盖。

func (*Manager) LoadThroughBatchWithSummary

func (m *Manager) LoadThroughBatchWithSummary(ctx context.Context, items []LoadThroughItem) ([]LoadThroughBatchResult, LoadThroughBatchSummary, error)

LoadThroughBatchWithSummary 批量执行读穿缓存,并返回汇总信息与聚合错误,便于任务调度快速判定整批状态。

func (*Manager) LoadThroughBatchWithSummaryOptions

func (m *Manager) LoadThroughBatchWithSummaryOptions(ctx context.Context, items []LoadThroughItem, options LoadThroughBatchOptions) ([]LoadThroughBatchResult, LoadThroughBatchSummary, error)

LoadThroughBatchWithSummaryOptions 批量执行读穿缓存,并支持批次级默认参数、并发覆盖和汇总结果返回。

func (*Manager) LoadThroughWithOptions

func (m *Manager) LoadThroughWithOptions(ctx context.Context, key string, dest any, options LoadThroughOptions) (LookupResult, error)

LoadThroughWithOptions 提供带可选参数的完整读穿缓存入口,适用于字段级局部刷新和临时覆盖 Loader。

func (*Manager) RefreshAll

func (m *Manager) RefreshAll(ctx context.Context) error

RefreshAll 刷新全部允许批量重建的缓存目标。

func (*Manager) RefreshAllDetailed

func (m *Manager) RefreshAllDetailed(ctx context.Context) []RefreshBatchResult

RefreshAllDetailed 刷新全部允许批量重建的缓存目标,并逐项返回执行结果。

func (*Manager) RefreshAllWithSummary

func (m *Manager) RefreshAllWithSummary(ctx context.Context) ([]RefreshBatchResult, RefreshBatchSummary, error)

RefreshAllWithSummary 刷新全部允许批量重建的缓存目标,并返回汇总信息与聚合错误。

func (*Manager) RefreshByKey

func (m *Manager) RefreshByKey(ctx context.Context, key string, fields ...string) error

RefreshByKey 根据 Redis key 刷新匹配的缓存目标。

func (*Manager) RefreshByKeys

func (m *Manager) RefreshByKeys(ctx context.Context, keys []string) error

RefreshByKeys 批量刷新多个缓存 key;同 key 会自动去重。

func (*Manager) RefreshByKeysDetailed

func (m *Manager) RefreshByKeysDetailed(ctx context.Context, keys []string) []RefreshBatchResult

RefreshByKeysDetailed 批量刷新多个缓存 key,并逐项返回执行结果。

func (*Manager) RefreshByKeysWithSummary

func (m *Manager) RefreshByKeysWithSummary(ctx context.Context, keys []string) ([]RefreshBatchResult, RefreshBatchSummary, error)

RefreshByKeysWithSummary 批量刷新多个缓存 key,并返回汇总信息与聚合错误。

type MarkerReplaceStore added in v1.22.2

type MarkerReplaceStore interface {
	// ReplaceWithMarker 先写入 marker,成功后再删除同槽旧 key。
	ReplaceWithMarker(ctx context.Context, guards []LockGuard, marker Entry, deleteKeys ...string) error
}

MarkerReplaceStore 定义 String marker 与旧缓存的一致切换能力。

type Metrics

type Metrics interface {
	// RecordRefresh 记录一次刷新执行的结果与耗时。
	RecordRefresh(ctx context.Context, index string, result string, duration time.Duration)
	// RecordCacheHit 记录一次缓存命中次数。
	RecordCacheHit(ctx context.Context, index string)
	// RecordCacheMiss 记录一次缓存未命中次数。
	RecordCacheMiss(ctx context.Context, index string)
	// RecordLockFailed 记录一次分布式锁竞争失败次数。
	RecordLockFailed(ctx context.Context, index string)
}

Metrics 定义 tablecache 运行指标记录接口,可由 Prometheus、StatsD 或自定义埋点实现。

type Option

type Option func(*Manager)

Option 表示 Manager 的可选配置。

func WithDecoder

func WithDecoder(decoder Decoder) Option

WithDecoder 设置缓存读取反序列化函数。

func WithEmptyMarker

func WithEmptyMarker(marker string, ttl time.Duration) Option

WithEmptyMarker 设置空值缓存占位内容和默认过期时间。

func WithGoUtilsLogger

func WithGoUtilsLogger(logger utils.Logger) Option

WithGoUtilsLogger 设置 go-utils.Logger 日志适配器。 推荐在项目已统一使用 utils.Configure(utils.WithLogger(...)) 时直接传入 utils.Log()。

func WithKeyPrefix

func WithKeyPrefix(prefix string) Option

WithKeyPrefix 设置业务缓存 key 命名空间前缀,用于把 tablecache 管理的业务数据与其它 Redis key 隔离。 默认前缀为 "tc:";配置必须以冒号结尾,刷新、删除和写回只接受已带该前缀的实际 Redis key。

func WithLoaderConcurrency added in v1.22.2

func WithLoaderConcurrency(concurrency int) Option

WithLoaderConcurrency 设置单个 Manager 同时执行的 Loader 数量。

func WithLoaderTimeout

func WithLoaderTimeout(timeout time.Duration) Option

WithLoaderTimeout 设置默认 Loader 超时时间。

func WithLockRenewInterval

func WithLockRenewInterval(interval time.Duration) Option

WithLockRenewInterval 设置缓存重建锁续期间隔。

func WithLockTTL

func WithLockTTL(ttl time.Duration) Option

WithLockTTL 设置缓存重建锁持有时间。

func WithLogKeyRedaction

func WithLogKeyRedaction(enabled bool) Option

WithLogKeyRedaction 设置事件日志中 key/prefix/lock_name/err 等可能携带业务 key 的字段是否只输出摘要,默认开启。

func WithLogger

func WithLogger(logger Logger) Option

WithLogger 设置缓存管理器日志适配器。

func WithMetrics

func WithMetrics(metrics Metrics) Option

WithMetrics 设置缓存运行指标记录器。

func WithPrefixDeleteConcurrency

func WithPrefixDeleteConcurrency(concurrency int) Option

WithPrefixDeleteConcurrency 设置 DeleteByPrefix 同时扫描删除的 pattern 数。 默认 1 表示保守串行;大 keyspace 且可接受更高 Redis 瞬时压力时可提高到 2~4 来缩短清理耗时。

func WithPrefixEpochTTL

func WithPrefixEpochTTL(ttl time.Duration) Option

WithPrefixEpochTTL 设置前缀全量刷新代际元信息保留时间。

func WithPrefixKeyIndex

func WithPrefixKeyIndex(enabled bool) Option

WithPrefixKeyIndex 设置是否启用前缀 key 索引。 启用后 Manager 会在前缀目标写入时维护索引,并在 DeleteByPrefix 时优先按索引删除;降级 SCAN 仍要求 Store 实现 GuardedPatternStore。

func WithPrefixKeyIndexTTL

func WithPrefixKeyIndexTTL(ttl time.Duration) Option

WithPrefixKeyIndexTTL 设置前缀 key 索引与可信标记的保留时间。 TTL 过短会让删除更容易降级到 SCAN;TTL 过长会保留更多可能已过期的成员,建议按业务缓存最长 TTL 配置。

func WithRebuildContextPolicy

func WithRebuildContextPolicy(policy RebuildContextPolicy) Option

WithRebuildContextPolicy 设置缓存重建上下文取消策略。

func WithRebuildResultTTL

func WithRebuildResultTTL(ttl time.Duration) Option

WithRebuildResultTTL 设置重建完成元信息保留时间。

func WithRefreshConcurrency

func WithRefreshConcurrency(concurrency int) Option

WithRefreshConcurrency 设置 RefreshAll 和 RefreshByKeys 的有限并发度。

func WithScanCount

func WithScanCount(count int64) Option

WithScanCount 设置前缀缓存清理时的 Redis SCAN count。

func WithScanFallback

func WithScanFallback(enabled bool) Option

WithScanFallback 设置 DeleteByPrefix 在前缀索引不可用时是否允许降级 SCAN。 默认关闭;仅在受控维护窗口显式开启,让线上调用优先建立可信索引或转后台任务。

func WithWait

func WithWait(step time.Duration, times int) Option

WithWait 设置未抢到锁时等待其它实例重建缓存的轮询策略。

type PipelineExecError

type PipelineExecError struct {
	Operation  string   // Operation 表示本次 Pipeline 执行的操作名称(用于日志与排障归类)
	FailedKeys []string // FailedKeys 表示本次 Pipeline 中检测到失败的 key 列表(已排序去重)
	Cause      error    // Cause 是底层错误原因
}

PipelineExecError 表示 Pipeline 执行失败的增强错误信息。 在部分命令失败(例如 cluster 路由抖动、网络短暂错误)时可携带失败 key 列表,便于线上快速定位与重试。

func (*PipelineExecError) Error

func (e *PipelineExecError) Error() string

Error 返回稳定的 Pipeline 失败摘要,避免日志输出过长 key 列表。

func (*PipelineExecError) Unwrap

func (e *PipelineExecError) Unwrap() error

Unwrap 返回底层错误,便于 errors.Is 和 errors.As 继续匹配。

type PrefixIndexMutation

type PrefixIndexMutation struct {
	IndexKey string        // IndexKey 是前缀目标对应的索引集合 Redis key
	TTL      time.Duration // TTL 是安全超集索引加入成员时刷新的有效保留时间,由 Store 校验
	Keys     []string      // Keys 是需要加入索引集合的真实 Redis key 成员列表
}

PrefixIndexMutation 描述一次前缀索引集合的成员变更。

type PrefixIndexStore

type PrefixIndexStore interface {
	// DeletePrefixIndexKeys 分批遍历安全超集索引并删除真实 Redis key,索引成员在线保留。
	DeletePrefixIndexKeys(ctx context.Context, indexKey string, count int64, guards []LockGuard) (int64, error)
}

PrefixIndexStore 定义按前缀安全超集索引删除的能力,用于大 keyspace 下绕开全库 SCAN。 RedisStore 默认实现该接口;自定义 Store 未实现时,Manager 仅可通过 GuardedPatternStore 执行带锁 guard 的 SCAN 降级。

type PrefixMutationTopologyStore added in v1.22.2

type PrefixMutationTopologyStore interface {
	// AllowsPrefixMutation 表示当前部署能否安全执行该前缀的全量写删与索引维护。
	AllowsPrefixMutation(prefix string) bool
}

PrefixMutationTopologyStore 暴露无需网络探测的前缀原子提交拓扑能力。

type PrefixMutationValidator added in v1.22.2

type PrefixMutationValidator interface {
	// ValidatePrefixMutation 拒绝无法与前缀锁原子提交的分布式跨槽前缀。
	ValidatePrefixMutation(ctx context.Context, prefix string) error
}

PrefixMutationValidator 在回源前校验前缀全量写删能否安全执行。

type PrefixReplaceMutation added in v1.22.2

type PrefixReplaceMutation struct {
	Guards         []LockGuard   // Guards 是每批真实写删必须原子校验的锁 owner
	Prefix         string        // Prefix 是全量替换的业务前缀,用于校验分布式 Redis 的同槽约束
	Entries        []Entry       // Entries 是本次快照需要写入的业务或元信息条目
	KeepKeys       []string      // KeepKeys 是替换成功后必须保留的真实 Redis key,通常覆盖 Entries 及本轮保留元信息
	DeletePatterns []string      // DeletePatterns 是旧索引不可信时用于枚举旧 key 的已转义 Redis glob pattern
	IndexKey       string        // IndexKey 是前缀目标的索引 manifest key
	ReadyKey       string        // ReadyKey 是当前索引可信标记,只用于选择索引或 SCAN 枚举路径
	IndexTTL       time.Duration // IndexTTL 是索引可信窗口,分片成员会保留更长的安全窗口
	ScanCount      int64         // ScanCount 是索引或 keyspace 分页枚举的单批建议数量
}

PrefixReplaceMutation 描述一次前缀全量快照替换。

type PrefixReplaceStore added in v1.22.2

type PrefixReplaceStore interface {
	// ReplacePrefix 写入当前快照并删除旧快照中的过期 key,返回实际删除数量。
	ReplacePrefix(ctx context.Context, mutation PrefixReplaceMutation) (int64, error)
}

PrefixReplaceStore 定义前缀目标的安全全量替换能力。 实现必须先完整校验并写入新数据,再删除不在 KeepKeys 中的旧数据;失败时允许保留冗余数据,但不能先清空旧前缀。

type PrometheusMetrics

type PrometheusMetrics struct {
	// contains filtered or unexported fields
}

PrometheusMetrics 提供 Metrics、ExtendedMetrics、LookupMetrics 的 Prometheus 实现。

func NewPrometheusMetrics

func NewPrometheusMetrics(opts ...PrometheusMetricsOption) (*PrometheusMetrics, error)

NewPrometheusMetrics 创建 Prometheus 指标适配器,默认兼容重复注册场景。

func (*PrometheusMetrics) RecordCacheHit

func (m *PrometheusMetrics) RecordCacheHit(ctx context.Context, index string)

RecordCacheHit 记录基础缓存命中次数。

func (*PrometheusMetrics) RecordCacheMiss

func (m *PrometheusMetrics) RecordCacheMiss(ctx context.Context, index string)

RecordCacheMiss 记录基础缓存未命中次数。

func (*PrometheusMetrics) RecordEmptyMarkerWrite

func (m *PrometheusMetrics) RecordEmptyMarkerWrite(ctx context.Context, index string)

RecordEmptyMarkerWrite 记录空值占位写入次数。

func (*PrometheusMetrics) RecordLoaderError

func (m *PrometheusMetrics) RecordLoaderError(ctx context.Context, index string, err error)

RecordLoaderError 记录 Loader 错误次数。

func (*PrometheusMetrics) RecordLockFailed

func (m *PrometheusMetrics) RecordLockFailed(ctx context.Context, index string)

RecordLockFailed 记录锁竞争失败次数。

func (*PrometheusMetrics) RecordLookupRefreshTriggered

func (m *PrometheusMetrics) RecordLookupRefreshTriggered(ctx context.Context, index string)

RecordLookupRefreshTriggered 记录读穿触发刷新次数。

func (*PrometheusMetrics) RecordLookupState

func (m *PrometheusMetrics) RecordLookupState(ctx context.Context, index string, state LookupState)

RecordLookupState 记录一次逻辑读取的最终状态。

func (*PrometheusMetrics) RecordPrefixDelete

func (m *PrometheusMetrics) RecordPrefixDelete(ctx context.Context, index string, prefix string, count int64)

RecordPrefixDelete 记录前缀删除次数和实际删除 key 总数。

func (*PrometheusMetrics) RecordPrefixRetry

func (m *PrometheusMetrics) RecordPrefixRetry(ctx context.Context, index string)

RecordPrefixRetry 记录单 key 因前缀全量刷新重试的次数。

func (*PrometheusMetrics) RecordPrefixWait

func (m *PrometheusMetrics) RecordPrefixWait(ctx context.Context, index string)

RecordPrefixWait 记录前缀全量刷新阻塞单 key 的次数。

func (*PrometheusMetrics) RecordRefresh

func (m *PrometheusMetrics) RecordRefresh(ctx context.Context, index string, result string, duration time.Duration)

RecordRefresh 记录刷新次数和刷新耗时。

func (*PrometheusMetrics) RecordRefreshBatch

func (m *PrometheusMetrics) RecordRefreshBatch(ctx context.Context, mode string, result string, total int, success int, failed int)

RecordRefreshBatch 记录批量刷新与全量刷新任务的次数、规模和成功失败条目数。

func (*PrometheusMetrics) RecordRefreshEntryCount

func (m *PrometheusMetrics) RecordRefreshEntryCount(ctx context.Context, index string, count int)

RecordRefreshEntryCount 记录单次刷新写入条数。

func (*PrometheusMetrics) RecordScanFallback

func (m *PrometheusMetrics) RecordScanFallback(ctx context.Context, index string, prefix string)

RecordScanFallback 记录实际执行的前缀删除降级 SCAN 次数。

func (*PrometheusMetrics) RecordWaitTimeout

func (m *PrometheusMetrics) RecordWaitTimeout(ctx context.Context, index string)

RecordWaitTimeout 记录等待重建超时次数。

type PrometheusMetricsConfig

type PrometheusMetricsConfig struct {
	Namespace           string                // Namespace 是 Prometheus 指标命名空间
	Subsystem           string                // Subsystem 是 Prometheus 指标子系统
	Registerer          prometheus.Registerer // Registerer 是指标注册器,nil 时默认使用全局注册器
	RefreshBuckets      []float64             // RefreshBuckets 是刷新耗时直方图桶
	RefreshEntryBuckets []float64             // RefreshEntryBuckets 是单次刷新写入条数直方图桶
}

PrometheusMetricsConfig 表示 Prometheus 指标适配器的构造配置。

type PrometheusMetricsOption

type PrometheusMetricsOption func(*PrometheusMetricsConfig)

PrometheusMetricsOption 表示 Prometheus 指标适配器的可选配置。

func WithPrometheusNamespace

func WithPrometheusNamespace(namespace string) PrometheusMetricsOption

WithPrometheusNamespace 设置 Prometheus 指标命名空间。

func WithPrometheusRefreshBuckets

func WithPrometheusRefreshBuckets(buckets []float64) PrometheusMetricsOption

WithPrometheusRefreshBuckets 设置刷新耗时直方图桶。

func WithPrometheusRefreshEntryBuckets

func WithPrometheusRefreshEntryBuckets(buckets []float64) PrometheusMetricsOption

WithPrometheusRefreshEntryBuckets 设置单次刷新写入条数直方图桶。

func WithPrometheusRegisterer

func WithPrometheusRegisterer(registerer prometheus.Registerer) PrometheusMetricsOption

WithPrometheusRegisterer 设置 Prometheus 指标注册器。

func WithPrometheusSubsystem

func WithPrometheusSubsystem(subsystem string) PrometheusMetricsOption

WithPrometheusSubsystem 设置 Prometheus 指标子系统。

type ReadPageOptions

type ReadPageOptions struct {
	Fields []string // Fields 是 Hash 指定字段读取列表;非空时优先使用 HMGET
	Start  int64    // Start 是 List/ZSet 范围读取的起始下标
	Stop   int64    // Stop 是 List/ZSet 范围读取的结束下标;为 0 时按 Count 或 Store 默认页大小自动计算
	Cursor uint64   // Cursor 是 Hash/Set 游标扫描的起始游标
	Match  string   // Match 是 Hash/Set 游标扫描的匹配表达式
	Count  int64    // Count 是本页建议读取数量;小于等于 0 时使用 Store 默认 SCAN count
}

ReadPageOptions 表示集合类型分页读取配置。

type ReadPageResult

type ReadPageResult struct {
	Value  any    // Value 是当前页 Redis 原始值,类型与 Read 返回值保持一致
	Cursor uint64 // Cursor 是 Hash/Set 下一页游标;0 表示遍历完成
}

ReadPageResult 表示集合类型分页读取结果。

type RebuildContextPolicy

type RebuildContextPolicy int

RebuildContextPolicy 表示缓存重建上下文的取消信号策略。

const (
	// RebuildContextInheritCancel 表示重建上下文继承调用方取消信号。
	RebuildContextInheritCancel RebuildContextPolicy = iota
	// RebuildContextIgnoreCancel 表示重建上下文保留调用方上下文值,但忽略调用方取消信号。
	RebuildContextIgnoreCancel
)

func RebuildPolicy

func RebuildPolicy(value RebuildContextPolicy) *RebuildContextPolicy

RebuildPolicy 返回重建上下文策略指针,便于 LoadThroughOptions 显式设置单次调用策略。

type RedisStore

type RedisStore struct {
	// contains filtered or unexported fields
}

RedisStore 是基于 go-redis 的 Store 适配器,可直接服务 go-zero、Gin、Kratos 等 Go 框架。

func NewRedisStore

func NewRedisStore(client redis.UniversalClient, opts ...RedisStoreOption) *RedisStore

NewRedisStore 创建 go-redis 存储适配器。

func (*RedisStore) AcquireRefreshLock added in v1.22.2

func (s *RedisStore) AcquireRefreshLock(ctx context.Context, key string, value string, ttl time.Duration) (bool, string, error)

AcquireRefreshLock 原子获取刷新锁,失败时在同一脚本内返回当前owner。

func (*RedisStore) AllowsPrefixMutation added in v1.22.2

func (s *RedisStore) AllowsPrefixMutation(prefix string) bool

AllowsPrefixMutation 判断前缀在当前明确拓扑下是否具备原子 guard 条件。

func (*RedisStore) ApplyMutation

func (s *RedisStore) ApplyMutation(ctx context.Context, mutation StoreMutation) error

ApplyMutation 按“索引先加、业务写删原子提交”的故障安全顺序提交变更。

func (*RedisStore) DeleteHashFields added in v1.22.2

func (s *RedisStore) DeleteHashFields(ctx context.Context, guards []LockGuard, key string, registryKey string, fields []string) error

DeleteHashFields 删除本次请求的旧 Hash 字段和字段空值 registry,保留同 key 的其它字段与 TTL。

func (*RedisStore) DeletePatternGuarded added in v1.22.2

func (s *RedisStore) DeletePatternGuarded(ctx context.Context, pattern string, count int64, guards []LockGuard) (int64, error)

DeletePatternGuarded 对每批 SCAN 结果原子校验 owner 后删除。

func (*RedisStore) DeletePrefixIndexKeys

func (s *RedisStore) DeletePrefixIndexKeys(ctx context.Context, indexKey string, count int64, guards []LockGuard) (int64, error)

DeletePrefixIndexKeys 分页删除索引内的真实 key,并返回实际删除数量。

func (*RedisStore) Exists

func (s *RedisStore) Exists(ctx context.Context, key string) (bool, error)

Exists 判断 Redis key 是否存在。

func (*RedisStore) ExistsMulti

func (s *RedisStore) ExistsMulti(ctx context.Context, keys ...string) (map[string]bool, error)

ExistsMulti 批量判断 Redis key 是否存在,返回 map 只包含传入的有效 key。

func (*RedisStore) HasFieldsEmpty added in v1.22.2

func (s *RedisStore) HasFieldsEmpty(ctx context.Context, registryKey string, fieldsID string) (bool, error)

HasFieldsEmpty 判断字段组合空值状态是否仍在独立有效期内。

func (*RedisStore) Read

func (s *RedisStore) Read(ctx context.Context, key string, typ CacheType) (any, error)

Read 按缓存类型读取 Redis 原始值。

func (*RedisStore) ReadPage

func (s *RedisStore) ReadPage(ctx context.Context, key string, typ CacheType, options ReadPageOptions) (ReadPageResult, error)

ReadPage 按缓存类型分页读取 Redis 原始值,避免大集合必须一次性全量读取。

func (*RedisStore) RefreshLock

func (s *RedisStore) RefreshLock(ctx context.Context, key string, value string, ttl time.Duration) (bool, error)

RefreshLock 仅当锁值与持有者标识一致时续期锁。

func (*RedisStore) ReleaseLock

func (s *RedisStore) ReleaseLock(ctx context.Context, key string, value string) (bool, error)

ReleaseLock 仅当锁值与持有者标识一致时释放锁,避免误删其它实例刚抢到的锁。

func (*RedisStore) ReplaceFieldsWithEmpty added in v1.22.2

func (s *RedisStore) ReplaceFieldsWithEmpty(ctx context.Context, guards []LockGuard, key string, registryKey string, fieldsID string, fields []string, ttl time.Duration) error

ReplaceFieldsWithEmpty 删除请求字段,并登记字段组合为空。

func (*RedisStore) ReplacePrefix added in v1.22.2

func (s *RedisStore) ReplacePrefix(ctx context.Context, mutation PrefixReplaceMutation) (int64, error)

ReplacePrefix 安全替换前缀快照;任一步失败时不会先删除旧快照。

func (*RedisStore) ReplaceWithMarker added in v1.22.2

func (s *RedisStore) ReplaceWithMarker(ctx context.Context, guards []LockGuard, marker Entry, deleteKeys ...string) error

ReplaceWithMarker 先写入 String marker,成功后再删除同槽旧缓存。

func (*RedisStore) ValidatePrefixMutation added in v1.22.2

func (s *RedisStore) ValidatePrefixMutation(ctx context.Context, prefix string) error

ValidatePrefixMutation 在 Store 拓扑校验后拒绝 Cluster 普通跨槽前缀。

func (*RedisStore) ValidateTablecacheStore added in v1.22.2

func (s *RedisStore) ValidateTablecacheStore() error

ValidateTablecacheStore 执行 Manager 构造期专用的 RedisStore 校验。

type RedisStoreOption

type RedisStoreOption func(*RedisStore)

RedisStoreOption 表示 RedisStore 可选配置。

func WithDefaultJitterRatio

func WithDefaultJitterRatio(ratio float64) RedisStoreOption

WithDefaultJitterRatio 设置未显式配置 Jitter 时的默认 TTL 抖动比例;0 表示关闭默认抖动。

func WithMaxCollectionReadCount

func WithMaxCollectionReadCount(limit int64) RedisStoreOption

WithMaxCollectionReadCount 设置全量读取 Hash/List/Set/ZSet 前允许的最大成员数;默认5000,0表示显式不限制。

func WithMaxCollectionWriteCount

func WithMaxCollectionWriteCount(limit int) RedisStoreOption

WithMaxCollectionWriteCount 设置单个 Entry 写入集合成员数上限;默认5000,0表示显式不限制。

func WithPipelineRetries

func WithPipelineRetries(retries int) RedisStoreOption

WithPipelineRetries 设置批量删除与覆盖写的瞬时失败重试次数。

func WithRedisEncoder

func WithRedisEncoder(encoder Encoder) RedisStoreOption

WithRedisEncoder 设置 Redis 复杂值序列化函数。

func WithUnlinkChunkSize

func WithUnlinkChunkSize(size int) RedisStoreOption

WithUnlinkChunkSize 设置批量删除时单个 Pipeline 的 UNLINK 命令数量。 较大的 chunk 可减少网络往返,较小的 chunk 可降低单次请求体积和 Redis 侧瞬时压力。

type RefreshBatchAdminItem

type RefreshBatchAdminItem struct {
	Key     string `json:"key"`     // Key 是当前批量项的缓存 key
	Success bool   `json:"success"` // Success 表示当前批量项是否刷新成功
	Code    string `json:"code"`    // Code 是稳定且不包含内部细节的结果码
	Message string `json:"message"` // Message 是可安全展示的结果文案
	Error   error  `json:"-"`       // Error 保留原始错误,供调用方在受控日志中使用
}

RefreshBatchAdminItem 表示管理页可直接返回的单条批量刷新结果。

type RefreshBatchAdminResponse

type RefreshBatchAdminResponse struct {
	Success bool                    `json:"success"` // Success 表示整批是否全部成功
	Code    string                  `json:"code"`    // Code 是稳定且不包含内部细节的结果码
	Message string                  `json:"message"` // Message 是面向管理页展示的安全文案
	Error   error                   `json:"-"`       // Error 保留整批聚合错误,供调用方在受控日志中使用
	Summary RefreshBatchSummary     `json:"summary"` // Summary 是当前批量结果的汇总统计
	Items   []RefreshBatchAdminItem `json:"items"`   // Items 是当前批量每一项的明细结果
}

RefreshBatchAdminResponse 表示管理页批量刷新接口可直接返回的标准 JSON 结构。

func BuildRefreshBatchAdminResponse

func BuildRefreshBatchAdminResponse(results []RefreshBatchResult) RefreshBatchAdminResponse

BuildRefreshBatchAdminResponse 根据批量刷新结果构建管理页标准响应结构。

func BuildRefreshBatchAdminResponseWithSummary

func BuildRefreshBatchAdminResponseWithSummary(results []RefreshBatchResult, summary RefreshBatchSummary, err error) RefreshBatchAdminResponse

BuildRefreshBatchAdminResponseWithSummary 根据批量刷新结果、汇总信息和聚合错误构建管理页标准响应结构。

type RefreshBatchError

type RefreshBatchError struct {
	Summary RefreshBatchSummary // Summary 是当前批量刷新结果的汇总信息
}

RefreshBatchError 表示批量刷新存在失败项的聚合错误。

func (*RefreshBatchError) Error

func (e *RefreshBatchError) Error() string

Error 返回批量刷新聚合错误描述。

type RefreshBatchMetrics

type RefreshBatchMetrics interface {
	Metrics
	// RecordRefreshBatch 记录批量刷新/全量刷新任务的汇总信息。
	RecordRefreshBatch(ctx context.Context, mode string, result string, total int, success int, failed int)
}

RefreshBatchMetrics 定义批量刷新与全量刷新任务的汇总指标接口。

type RefreshBatchResult

type RefreshBatchResult struct {
	Key   string `json:"key"` // Key 是当前批量项的缓存 key
	Error error  `json:"-"`   // Error 是当前批量项的执行错误
}

RefreshBatchResult 表示单条批量刷新请求的执行结果。

type RefreshBatchSummary

type RefreshBatchSummary struct {
	Total      int      `json:"total"`      // Total 是批量请求总数
	Success    int      `json:"success"`    // Success 是执行成功的条数
	Failed     int      `json:"failed"`     // Failed 是执行失败的条数
	FailedKeys []string `json:"failedKeys"` // FailedKeys 是执行失败的 key 列表
}

RefreshBatchSummary 表示一批刷新请求的汇总结果。

func SummarizeRefreshBatchResults

func SummarizeRefreshBatchResults(results []RefreshBatchResult) RefreshBatchSummary

SummarizeRefreshBatchResults 汇总批量刷新结果,便于管理页和预热任务统一判断。

func (RefreshBatchSummary) HasError

func (s RefreshBatchSummary) HasError() bool

HasError 返回当前批量刷新汇总是否包含失败项。

type ScanFallbackMetrics

type ScanFallbackMetrics interface {
	Metrics
	// RecordScanFallback 记录一次 DeleteByPrefix 索引未命中后的 SCAN 降级。
	RecordScanFallback(ctx context.Context, index string, prefix string)
}

ScanFallbackMetrics 定义前缀删除降级全库扫描的可选指标。

type Store

type Store interface {
	// AcquireRefreshLock 原子获取刷新锁;竞争失败时同时返回当前 owner。
	AcquireRefreshLock(ctx context.Context, key string, value string, ttl time.Duration) (locked bool, owner string, err error)
	// ApplyMutation 按故障安全顺序提交一次缓存变更。
	ApplyMutation(ctx context.Context, mutation StoreMutation) error
	// Exists 判断指定 key 是否存在。
	Exists(ctx context.Context, key string) (bool, error)
	// ExistsMulti 批量判断 key 是否存在,返回 map[key]exists。
	ExistsMulti(ctx context.Context, keys ...string) (map[string]bool, error)
	// Read 按缓存类型读取 Redis 原始值。
	Read(ctx context.Context, key string, typ CacheType) (any, error)
	// RefreshLock 仅当锁值与持有者标识一致时续期锁。
	RefreshLock(ctx context.Context, key string, value string, ttl time.Duration) (bool, error)
	// ReleaseLock 仅当锁值与持有者标识一致时释放锁,避免误删其它实例刚抢到的锁。
	ReleaseLock(ctx context.Context, key string, value string) (bool, error)
}

Store 定义 Manager 依赖的读取、批量变更和分布式锁契约。

type StoreMutation

type StoreMutation struct {
	Guards       []LockGuard           // Guards 是业务写删同一原子边界内必须校验的锁 owner
	DeleteKeys   []string              // DeleteKeys 是需要删除的真实 Redis key 列表,来源于旧业务 key、空值元信息或重建结果元信息
	WriteEntries []Entry               // WriteEntries 是需要写入的缓存条目,来源于 Loader 结果或内部元信息
	AddIndex     []PrefixIndexMutation // AddIndex 表示需要把哪些 key 加入前缀索引集合,通常来源于写入成功的业务 key 或元信息 key
}

StoreMutation 描述一次缓存刷新或清理需要提交到底层 Store 的变更集合。

type StoreValidator added in v1.22.2

type StoreValidator interface {
	// ValidateTablecacheStore 校验 Store 配置能否安全服务 table-cache。
	ValidateTablecacheStore() error
}

StoreValidator 定义 table-cache 构造期专用校验能力,避免碰撞自定义 Store 的通用 Validate 方法。

type Target

type Target struct {
	Index            string        // Index 是缓存目标索引,通常等于 Redis key 第一个冒号前的前缀
	Title            string        // Title 是缓存目标中文名称
	Key              string        // Key 是不含 Manager keyPrefix 的逻辑 key 或前缀,前缀型目标以冒号结尾
	KeyTitle         string        // KeyTitle 是不含 Manager keyPrefix 的展示模板
	Type             CacheType     // Type 是 Redis 数据结构类型
	Remark           string        // Remark 是缓存用途说明
	TTL              time.Duration // TTL 是业务缓存基础过期时间,0 表示不过期
	Jitter           time.Duration // Jitter 是 TTL 最大抖动范围,用于降低缓存雪崩风险
	EmptyTTL         time.Duration // EmptyTTL 是空值占位缓存过期时间,用于缓存穿透保护
	LoaderTimeout    time.Duration // LoaderTimeout 是当前目标回源加载超时时间,0 表示使用管理器默认值
	RefreshAll       bool          // RefreshAll 表示刷新全部缓存时是否包含该目标
	AllowEmptyMarker bool          // AllowEmptyMarker 表示加载空数据时是否写入空值占位
	Loader           Loader        // Loader 是缓存回源加载器
}

Target 描述一个可刷新、可展示、可复用的表数据缓存目标。

type ZMember

type ZMember struct {
	Member any     // Member 是有序集合成员
	Score  float64 // Score 是有序集合分数
}

ZMember 表示 Redis ZSet 成员与分数。

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

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