乐趣区

关于程序员:本地缓存Guava-Cache教程

1. 背景

缓存的次要作用是临时在内存中保留业务零碎的数据处理后果,并且期待下次访问应用。在日长开发有很多场合,有一些数据量不是很大,不会常常改变,并且拜访十分频繁。然而因为受限于硬盘 IO 的性能或者近程网络等起因获取可能十分的费时。会导致咱们的程序十分迟缓,这在某些业务上是不能忍的!而缓存正是解决这类问题的神器!

缓存在很多零碎和架构中都用宽泛的利用, 例如:

  • CPU 缓存
  • 操作系统缓存
  • HTTP 缓存
  • 数据库缓存
  • 动态文件缓存
  • 本地缓存
  • 分布式缓存

能够说在计算机和网络畛域,缓存是无处不在的。能够这么说,只有有硬件性能不对等,波及到网络传输的中央都会有缓存的身影。

缓存总体可分为两种 集中式缓存 和 分布式缓存

“集中式缓存 ” 与 ” 分布式缓存 ” 的区别其实就在于“集中”与 ” 非集中 ” 的概念,其对象可能是服务器、内存条、硬盘等。

2.Guava Cache

Google 的 guava 是个很好的我的项目,提供了诸如汇合、缓存、并发、String 工具类等等,实乃 Java 开发利器。这里说一下 LoadingCache 应用的应用。

2.1 简略应用

应用 Cache 时,咱们优先读取缓存,当缓存不存在时,则从理论的数据存储获取,如 DB、磁盘、网络等,即 get-if-absent-compute。guava 提供了 CacheLoader 机制,容许咱们通过设置 Loader 来主动实现这一过程。如:

Cache<String, User> cache = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES);
user = cache.get(name, () -> {User value = query(key);//from databse, disk, etc.
    return value;
});

或者应用 LoadingCache:

LoadingCache<String, User> cache = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build(new CacheLoader<String, User>() {
        @Override
        public User load(String name) throws Exception {User value = query(key);//from databse, disk, etc.
        return value;
        }
    }
);

这可比本人写一个 Map 来缓存数据不便多了,而且还能够设置超时工夫主动帮咱们清理过期的数据。

不过须要留神一点的是,CacheLoader 不容许返回的数据为 NULL,否则会抛出异样:CacheLoader returned null for key。所以咱们须要保障查找的数据必须存在,或者抛出异样内部解决。在某些状况下,咱们的数据可能的确不在,比方用户治理模块,咱们在新增数据前,要查问原来是否曾经存在该用户,那么这时候抛出异样也不适合,此时能够应用 Optional 来优化 CacheLoader:

 LoadingCache<String, Optional<User>> cache = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build(new CacheLoader<String, Optional<User>>() {
        @Override
        public Optional<User> load(String name) throws Exception {User value = query(key);//from databse, disk, etc.
        return Optional.ofNullable(value);
        }
    }
);

这样咱们保障了 CacheLoader 返回值不为 NULL,而业务数据是否存在,只须要判断 Optional.ifPresent() 就行了,同时 Optional 的其余函数在业务逻辑中也是十分有用的。

2.2 和 Map 比拟

Guava Cache 与 ConcurrentMap 很类似,但也不齐全一样。最根本的区别是 ConcurrentMap 会始终保留所有增加的元素,直到显式地移除。绝对地,Guava Cache 为了限度内存占用,通常都设定为主动回收元素。在某些场景下,只管 LoadingCache 不回收元素,它也是很有用的,因为它会主动加载缓存。

Guava Cache 是在内存中缓存数据,相比拟于数据库或 redis 存储,拜访内存中的数据会更加高效。Guava 官网介绍,上面的这几种状况能够思考应用 Guava Cache:

  1. 违心耗费一些内存空间来晋升速度。
  2. 预料到某些键会被屡次查问。
  3. 缓存中寄存的数据总量不会超出内存容量。

所以,能够将程序频繁用到的大量数据存储到 Guava Cache 中,以改善程序性能。

2.3 Guava Cache 的 refresh 和 expire 刷新机制

看一下三种基于工夫的清理或刷新缓存数据的形式:

expireAfterAccess:当缓存项在指定的时间段内没有被读或写就会被回收。

expireAfterWrite: 当缓存项在指定的时间段内没有更新就会被回收。

refreshAfterWrite: 当缓存项上一次更新操作之后的多久会被刷新。

这三种之间的比照能够参考:Guava Cache 的刷新机制

退出移动版