一、痛点
多模块服务协作开发背景下,随着缓存越来越多,缓存的一致性维护难度随之提升。
-
多模块服务之间的缓存 key 维护容易造成遗漏,如 OP 与各服务之间的缓存交互。
-
单独模块多人开发甚至独立开发时,随着业务缓存的数量增多,在缓存的处理上也会有遗漏。
结论:
人工维护极易遗漏,沟通时也会出现理解偏差,造成缓存不一致,后期排查定位问题难度增加。其中的种种,带来很多的时间成本、沟通成本和开发成本。
二、思考
难点其实在于 数据查询方 与 数据更新方 的沟通问题,思考:
- 数据查询方
查询数据时,我加了缓存之后需要告诉哪些服务我缓存了这些数据?什么时候需要刷新缓存?数据有变动,有什么机制通知到我更新缓存,或者帮我做刷新? - 数据更新方
数据更新时,那些缓存与之相关需要更新?什么情况下需要更新?
结论:
加缓存时通知加了 什么表 的缓存,什么时候 需要刷新缓存;
数据表更新时按照缓存的 刷新时机 刷新。
三、解决方案
首先讨论缓存的更新机制都有哪些:
- 单条更新时(id,userId 等特定标识,适用单条缓存)
- 单表有数据更新时(表全量数据缓存或难以通过特定标示定位到的)
- 多表有数据更新时(缓存的数据与业务多表强相关,一张表有更新就要更新缓存)
...
解决思路:
1、加缓存,规则统一无需通知
按更新机制配置 Hash name , 命名方式为 表名 + 更新机制,下属 key 的命名可以按照模块前缀 + 自定义方式。
2、更新缓存,端 + Syncer 管理。
缓存的刷新由服务本身管理 + Syncer 统一管理的方式。服务可以自主更新缓存,并发送更新消息至 Syncer , 解析消息后刷新缓存。
消息格式:
表 + 更新机制 即上述的 Hash name,对应的更新机制消息:
- 单条更新,带上 id;
- 单表更新, 多表更新
- 能准确定位 id ,带上各表 id
- 其他
交互图:
3、通知方式
- 各服务自己控制缓存更新时发送消息,注解 AOP
- Mybatis 拦截器
- binglog
...
四、应用到生产环境的解决方案
- 使用发 MQ 的方式解决,每个表为特定的 topic ,对数据有修改则发消息,消息内容为
{"source":"app1","id":1...}
,其中 source 是标示发消息的应用,再带上关注的索引,一般 key 都是以重要的索引来作区分,比如 id ,userId... - 应用订阅关心的 topic ,自己消费做缓存同步处理。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于