两级缓存J2cache的小问题
声明:本文转载自https://my.oschina.net/qixiaobo025/blog/1617486,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。
背景
由于系统性能需求 现在将某些数据做了缓存 目前的策略是最长10分钟过期
<cache name="bussiness" maxElementsInMemory="100000" eternal="false" overflowToDisk="false" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU"> </cache>
这部分数据有特点如下:
- 数据不要求实时更新【查询次数多 更新次数少】
- 数据对于日期敏感
- 无特殊条件 各个用户数据相同
问题
实施反馈了一些数据如下

但是随后告知了开发

那么如何着手这个问题呢?
分析
- 首先在代码未变动之前 客户未反馈过此问题 初步排除是客户端缓存【不然应该以前也反馈该问题了】
- 那么大概率由于服务端加了缓存导致的 如果说是缓存出现了问题 那么客户清理了浏览器缓存怎么也不会发生数据正常【除非恰巧那个时间过期了】
- 那么集合我们使用两级缓存来分析吧 关于两级缓存的说明

既然使用了多级缓存那么必然是分布式环境才有价值
考虑了一下上述流程存在一个问题
- 由于ehcache这一步写数据到redis中是使用list的那么势必无法对redis每个key设置各自的ttl 因此对于
很明显了确实ttl是-1 - 对于ehcache来说我们知道ehcache的过期是懒过期 何为懒过期?就是过期的策略在执行get的时候才会检查 参考关于两级缓存的说明 这样有可能发生一个问题

- 当多台机器的时候 一旦某一台机器正在发布等场景 为了简单描述我们分别设置为机器A 机器B
机器A上的为ehcacheA 机器B上的为ehcacheB 【两者完全等价】 - 如果用户访问的数据此后再不会访问的话
当机器A需要发布的时候 此时机器A上的ecacheA将会清空
那么就会出现在ehcacheB上的数据存在 而此时ehcacheA上并没有该key【当然redis中也存在】
此时机器A发布完成 来进行机器B的发布 那么此时机器B上ehcacheB的对应的缓存key也会消失
那么现在唯一留着数据的地方就是redis
第二天用户访问该数据就会发现本地ehcache没有数据 那么访问机器A会生成本地ehcacheA数据 访问机器B会生成本地ehcacheB数据【出现下次第一次访问的时候直到ehcache过期时间达到才会清除数据】 - 当机器A需要发布的时候 用户通过机器B来访问服务 此时机器A上的ecacheA将会清空
此时机器A发布完成 来进行机器B的发布 那么此时机器B上ehcacheB的对应的缓存key也会消失 此刻用户通过机器A获取服务【ehcacheA上写入了新的数据】
如果用户访问的数据此后再不会访问的话 那么就会出现在ehcacheA上的数据一直存在【ehcache懒过期】 而此时ehcacheB上并没有该key【当然redis中也存在】
用户下一次【比如现在的场景 下一天】访问时假设第一次访问的是机器B 发现ehcacheB中没有数据 随即去了redis中获取了脏数据 那么此时ehcacheB和ehcachA中数据已经不一样了
那么用户如果一直访问机器B的话直到ehcache过期时间达到才会清除数据 但是由于nginx策略通常会随机访问到机器A的服务 此时由于懒加载策略发现时间已经过期 因此去除了缓存 发送了expire广播
此时机器A 机器B 和redis中数据都被清除 但是此时访问到了真正的服务【通常是db】将新的结果同时存入了redis和ehcacheA中 用户获得了正确的结果
-
推广开应该很多场景下会有此问题 需要开发人员注意一下~
解决方案
由于用户关心的数据对日期比较敏感
因此考虑增加日终任务在12:00 自动清除该缓存~
抱拳了,老铁!
本文发表于2018年02月02日 20:31
(c)注:本文转载自https://my.oschina.net/qixiaobo025/blog/1617486,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.
阅读 3634 讨论 0 喜欢 0