介绍
编写自定义缓存解决方案具有不可抗拒的吸引力,因为这似乎是“提高”整体应用程序性能的最简单途径。 嗯,缓存是一种很棒的技术,但是在考虑之前甚至没有几个步骤需要考虑。
最佳实践
-
键/值集合不是缓存
我从事的几乎所有项目都在使用某种基于Java Maps构建的自定义缓存解决方案。 映射不是开箱即用的缓存解决方案,因为缓存不仅仅是键/值存储。
缓存还需要:- 搬迁政策
- 最大尺寸限制
- 持久存储
- 弱引用键
- 统计
Java Map不提供这些功能,您也不应花费客户的钱来编写自定义缓存解决方案。 您应该选择功能强大且易于使用的专业缓存,例如EHCache或Guava Cache 。 所有使用这些工具的项目都对这些工具进行了不断的测试,因此代码质量高于大多数定制解决方案。
-
使用缓存抽象层
一个非常灵活的解决方案是Spring Cache抽象 。 @Cacheable批注允许您将业务逻辑代码与缓存横切关注点分开。 因此,缓存解决方案是可配置的,不会污染您的业务方法。
-
当心缓存开销
每个API都有成本,并且缓存也不例外。 如果您缓存Web服务或昂贵的数据库调用,则开销可以忽略不计。 如果将本地缓存用于递归算法,则需要了解整体缓存解决方案的开销。 即使是Spring缓存抽象也有开销 ,因此请确保收益大于成本。
-
如果您的数据库查询速度很慢,那么缓存应该是您的最后选择
如果您使用Hibernate之类的ORM工具,那么这就是您应该从中开始优化过程的第一步。 确保提取策略设计正确,并且不会遇到N + 1查询问题 。 您还可以声明SQL语句计数以验证ORM生成的查询。
完成对ORM SQL查询生成的优化后,应检查数据库中是否存在慢查询。 确保所有索引均已就位,并且您的SQL查询有效。 索引必须始终适合RAM,否则您将使用更昂贵的SSD或HDD。 您的数据库具有缓存查询结果的能力,因此请充分利用它。 如果数据集很大且增长率很高,则可以在多个分片上水平缩放它。 如果所有这些操作还不够,您可以考虑使用专业的缓存解决方案,例如Memcached 。 -
数据一致性如何?
当您开始在业务层前面使用高速缓存时,数据一致性约束受到了挑战。 如果缓存与数据库未正确同步,则ACID的好处可能会受到影响。 这就像保留实际数据的非规范化形式。 如果根实体发生更改,则可能会影响缓存的很大一部分。 如果丢弃高速缓存条目,则所有高速缓存的好处都会丢失。 如果异步更新缓存条目,则会失去强大的数据一致性,从而最终使数据模型保持一致 。
上场时间
受到关于Java 8computeIfAbsent Map新增内容这一非常有趣的文章的启发,我决定为您提供具有以下优点的Guava Cache替代品:
- 固定的缓存大小为2个条目
- 它适用于Java 1.6
private LoadingCache<Integer, Integer> fibonacciCache = CacheBuilder.newBuilder()
.maximumSize(2)
.build(new CacheLoader<Integer, Integer>() {
public Integer load(Integer i) {
if (i == 0)
return i;
if (i == 1)
return 1;
LOGGER.info("Calculating f(" + i + ")");
return fibonacciCache.getUnchecked(i - 2) + fibonacciCache.getUnchecked(i - 1);
}
});
@Test
public void test() {
for (int i = 0; i < 10; i++) {
LOGGER.info("f(" + i + ") = " + fibonacciCache.getUnchecked(i));
}
}
输出为:
INFO [main]: FibonacciGuavaCacheTest - f(0) = 0
INFO [main]: FibonacciGuavaCacheTest - f(1) = 1
INFO [main]: FibonacciGuavaCacheTest - Calculating f(2)
INFO [main]: FibonacciGuavaCacheTest - f(2) = 1
INFO [main]: FibonacciGuavaCacheTest - Calculating f(3)
INFO [main]: FibonacciGuavaCacheTest - f(3) = 2
INFO [main]: FibonacciGuavaCacheTest - Calculating f(4)
INFO [main]: FibonacciGuavaCacheTest - f(4) = 3
INFO [main]: FibonacciGuavaCacheTest - Calculating f(5)
INFO [main]: FibonacciGuavaCacheTest - f(5) = 5
INFO [main]: FibonacciGuavaCacheTest - Calculating f(6)
INFO [main]: FibonacciGuavaCacheTest - f(6) = 8
INFO [main]: FibonacciGuavaCacheTest - Calculating f(7)
INFO [main]: FibonacciGuavaCacheTest - f(7) = 13
INFO [main]: FibonacciGuavaCacheTest - Calculating f(8)
INFO [main]: FibonacciGuavaCacheTest - f(8) = 21
INFO [main]: FibonacciGuavaCacheTest - Calculating f(9)
INFO [main]: FibonacciGuavaCacheTest - f(9) = 34
- 代码可在GitHub上获得 。
翻译自: https://www.javacodegeeks.com/2014/03/caching-best-practices.html