ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

guava缓存批量获取的一个坑

2019-10-14 21:52:58  阅读:200  来源: 互联网

标签:缓存 批量 loadAll ids guava 加载


摘要

Guava Cache是Google开源的Java工具集库Guava里的一款缓存工具,一直觉得使用起来比较简单,没想到这次居然还踩了一个坑

背景

功能需求抽象出来很简单,就是将数据库的查询sthMapper.findById(Long id)的结果缓存起来。但同时还有批量请求,为了提高效率,肯定要批量查询数据库,sthMapper.findByIds(Collection<Long> ids)

对于的guava cache 处理类

  // 定义guava缓存
  public SthCache() {
        sthCache = CacheBuilder.newBuilder()
                .maximumSize(SIZE)
                .refreshAfterWrite(3, TimeUnit.SECONDS)
                .build(new CacheLoader<Long, List<Long>>() {
                    @Override
                    public List<Long> load(final Long id) {
                        return doLoad(Arrays.asList(id)).get(id);
                    }

                    @Override
                    public Map<Long, List<Long>> loadAll(
                            final Iterable<? extends Long> ids)
                            throws Exception {
                        return doLoad(Lists.newArrayList(ids));
                    }
                });
    }
// 实际从数据库中加载数据
private Map<Long, List<Long>> doLoad(final List<Long> ids) {
    return sthMapper.findByIds(ids);
} 
// 批量获取数据
 public Map<Long, List<Long>> getSthById(final List<Long> ids) {
        return sthCache.getAll(ids);
    
    }

没毛病,getAll(Iterable<? extendsK>)方法用来执行批量查询。默认情况下,对每个不在缓存中的键,getAll方法会单独调用CacheLoader.load来加载缓存项。如果批量的加载比多个单独加载更高效,你可以重载CacheLoader.loadAll来利用这一点。getAll(Iterable)的性能也会相应提升。这边定义了loadAll效率高了。

问题

在debug的时候发现确实走的loadAll,批量查询数据库。但是上线后,线上监控数据却发现这个接口耗时很长,通过分析,发现有很多sthMappper.findByIds()的单个查询。也就是说,并没有调用loadAll,走到批量查询数据库中。

分析解决

  1. 首先看了下guava的代码实现
ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
   int hits = 0;
   int misses = 0;
   // 省略一大坨
   try {
     if (!keysToLoad.isEmpty()) {
       try {
       // 调用loadAll
         Map<K, V> newEntries = loadAll(keysToLoad, defaultLoader);

批量查询时,对于没有命中的,确实调用的loadAll来加载数据的。

那问题就不是这边了。在load()方法打了个断点,原因就找到了。

原来是refesh的时候,加载的。refreshAfterWrite 刷新缓存数据时调用的还是load方法。

搜索了下,https://github.com/google/guava/issues/1975 github上这个issue还在。汗!!!

最后我这边解决是用Spring Cache统一了缓存管理。

总结

对于开源库的使用不可只知其然,不知其所以然。

关注公众号【方丈的寺院】,第一时间收到文章的更新,与方丈一起开始技术修行之路
在这里插入图片描述

标签:缓存,批量,loadAll,ids,guava,加载
来源: https://www.cnblogs.com/stoneFang/p/11674388.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有