首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Guava Cache最佳实践

Guava Cache最佳实践

作者头像
十毛
发布2019-03-27 14:43:44
1.7K0
发布2019-03-27 14:43:44
举报

项目中经常使用Guava Cache,根据经验总结了一些最佳实践。

示例代码

快速有效的使用示例如下:

LoadingCache<Integer, Model> modelCache = CacheBuilder.newBuilder()
        //限制缓存大小,防止OOM
        .maximumSize(1000)
        //提供过期策略
        .expireAfterAccess(100, TimeUnit.MINUTES)
        //缓存不存在的时候,自动加载
        .build(new CacheLoader<Integer, Model>() {
            @Override
            public Model load(@Nonnull Integer key) {
                Model model = doGetModel(key);
                if (model == null) {
                    //guava不支持null,会抛出异常InvalidCacheLoadException,最佳办法是抛出自定义异常
                    throw new ModelNotFoundException();
                }
                return model;
            }
        });

最佳实践

自动加载

如果缓存不存在,则自动去数据源加载数据到缓存

.build(new CacheLoader<Integer, Model>() {
    @Override
    public Model load(@Nonnull Integer key) {
        return doGetModel(key);
    }
)

内存控制

使用缓存一定要防止缓存占用过多的内存,导致程序OOM。需要对缓存的内存使用量进行限制,同时还需要设置过期或刷新策略。

//限制缓存大小,防止OOM
.maximumSize(1000)
//提供过期策略
.expireAfterAccess(100, TimeUnit.MINUTES)

上面是使用得最多的两个选项,其他选项还有:

  • maximumWeight:限制最大权重(权重的计算方式需要传递Weigher
  • expireAfterWrite:写入后多长时间过期
  • refreshAfterWrite:写入后多长时间刷新

removal listener

在一些场景下,监控cache的换出结果,方便做出响应,比如在集群本地缓存同步的时候,可以监听后同步给集群内其他机器。参见:本地缓存同步的一个简单方案

.removalListener((RemovalListener<Integer, Model>) notification -> {
    log.info("remove taskbot from guava cache: key[{}], cause[{}]", notification.getKey(), notification.getCause());
    final RemovalCause cause = notification.getCause();
    switch (cause) {
        case EXPIRED:
            log.info("model evicted because of expiration in guava cache: {}", notification.getKey());
            break;
        case SIZE:
            log.info("model evicted because of size in guava cache: {}", notification.getKey());
            break;
        case COLLECTED:
            //如果是缓存到期等原因被删除,则需要通知分布式环境下的其他机器也要删除
            log.info("model evicted because of gc in guava cache: {}", notification.getKey());
            break;
        case EXPLICIT:
            log.info("model evicted because of explicit in guava cache: {}", notification.getKey());
            break;
        case REPLACED:
            log.info("model updated because of replaced in guava cache: {}", notification.getKey());
            break;
        default:
            log.error("there should not be [{}]", cause);
    }
})

查看缓存统计值

可以了解缓存使用的特性,比如命中率等

CacheStats Cache#stats();

public final class CacheStats {
  //命中次数
  private final long hitCount;
  //击穿次数
  private final long missCount;
  //加载成功次数
  private final long loadSuccessCount;
  //加载发生异常的次数
  private final long loadExceptionCount;
  //加载时间总机
  private final long totalLoadTime;
  //换出的次数
  private final long evictionCount;
}

不常用功能

weakKey, weakValue, softValue

使用这些值可以把内存的使用量交给JVM来控制,一般不太实用

NULL值的处理

GauvaCache不支持null值的缓存,而且会抛出异常InvalidCacheLoadException,最佳办法是抛出自定义异常,然后在Cache#get的时候捕捉定义异常。示例如下:

@Override
public Model load(@Nonnull Integer key) {
    Model model = doGetModel(key);
    if (model == null) {
        //guava不支持null,会抛出异常InvalidCacheLoadException,最佳办法是抛出自定义异常
        throw new ModelNotFoundException();
    }
    return model;
}
try {
    modelCache.get(key);
} catch (ExecutionException e) {
    //TODO: handle exception
} catch (ModelNotFoundException e) {
    //TODO: handle exception
}

注意事项

  • GauvaCache异步刷新缓存,不会阻塞线程获取缓存内容(老的内容)
  • GauvaCache不支持缓存null值

参考

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 示例代码
  • 最佳实践
    • 自动加载
      • 内存控制
        • removal listener
          • 查看缓存统计值
            • 不常用功能
              • weakKey, weakValue, softValue
            • NULL值的处理
            • 注意事项
            • 参考
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档