guava cache的一些使用经验

ClickHouse微服务Service Mesh
  1. guava cache的实现

这里我们主要介绍LoadingCache,对于LoadingCache主要有:

  • ForwardingLoadingCache 需要自己设置一个代理的LoadingCache
  • LocalLoadingCache 用的是LocalCache来处理
  1. 关于LocalCache

它本身继承自AbstractMap,实现了ConcurrentMap。是根据jdk1.7中的ConcurrentHashMap中的分段锁的原理来实现的,构造方法为:

picture.image

先分N个Segment加锁,Segment下面才是HashMap。这样就把原本一个锁,打散成N个锁。但和ConcurrentHashMap默认16个锁不一样,GuavaCache默认是4个锁。下面的concurrencyLevel是根据这个来设置的。

  1. 使用cache


      1. `1. Cache<Object, Object> realTimeCache = CacheBuilder.newBuilder().maximumSize(2000).maximumWeight(2000).`
2. `//并发级别,即锁粒度`
3. `.concurrencyLevel(16).`
4. `expireAfterWrite(7, TimeUnit.DAYS).build();`
5. 
6. `2. CacheBuilder.newBuilder()`
7. `.expireAfterWrite(time, TimeUnit.MINUTES)`
8. `.build(new CacheLoader<Long, Object>() {`
9. `@Override`
10. `public Object load(Long key) throws Exception {`
11. `return new Object();`
12. `}`
13. `});`


    

缓存控制主要有根据大小和时间还有缓存引用这几种方式。根据大小:

  • maximumSize :该缓存的最大存储单位(key)个数。
  • maximumWeight:设定缓存数据的最大值。根据时间:
  • expireAfterWrite:缓存写入后多久过期。
  • expireAfterAccess:缓存读取后多久过期。
  • refreshAfterWrite:缓存写入后多久更新。根据引用:weakKeys,weakValues,softValues三种方式都是应用java的弱引用(WeakReference)和软引用(SoftReference)在内存不足时会自动触发gc,被回收。
  1. 缓存加载

  • 构建com.google.common.cache.CacheBuilder#build(com.google.common.cache.CacheLoader):

picture.image

  • 根据key获取缓存中的值:

picture.image


      1. `V getOrLoad(K key) throws ExecutionException {`
2. `return get(key, defaultLoader);`
3. `}`
4. 
5. `V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException {`
6. `int hash = hash(checkNotNull(key));`
7. `return segmentFor(hash).get(key, hash, loader);`
8. `}`
9. 
10. ![picture.image](https://p3-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/e4b3ec3f487448d2a97290fddb22e280~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1749376347&x-signature=E%2BFegaQPozMsg6%2BJpOaC6ypKCIE%3D)
11. 
12. `创建新段的时候是通过loadSync去加载的:`
13. ![picture.image](https://p3-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/6deb6ce3da314feaac5f03a246f57409~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1749376347&x-signature=HZ4VX0RyYgVfdRixQ%2FsFcmNgWSw%3D)


    

实际加载的过程为:

picture.image

picture.image

picture.image

可以看到在com.google.common.cache.LocalCache.Segment#loadSync和com.google.common.cache.LocalCache.Segment#loadAsync方法中都有ListenableFutureloadingFuture = loadingValueReference.loadFuture(key, loader)的操作, 在其内部调用的是com.google.common.cache.CacheLoader#reload方法,使用的是Futures.immediateFuture(load(key))阻塞式的返回方法。如果load的过程比较耗时,会造成卡顿,需要设置后台刷新。

  1. 设置缓存的后台刷新

  • 使用com.google.common.cache.CacheLoader#asyncReloading方法创建CacheLoader:

      1. `public static <K, V> CacheLoader<K, V> asyncReloading(`
2. `final CacheLoader<K, V> loader, final Executor executor)`


    

可以传入一个Executor。

  • 自己实现CacheLoader的时候,同时实现reload方法,给这个reload方法一个Executor线程(如果多处使用,可以使用只有一个线程的池)。

上述两种方法哪种更好,一般建议使用后一种,因为前一种包装类的方式可能会不内联。

参考江南白衣的博客:http://calvin1978.blogcn.com/articles/guava-cache%E5%B0%8F%E8%AE%B0.html

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
VikingDB:大规模云原生向量数据库的前沿实践与应用
本次演讲将重点介绍 VikingDB 解决各类应用中极限性能、规模、精度问题上的探索实践,并通过落地的案例向听众介绍如何在多模态信息检索、RAG 与知识库等领域进行合理的技术选型和规划。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论