概述
- Cache-Aside
- Cache-As-SoR
- Read-Through
- Write-Through
- Write-Behind
在我们使用缓存时,有一些模式或者策略。其主要分为两大类,Cache-Aside
:由业务代码直接维护缓存;Cache-As-SoR
:把Cache作为数据源,所有的读写操作都是对Cache而言的,如果要执行持久化等操作,则是由Cache本身去处理。
Cache-Aside
- 读场景:先从缓存读取,如果没有命中,则回源到DB中去获取,并且将数据放入缓存,以备下一次使用。
- 写场景:先将数据写入DB,成功后再将数据同步至缓存(也可能是删除过期缓存)。
Cache-Aside方式的缓存策略,通常情况下我们会想到AOP就可以解决这个事情。笔者也写过简单的基于AOP的注解缓存,但是还有更为强大的中间件封装。其中有Spring官方提供的Spring Cache和Alibaba开源的JetCache。但是笔者认为JetCache使用起来更加便利,功能更为强大,后续会有文章单独介绍。
缓存更新时,有可能会出现多实例同时更新,则可以考虑以下2中场景。
如用户维度
的数据(账户流水/订单等),产生并发的几率比较小,通常情况下不会考虑到并发更新的问题,加上个过期时间就可以了。
如果是基础数据
(商品等),则可以考虑使用canal订阅binlog,来实现增量更新分布式缓存,这样就不会出现缓存数据不一致的情况。但是本地缓存要设置合理的过期时间,来容忍本地缓存的延迟。
Cache-As-SoR
Cache-As-SoR把Cache看成数据源,所有的操作都只是对Cache操作的,然后Cache再异步的去进行持久化存储。其有3种实现:read-through、write-through、write-behind。
Read-Through
业务代码首先读取Cache,当Cache没有时,此时回源操作交给Cache去操作。这样对业务代码来说是透明的。下面看一下Guava的实现:
LoadingCache<Integer, Result<Category>> getCache = CacheBuilder.newBuilder()
.softValues().maximumSize(5000).expireAfterWrite(2, TimeUnit.MINUTES)
.build(new CacheLoader<Integer, Result<Category>>() {
@Override
public Result<Category> load(final Integer sortId) throws Exception {
return categoryService.get(sortId);
}
});
build cache时,传入了一个CacheLoader用来加载缓存,流程如下:
(1)业务代码调用getCache(sortId)时,首先查询Cache,若有则直接返回。
(2)若没有,则委托给CacheLoader去回源,然后写入缓存。
这种委托模式使代码看起来更加的整洁,并且在委托代码中可以更容易的实现同步控制,避免并发更新缓存使得DB压力过大。但是这种模式需要注意的是,委托的过程中失败的问题,要去不断的重试去履约缓存的操作。
Write-Through
业务代码首先写到Cache中,然后负责写Cache和DB数据。Guava Cache并没有提供支持,Ehcache提供了这种支持。
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);
Cache<String, String> myCache = cacheManager.createCache("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(100, MemoryUnit.MB)))
.withDispatcherConcurrency(4)
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(10, TimeUnit.SECONDS)))
.withLoaderWriter(new DefaultCacheLoaderWriter<String, String>() {
@Override
public void write(String key, String value) throws Exception {
// write
}
@Override
public void writeAll(Iterable<? extends Map.Entry<? extends String, ? extends String>> entries) throws BulkCacheWritingException, Exception {
for (Object entry : entries) {
// batch write
}
}
@Override
public void delete(String key) throws Exception {
// delete
}
@Override
public void deleteAll(Iterable<? extends String> keys) throws BulkCacheWritingException, Exception {
for (Object key : keys) {
// batch delete
}
}
}).build();
Write-Behind
这种模式是在写入缓存之后,再异步的进行持久化操作。异步化之后,可以实现批量入库、延迟入库等。
参考:《亿级流量网站架构核心技术》
链接:http://moguhu.com/article/detail?articleId=94
最后
以上就是无聊小刺猬为你收集整理的分布式应用缓存使用模式Cache-AsideCache-As-SoR的全部内容,希望文章能够帮你解决分布式应用缓存使用模式Cache-AsideCache-As-SoR所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复