跳到主要内容
版本:7.0.3

理解缓存抽象

Hunyuan 7b 中英对照 Understanding the Cache Abstraction

缓存(Cache)与缓冲区(Buffer)

“缓冲区(buffer)”和“缓存(cache)”这两个术语经常被交替使用。然而需要注意的是,它们实际上代表不同的概念。传统上,缓冲区(buffer)被用作快速处理单元和慢速处理单元之间的临时数据存储介质。由于一方需要等待另一方(这会影响性能),缓冲区通过允许数据整块传输而非分小部分传输来缓解这一问题。数据仅从缓冲区中写入或读取一次。此外,至少有一方能够意识到缓冲区的存在。

另一方面,缓存(cache)按定义是“隐藏”的,双方都无法察觉到缓存机制的运行。缓存同样能够提升性能,但其实现方式是允许同一数据被快速地多次读取。

关于缓冲区和缓存之间差异的更多解释,可在此处找到。

其核心在于,缓存抽象将缓存机制应用于Java方法,从而根据缓存中的信息减少方法的执行次数。也就是说,每次调用某个方法时,该抽象会检查该方法是否已经针对给定的参数被调用过。如果已经调用过,则直接返回缓存结果,而无需再实际调用该方法;如果尚未调用过,则会执行该方法,并将结果缓存起来以便下次调用时能够直接返回缓存结果。通过这种方式,对于那些计算复杂(无论是依赖CPU运算还是I/O操作)的方法,即使针对相同的参数组合也只需调用一次,之后就可以重用缓存结果,而无需再次实际调用该方法。这种缓存逻辑的实现是透明的,不会对调用者造成任何干扰。

important

这种方法仅适用于那些无论被调用多少次,对于给定的输入(或参数)都能保证返回相同输出(结果)的方法。

缓存抽象提供了其他与缓存相关的操作,例如更新缓存内容或删除一个或所有条目的能力。如果缓存处理的数据在应用程序运行过程中可能会发生变化,这些功能就非常有用。

与Spring框架中的其他服务一样,缓存服务也是一种抽象(而不是缓存实现),它需要使用实际的存储来保存缓存数据——也就是说,这种抽象让你不必编写缓存逻辑,但不提供实际的数据存储机制。这种抽象通过org.springframework.cache CACHEorg.springframework.cache.CacheManager接口得以实现。

Spring提供了几种实现这一抽象的方式:基于JDK java.util.concurrent.ConcurrentMap的缓存、Gemfire缓存、Caffeine,以及符合JSR-107标准的缓存(如Ehcache 3.x)。有关插入其他缓存存储和提供者的更多信息,请参阅插入不同的后端缓存

important

缓存抽象对多线程和多进程环境没有特殊的处理方式,因为这些特性是由缓存实现来处理的。

如果你拥有一个多进程环境(即,一个部署在多个节点上的应用程序),你需要相应地配置你的缓存提供者。根据你的使用场景,可能在几个节点上复制相同的数据就足够了。然而,如果你在应用程序运行过程中更改了数据,你可能需要启用其他的数据传播机制。

缓存某个特定项目,相当于程序化缓存交互中常见的“如果没有找到则继续执行,最终再put”的代码块。在这种情况下不会应用任何锁机制,因此多个线程可以同时尝试加载同一个项目。驱逐(eviction)操作也是如此。如果多个线程同时尝试更新或驱逐数据,那么就可能会导致使用到过时的数据。某些缓存提供者在这方面提供了更高级的功能。有关更多详细信息,请查阅你所使用的缓存提供者的文档。

要使用缓存抽象,你需要处理两个方面:

  • 缓存声明:确定需要缓存的方法及其缓存策略。
  • 缓存配置:存储数据并从中读取数据的后端缓存。