多级缓存支撑海量读服务设计方案
Cache1:一级本地缓存(map,ehcache,guava)
Cache2: 二级分布式缓存(redis,memcached,hazelcast,iginte)
更新集群一级缓存(jgroup,mq,redis subscribe,zk)
get操作 getCache1 > getCache2 > setCache1
set操作 deleteCache1(广播,消息) > setCache1 > setCache2
delete操作 > deleteCache1 > deleteCache2 > deleteCache1(广播,消息)
场景1: 一对一缓存(更新某个特定对象)
方案一:
删除所有一二缓存,请求重新构建缓存
请求 > get操作 > getDB > set操作
方案二:
cache1缓存永不失效,在应用端监控CacheKey(应用本地监控,或者更新源发送mq信息通知),发现缓存失效,重新构建更新cache1,cache2.
更新缓存 > 监控CacheKey > setCache1 > setCache2
请求 > get操作
场景2: 一对多缓存(一个聚合对象,包含很多小对象嵌套,小对象有多处修改,小对象修改会影响象,但是无法更新聚合对象缓存,只能清除聚合对象缓存)
请求 > get操作 > getAll聚合 > set操作
更新小对象:
方案一:
删除所有一二缓存,请求重新构建缓存
更新小对象SmallObj2 > setCache1SmallObj2 > setCache2SmallObj2 > deleteCache2 > deleteCache1(广播,消息)
请求 > get操作 > getAll聚合(getSmallObj1(缓存操作),getSmallObj2(缓存操作),getSmallObj3(缓存操作)) > set操作
方案二:
cache1缓存永不失效,在应用端监控CacheKey(应用本地监控,或者更新源发送mq信息通知),发现缓存失效,重新构建更新cache1,cache2.
更新小对象SmallObj2 > 监控CacheKey > setCache1 > setCache2
请求 > get操作
缺点:
1.由于是聚合对象,更新小对象时无法回源聚合对象,如需回源聚合对象需要保存回源参数,实现较麻烦。
2.更新延迟问题。
优点:
如果能方便回源聚合对象,这种方式稳定性优。
场景1和场景2的区别:
小对象(简单的单一对象),应该只有一个地方修改,而且可以根据参数回源该对象
比如角色对象修改,可以直接修改集群中的一级缓存
嵌套对象(复杂的对象嵌套层级多,修改点多),修改的地方很多,在修改的地方回源不了嵌套对象,
更新不了集群中的一级缓存
---------------------------------------------------------------------------------------------------------------------------
缓存穿透,缓存雪崩而外处理
---------------------------------------------------------------------------------------------------------------------------
根据设计方案应该设计一个类似j2cache的框架
实际场景:
由于目前用的redis两种版本,而且互相调用,如果设计类似j2cache的框架,没法用会冲突。
方案:
设计一个本地一级缓存方案,添加本地一级缓存,分布式二级缓存,分开来添加。对本地一级缓存提供一下功能:
增删该查本地,集群一级缓存