元数据变更后的缓存失效
当 PM 在后台保存变更(给表单加列、更新权限、注册新模块)时,每个运行节点都必须丢弃对旧元数据的缓存解释。xly 通过 JMS 完成,而不是轮询。
路径
PM 在**后台**保存
↓
**后台**控制器写入变更的 gds_* 行
↓
Controller 发布 JMS “module changed” 消息
↓
每个节点的 xlyErpJmsConsumer 收到消息
↓
ConsumerChangeGdsModuleThread.run() 清除相关 Redis key
↓
任意节点下一次 /business/getModelBysId 调用重新读表,
并用新值重新填充缓存
处理器位于 xlyErpJmsConsumer/src/main/java/com/xly/xlyerpjmsconsumer/thread/ConsumerChangeGdsModuleThread.java。
为什么是 JMS,不是轮询后清除
xly 经常跨多个节点运行(xlyEntry、xlyApi、xlyInterface 各自 JVM,有时水平扩展)。轮询“元数据是否变了”要么很慢(直到下一次轮询才可见),要么很吵(持续心跳)。JMS 可以在毫秒级把失效广播到每个节点。
代码库同时使用 ActiveMQ 和 RocketMQ,但这里记录的元数据变更路径是 ActiveMQ / JMS:xlyErpJmsConsumer 用 @JmsListener 监听 P2pQueue.ERP_JMS_ACTIVEMQ_CHANGE_GDS_MODULE,ConsumerChangeGdsModuleThread 负责清缓存。RocketMQServiceImpl 用于其他集成流。
会清哪些 key
Redis 缓存包含:
- 按
sId的模块元数据。 - 按
sId的表单元数据。 - 按表单
sId的字段从表列表。 - 每租户覆盖合并结果(派生缓存)。
- 每(模块、角色)的权限规则。
consumer thread 收到变更行 ID 后,会清掉每个可能包含它的缓存 key 家族。这里过度失效是安全选择:下一次请求多读一次 DB 的成本,远小于继续服务陈旧元数据的成本。
直接用 SQL 修改元数据时
通过 MyBatis 或通过后台做的 insert / update 会触发 JMS 事件。工程师直接在生产 DB 执行 UPDATE gdsmodule SET ... 不会触发。缓存会持续提供旧元数据,直到:
- 缓存 TTL 过期(实际 TTL 看缓存配置)。
- 重启应用服务器。
- 手工发送 JMS 消息(见
xlyBusinessService中的BusinessCleanRedisDataImpl)。
第三种是受支持的 workaround;第二种是粗暴 fallback。
常见 bug:问题其实是缓存
当现象像是“我改了但页面还是旧值”时,按顺序检查:
- 变更是否实际提交?(对 DB 执行
SELECT确认。) - 后台节点能否访问 JMS broker?(不能访问时,失效事件不会发布。)
- 所有 consumer 节点是否在运行?(暂停的节点会继续服务旧元数据直到重启。)
- 变更是否通过原始 SQL 完成?(那就没有 JMS 事件,需要手工触发。)
切片 1 的“五表读取”会从缓存重新运行;理解哪一层陈旧是定位 bug 的关键。