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:
- 违心耗费一些内存空间来晋升速度。
- 预料到某些键会被屡次查问。
- 缓存中寄存的数据总量不会超出内存容量。
所以,能够将程序频繁用到的大量数据存储到 Guava Cache 中,以改善程序性能。
2.3 Guava Cache 的 refresh 和 expire 刷新机制
看一下三种基于工夫的清理或刷新缓存数据的形式:
expireAfterAccess:当缓存项在指定的时间段内没有被读或写就会被回收。
expireAfterWrite: 当缓存项在指定的时间段内没有更新就会被回收。
refreshAfterWrite: 当缓存项上一次更新操作之后的多久会被刷新。
这三种之间的比照能够参考:Guava Cache 的刷新机制