我是靠谱客的博主 无聊小刺猬,最近开发中收集的这篇文章主要介绍分布式应用缓存使用模式Cache-AsideCache-As-SoR,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

  • 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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部