3.5. 创建嵌入式缓存


Data Grid 提供了一个 EmbeddedCacheManager API,可让您以编程方式控制缓存管理器和嵌入式缓存生命周期。

3.5.1. 在项目中添加 Data Grid

将 Data Grid 添加到项目,以便在您的应用程序中创建嵌入的缓存。

先决条件

  • 配置项目以从 Maven 存储库获取数据网格工件。

流程

  • infinispan-core 工件作为依赖项添加到 pom.xml 中,如下所示:
<dependencies>
  <dependency>
    <groupId>org.infinispan</groupId>
    <artifactId>infinispan-core</artifactId>
  </dependency>
</dependencies>

3.5.2. 创建和使用嵌入式缓存

Data Grid 提供了一个 GlobalConfigurationBuilder API,用于控制 Cache Manager 和用于配置缓存的 ConfigurationBuilder API。

先决条件

  • infinispan-core 工件添加为 pom.xml 中的依赖项。

流程

  1. 初始化 CacheManager

    注意

    在创建缓存前,您必须始终调用 cacheManager.start () 方法来初始化 CacheManager。默认构造器为您完成此操作,但构建器的超载版本不会为您这样做。

    缓存管理器也是重量的对象,Data Grid 建议实例化每个 JVM 只有一个实例。

  2. 使用 ConfigurationBuilder API 定义缓存配置。
  3. 使用 getCache ()createCache ()getOrCreateCache () 方法获取缓存。

    Data Grid 建议使用 getOrCreateCache () 方法,因为它在所有节点上创建一个缓存或返回现有的缓存。

  4. 如有必要,对缓存使用 PERMANENT 标志,以在重启后保留。
  5. 通过调用 cacheManager.stop () 方法以释放 JVM 资源并正常关闭任何缓存,以停止 CacheManager
// Set up a clustered Cache Manager.
GlobalConfigurationBuilder global = GlobalConfigurationBuilder.defaultClusteredBuilder();
// Initialize the default Cache Manager.
DefaultCacheManager cacheManager = new DefaultCacheManager(global.build());
// Create a distributed cache with synchronous replication.
ConfigurationBuilder builder = new ConfigurationBuilder();
                     builder.clustering().cacheMode(CacheMode.DIST_SYNC);
// Obtain a volatile cache.
Cache<String, String> cache = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache("myCache", builder.build());
// Stop the Cache Manager.
cacheManager.stop();

getCache () 方法

调用 getCache (String) 方法以获取缓存,如下所示:

Cache<String, String> myCache = manager.getCache("myCache");

前面的操作会创建一个名为 myCache 的缓存(如果尚未存在),并返回它。

使用 getCache () 方法仅在您调用方法的节点上创建缓存。换句话说,它会执行一个本地操作,它必须在集群中的每个节点上调用。通常,在多个节点间部署的应用程序会在初始化过程中获取缓存,以确保缓存都是 对称的,并在每个节点上存在。

createCache () 方法

调用 createCache () 方法,以在整个集群中动态创建缓存。

Cache<String, String> myCache = manager.administration().createCache("myCache", "myTemplate");

前面的操作还会在随后加入集群的任何节点上自动创建缓存。

默认情况下,您使用 createCache () 方法创建的缓存是临时的。如果整个集群关闭,则缓存重启后不会自动创建。

PERMANENT 标志

使用 PERMANENT 标志来确保缓存可以在重启后保留。

Cache<String, String> myCache = manager.administration().withFlags(AdminFlag.PERMANENT).createCache("myCache", "myTemplate");

要使 PERMANENT 标志生效,您必须启用全局状态并设置配置存储提供程序。

有关配置存储供应商的更多信息,请参阅 GlobalStateConfigurationBuilder#configurationStorage ()

3.5.3. Cache API

Data Grid 提供了一个 Cache 接口,它公开简单的方法来添加、检索和删除条目,包括 JDK 的 ConcurrentMap 接口公开的原子机制。根据所使用的缓存模式,调用这些方法会触发多个事情,甚至可能包括将条目复制到远程节点或从远程节点查找条目,或可能缓存存储。

对于简单使用,使用 Cache API 不应与使用 JDK Map API 不同,因此从基于映射到 Data Grid 的缓存的简单内存缓存迁移应该很简单。

Certain Map 方法的性能一致性

与 Data Grid 一起使用时,在 Map 中公开的某些方法具有一定的性能后果,如 size ()value ()keySet ()entrySet ()。有关 keySet、value 和 entrySet 的具体方法,请参阅其 Javadoc 了解更多详情。

试图全局执行这些操作会对性能有很大的影响,并成为可扩展性瓶颈。因此,这些方法应该仅用于信息或调试目的。

应注意,在 withFlags () 方法中使用某些标记可以缓解其中的一些问题,请检查每个方法的文档以了解更多详情。

Mortal 和 Immortal Data

除了仅存储条目外,Data Grid 的缓存 API 允许您向数据附加 mortality 信息。例如,只是使用 put (键,值) 会创建一个 immortal 条目,例如,一个存在于缓存中的条目(永久存在),直到它被删除(或逐出内存以防止耗尽内存)。但是,如果您使用 put (key, value, lifespan, timeunit) 将数据放入缓存中,这会创建一个 mortal 条目,即具有固定生命周期的条目,并在该生命周期后过期。

除了 Lifespan 外,Data Grid 还支持 maxIdle 作为额外的指标,以决定到期。可以使用任何 lifespans 或 maxIdles 的组合。

putForExternalRead 操作

Data Grid 的 Cache 类包含不同的"put"操作,称为 putForExternalRead。当 Data Grid 用作在其他位置保留数据的临时缓存时,此操作特别有用。在大量读取场景中,缓存中的竞争不应延迟实时事务,因为缓存应该只是优化,而不是以某种方式获得。

要达到此目的,putForExternalRead () 充当 put 调用,只有在缓存中不存在密钥时才运行,并在另一个线程尝试同时存储同一密钥时失败。在这个特殊情况下,缓存数据是优化系统的方法,而不需要缓存失败会影响到持续的事务,因此为什么以不同的方式处理失败。putForExternalRead () 被视为快速操作,因为无论它是否成功,它都不会等待任何锁定,因此会立即返回到调用者。

要了解如何使用此操作,让我们来看基本的示例。试想一下,个人实例的缓存,每个由 PersonId 的密钥,其数据源自于单独的数据存储中。以下代码显示了在此示例上下文中使用 putForExternalRead 的最常见模式:

// Id of the person to look up, provided by the application
PersonId id = ...;

// Get a reference to the cache where person instances will be stored
Cache<PersonId, Person> cache = ...;

// First, check whether the cache contains the person instance
// associated with with the given id
Person cachedPerson = cache.get(id);

if (cachedPerson == null) {
   // The person is not cached yet, so query the data store with the id
   Person person = dataStore.lookup(id);

   // Cache the person along with the id so that future requests can
   // retrieve it from memory rather than going to the data store
   cache.putForExternalRead(id, person);
} else {
   // The person was found in the cache, so return it to the application
   return cachedPerson;
}

请注意,putForExternalRead 不应用作使用源自应用程序执行的新 Person 实例更新缓存的机制(例如,来自修改人员地址的事务)。更新缓存的值时,请使用标准 放置 操作,否则可能会出现缓存损坏数据的可能性。

3.5.3.1. AdvancedCache API

除了简单缓存接口外,Data Grid 还提供 AdvancedCache 接口,并提供给扩展作者。AdvancedCache 提供了访问某些内部组件,并应用标志来改变某些缓存方法的默认行为。以下代码片段描述了如何获取 AdvancedCache:

AdvancedCache advancedCache = cache.getAdvancedCache();
3.5.3.1.1. 标记

标志应用到常规缓存方法,以更改某些方法的行为。有关所有可用标志及其效果的列表,请查看 标记 枚举。使用 AdvancedCache.withFlags () 应用标志。此 builder 方法可用于将任意数量的标记应用到缓存调用,例如:

advancedCache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_LOCKING)
   .withFlags(Flag.FORCE_SYNCHRONOUS)
   .put("hello", "world");

3.5.3.2. Asynchronous API

除了同步的 API 方法(如 Cache.put ()Cache.remove () 等)之外,数据网格也有一个异步的非阻塞 API,您可以在其中实现相同的结果。

这些方法的命名方式与阻塞计数器类似,并附加"Async"。  例如,Cache.putAsync ()Cache.removeAsync () 等。  这些异步对应部分返回一个包含操作实际结果的 CompletableFuture

例如,在 cache 参数中,在 Cache<String, String>, Cache.put (String key, String value) 返回 String while Cache.putAsync (String key) returns Complet ableFuture<String&gt;。

3.5.3.2.1. 为什么使用这种 API?

非阻塞 API 非常强大,它们提供了所有同步通信保证 - 能够处理通信故障和例外 - 在调用完成后不需要阻止。  这可让您更好地利用系统中的并行性。  例如:

Set<CompletableFuture<?>> futures = new HashSet<>();
futures.add(cache.putAsync(key1, value1)); // does not block
futures.add(cache.putAsync(key2, value2)); // does not block
futures.add(cache.putAsync(key3, value3)); // does not block

// the remote calls for the 3 puts will effectively be executed
// in parallel, particularly useful if running in distributed mode
// and the 3 keys would typically be pushed to 3 different nodes
// in the cluster

// check that the puts completed successfully
for (CompletableFuture<?> f: futures) f.get();
3.5.3.2.2. 哪些进程实际发生在异步中?

Data Grid 中有 4 个事情,它们被视为典型写入操作的关键路径。这些是成本顺序:

  • 网络调用
  • Marshalling
  • 写入缓存存储(可选)
  • 锁定

使用 async 方法将取网络调用和划分出关键路径。  然而,出于各种技术原因,写入缓存存储和获取锁定,但仍然出现在调用者的线程中。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.