107 lines
7.3 KiB
Plaintext
107 lines
7.3 KiB
Plaintext
================================================================================
|
||
EasyGoAdmin 后端开发者文档 · 15 缓存键与失效策略
|
||
================================================================================
|
||
缓存实现:utility/cache 统一门面(Redis 优先,失败/运行期出错自动降级进程
|
||
内存 gcache,UsingMemory() 可查)。Redis 键统一前缀 easygoadmin:(consts/
|
||
cache_key.go)。降级影响:多实例不共享(限流计数、任务锁、在线用户、黑名单、
|
||
验证码、字典全部退化单机语义)。
|
||
|
||
--------------------------------------------------------------------------------
|
||
1. 缓存分层图
|
||
--------------------------------------------------------------------------------
|
||
|
||
请求 ──▶ ① 进程内缓存(sync.Map,无 Redis 交互,重启即清)
|
||
dictTextCache(300s) · reqFieldCache/textPlanCache(反射计划,永不过期)
|
||
maskReCache(正则,永不过期)
|
||
──▶ ② Redis(跨实例共享,TTL 自动回收)
|
||
黑名单/在线/验证码/字典/租户摘要/身份/限流/任务锁
|
||
──▶ ③ 数据库(唯一真相,dao.Ctx 全量过滤条件)
|
||
|
||
设计原则:② ③ 之间的一切缓存都必须有明确的失效点或短 TTL 兜底;
|
||
① 仅缓存“计算计划/只读文本”,不允许缓存业务状态。
|
||
|
||
--------------------------------------------------------------------------------
|
||
2. Redis 键全集(键模式 / TTL / 写入方 / 读取方 / 失效策略)
|
||
--------------------------------------------------------------------------------
|
||
|
||
键模式 TTL 写入 读取
|
||
------------------------------------ -------- ------------ --------------
|
||
easygoadmin:token:blacklist:{jti} 剩余有效期 Logout/Refresh JWT 中间件
|
||
+0(+60) 轮换/RemoveToken Exists 判定
|
||
ForceLogout
|
||
easygoadmin:online:jti:set (zset) 成员随info MarkOnline OnlineUser.Page
|
||
(score=过期 ts)MarkOffline (ZRangeByScore≥now)
|
||
easygoadmin:online:info:{jti} access剩余 MarkOnline OnlineUser.Page/
|
||
+60s MarkOffline Detail/ForceLogout
|
||
easygoadmin:captcha:{uuid} 300s Captcha 生成 Login/Verify(一次性)
|
||
easygoadmin:dict:item:{code} 3600s dict.setCache/ dict_item 快捷接口/
|
||
(Refresh RefreshCache AliasList 等
|
||
Cache 主动刷)
|
||
easygoadmin:tenant:info:{id} 60s Tenant中间件/ Tenant 中间件/
|
||
(自然过期) Login 路径 Login
|
||
easygoadmin:user:identity:{uid} 300s JWT 中间件 JWT 中间件
|
||
(回源Loader) (LoadIdentity 结果 JSON:
|
||
Roles/Perms/DataScope/DeptId;
|
||
旧缓存缺新字段时读侧回退安全值)
|
||
easygoadmin:user:perms:{uid} —(约定键,当前主路径用 identity 合并键,
|
||
保留扩展;变更时一并清理)
|
||
easygoadmin:user:roles:{uid} —(同上)
|
||
ratelimit:{ip}:{path}:{窗口起点} window+5s RateLimit incr RateLimit
|
||
job:lock:{jobId} 300s 兜底 jobTryLock(NX) jobTryLock
|
||
(执行完即 Del)
|
||
|
||
--------------------------------------------------------------------------------
|
||
3. 主动失效点清单(代码级)
|
||
--------------------------------------------------------------------------------
|
||
身份缓存 user:identity:{uid} 删除时机:
|
||
* role.SavePermission 保存角色权限 → clearRoleIdentityCache(roleId)
|
||
→ 查该角色全部 user → 逐个 Del
|
||
* role.Update 修改角色(含 data_scope 数据范围变更)→ AfterUpdate
|
||
钩子 roleClearCache → 同上链路逐个 Del
|
||
* user.AssignRoles 分配/调整角色 → clearIdentityCache(userId)
|
||
(user.Update / user.Add 均经 AssignRoles——改部门 dept_id 亦在此
|
||
路径清缓存,数据权限部门维度变更即时生效)
|
||
* user 修改密码 / 禁用等(部分路径主动清;其余靠 300s 过期兜底)
|
||
* 版本兼容:Identity 新增字段(DataScope/DeptId)反序列化缺省为 0,
|
||
读侧 GetDataScope 回退"全部"——升级无需强清存量缓存
|
||
租户摘要 tenant:info:{id} 删除时机:
|
||
* tenant 状态/过期时间变更(tenant 模块 AfterUpdate clearCache 钩子)
|
||
字典 Redis 缓存 dict:item:{code}:
|
||
* dict.RefreshCache 主动全量/单编码重建;dict_item 变更不主动清
|
||
(最长 1 小时延迟——关键场景调刷新接口)
|
||
黑名单:不主动删,靠 TTL=令牌剩余有效期自然过期(过期即令牌本身已失效)。
|
||
任务锁 job:lock:{id}:执行结束 defer Del;崩溃场景靠 300s TTL 兜底。
|
||
验证码:Verify 命中即删(一次性)。
|
||
|
||
--------------------------------------------------------------------------------
|
||
4. 进程内缓存明细
|
||
--------------------------------------------------------------------------------
|
||
dictTextCache(base.go)key={code}:{value} → 显示名,TTL 300s。
|
||
读多写少的 {field}Text 填充热路径。修改字典文案最迟 5 分钟生效;
|
||
RefreshCache 不清此层(各实例自然过期)。
|
||
reqFieldCache / textPlanCache / childrenIdxCache(module_spec.go)
|
||
反射索引与填充计划,按 reflect.Type 缓存,进程生命周期——只缓存“结构计划”
|
||
不缓存数据,类型不变即安全。
|
||
maskReCache(middleware/util.go)脱敏正则,按字段名缓存。
|
||
|
||
--------------------------------------------------------------------------------
|
||
5. TTL 设计原则(新增缓存时遵循)
|
||
--------------------------------------------------------------------------------
|
||
1) 状态判定类(黑名单/租户状态):TTL ≤ 业务有效期,且必须有主动失效点;
|
||
宁可短 TTL 多回源,不可长 TTL 陈旧放行。
|
||
2) 展示文本类(字典/归属地):TTL 300s~3600s + 刷新接口,接受分钟级延迟。
|
||
3) 高频读聚合类(identity):合并为单键 JSON(一次回源装多个集合),
|
||
TTL 300s,变更路径主动 Del。
|
||
4) 计数/锁类:键内嵌窗口起点或场景唯一 id,TTL 只做回收不参与语义
|
||
(限流窗口、执行锁均如此)。
|
||
5) 任何经 cache.Set 的值必须可 JSON 序列化为字符串;读侧 Unmarshal 失败
|
||
视为未命中回源。
|
||
|
||
--------------------------------------------------------------------------------
|
||
6. 排障
|
||
--------------------------------------------------------------------------------
|
||
键不存在/值陈旧:先查是否内存降级(redis-cli KEYS 'easygoadmin:*' 对比);
|
||
权限不生效:DEL easygoadmin:user:identity:{uid};
|
||
租户被禁仍可访问:等 60s 或 DEL easygoadmin:tenant:info:{id};
|
||
多实例行为不一致:确认 Redis 可用(/api/cache/info mode 应为 redis)。
|