缓存最佳做法

介绍

编写自定义缓存解决方案具有不可抗拒的吸引力,因为这似乎是“提高”整体应用程序性能的最简单途径。 嗯,缓存是一种很棒的技术,但是在考虑之前甚至没有几个步骤需要考虑。

最佳实践


  1. 键/值集合不是缓存

    我从事的几乎所有项目都在使用某种基于Java Maps构建的自定义缓存解决方案。 映射不是开箱即用的缓存解决方案,因为缓存不仅仅是键/值存储。
    缓存还需要:

    • 搬迁政策
    • 最大尺寸限制
    • 持久存储
    • 弱引用键
    • 统计

    Java Map不提供这些功能,您也不应花费客户的钱来编写自定义缓存解决方案。 您应该选择功能强大且易于使用的专业缓存,例如EHCacheGuava Cache 。 所有使用这些工具的项目都对这些工具进行了不断的测试,因此代码质量高于大多数定制解决方案。

  2. 使用缓存抽象层

    一个非常灵活的解决方案是Spring Cache抽象@Cacheable批注允许您将业务逻辑代码与缓存横切关注点分开。 因此,缓存解决方案是可配置的,不会污染您的业务方法。

  3. 当心缓存开销

    每个API都有成本,并且缓存也不例外。 如果您缓存Web服务或昂贵的数据库调用,则开销可以忽略不计。 如果将本地缓存用于递归算法,则需要了解整体缓存解决方案的开销。 即使是Spring缓存抽象也有开销 ,因此请确保收益大于成本。

  4. 如果您的数据库查询速度很慢,那么缓存应该是您的最后选择

    如果您使用Hibernate之类的ORM工具,那么这就是您应该从中开始优化过程的第一步。 确保提取策略设计正确,并且不会遇到N + 1查询问题 。 您还可以声明SQL语句计数以验证ORM生成的查询。
    完成对ORM SQL查询生成的优化后,应检查数据库中是否存在慢查询。 确保所有索引均已就位,并且您的SQL查询有效。 索引必须始终适合RAM,否则您将使用更昂贵的SSD或HDD。 您的数据库具有缓存查询结果的能力,因此请充分利用它。 如果数据集很大且增长率很高,则可以在多个分上水平缩放它。 如果所有这些操作还不够,您可以考虑使用专业的缓存解决方案,例如Memcached

  5. 数据一致性如何?

    当您开始在业务层前面使用高速缓存时,数据一致性约束受到了挑战。 如果缓存与数据库未正确同步,则ACID的好处可能会受到影响。 这就像保留实际数据的非规范化形式。 如果根实体发生更改,则可能会影响缓存的很大一部分。 如果丢弃高速缓存条目,则所有高速缓存的好处都会丢失。 如果异步更新缓存条目,则会失去强大的数据一致性,从而最终使数据模型保持一致

上场时间

受到关于Java 8computeIfAbsent Map新增内容这一非常有趣的文章的启发,我决定为您提供具有以下优点的Guava Cache替代品:

  1. 固定的缓存大小为2个条目
  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

参考:Vlad Mihalcea的Blog博客上,从我们的JCG合作伙伴 Vlad Mihalcea 缓存最佳实践

翻译自: https://www.javacodegeeks.com/2014/03/caching-best-practices.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值