7.2. 缓存存储实施


Data Grid 提供几个您可以使用的缓存存储实现。或者,您可以提供自定义缓存存储。

7.2.1. Cluster Cache Loaders

ClusterCacheLoader 从其他 Data Grid 集群成员检索数据,但不保留数据。换句话说,ClusterCacheLoader 不是缓存存储。

ClusterCacheLoader 提供了一个非阻塞部分替代状态传输。如果本地节点上没有这些密钥,则 ClusterCacheLoader 会从其他节点获取密钥,这与 lazily 加载缓存内容类似。

下图也适用于 ClusterCacheLoader

  • 预加载不会生效(preload=true)。
  • 不支持获取持久性状态(fetch-state=true)。
  • 不支持分段。
警告

ClusterLoader 已被弃用,并将在以后的发行版本中删除。

声明性配置

<persistence>
   <cluster-loader remote-timeout="500"/>
</persistence>
Copy to Clipboard Toggle word wrap

编程配置

ConfigurationBuilder b = new ConfigurationBuilder();
b.persistence()
    .addClusterLoader()
    .remoteCallTimeout(500);
Copy to Clipboard Toggle word wrap

7.2.2. 单个文件缓存存储

单个文件缓存存储( SingleFileStore )将数据持久保留到文件。Data Grid 还维护一个键内存中索引,而键和值存储在 文件中。默认情况下,单文件缓存存储被分段,这意味着 Data Grid 为每个网段创建单独的文件。

因为 SingleFileStore 保留了键和值位置的内存索引,所以它需要额外的内存,具体取决于密钥大小和键数。因此,对于密钥大的用例,不建议使用 SingleFileStore

在某些情况下,SingleFileStore 也可以变得碎片。如果值的大小持续增加,则不会使用单个文件中的可用空间,但条目会附加到文件的末尾。只有在条目可以容纳它时,才会使用文件中的可用空间。同样,如果您从内存中删除所有条目,则单个文件存储的大小不会减小,或者被碎片整理。

声明性配置

<persistence>
   <file-store max-entries="5000"/>
</persistence>
Copy to Clipboard Toggle word wrap

编程配置

  • 对于嵌入式部署,请执行以下操作:
ConfigurationBuilder b = new ConfigurationBuilder();
b.persistence()
    .addSingleFileStore()
    .maxEntries(5000);
Copy to Clipboard Toggle word wrap
  • 对于服务器部署,请执行以下操作:
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.configuration.NearCacheMode;
...

ConfigurationBuilder builder = new ConfigurationBuilder();
builder
  .remoteCache("mycache")
    .configuration("<infinispan><cache-container><distributed-cache name=\"mycache\"><persistence><file-store max-entries=\"5000\"/></persistence></distributed-cache></cache-container></infinispan>");
Copy to Clipboard Toggle word wrap

分段

单个文件缓存支持分段,并为每个片段创建一个单独的实例,这会在您配置的路径中生成多个目录。每个目录都是代表数据映射的网段的数字。

7.2.3. 基于 JDBC 字符串的缓存存储

基于 JDBC 字符串的缓存存储 JdbcStringBasedStore,使用 JDBC 驱动程序在底层数据库中加载和存储值。

JdbcStringBasedStore 将每个条目存储在表中自己的行中,以提高并发负载的吞吐量。JdbcStringBasedStore 还使用一个简单的一对一映射,它使用 key-to-string-mapper 接口将每个键映射到 String 对象。

Data Grid 提供了一个默认的实现,即 DefaultTwoWayKey2StringMapper,它处理原语类型。

注意

默认情况下,Data Grid 共享不会被存储,这意味着集群中的所有节点都写入到每个更新上的底层存储。如果只希望操作一次写入底层数据库,您必须将 JDBC 存储配置为共享。

分段

JdbcStringBasedStore 默认使用分段,并且需要数据库表中的列来代表条目所属的网段。

7.2.3.1. connection Factories

JdbcStringBasedStore 依赖于 ConnectionFactory 实现来连接数据库。

Data Grid 提供以下 ConnectionFactory 实现:

PooledConnectionFactoryConfigurationBuilder

基于通过 PooledConnectionFactoryConfiguration 配置的 Agroal 的连接工厂。

或者,您可以指定前缀为 org.infinispan.agroal. 的配置属性,如下例所示:

org.infinispan.agroal.metricsEnabled=false

org.infinispan.agroal.minSize=10
org.infinispan.agroal.maxSize=100
org.infinispan.agroal.initialSize=20
org.infinispan.agroal.acquisitionTimeout_s=1
org.infinispan.agroal.validationTimeout_m=1
org.infinispan.agroal.leakTimeout_s=10
org.infinispan.agroal.reapTimeout_m=10

org.infinispan.agroal.metricsEnabled=false
org.infinispan.agroal.autoCommit=true
org.infinispan.agroal.jdbcTransactionIsolation=READ_COMMITTED
org.infinispan.agroal.jdbcUrl=jdbc:h2:mem:PooledConnectionFactoryTest;DB_CLOSE_DELAY=-1
org.infinispan.agroal.driverClassName=org.h2.Driver.class
org.infinispan.agroal.principal=sa
org.infinispan.agroal.credential=sa
Copy to Clipboard Toggle word wrap

然后,您可以通过 PooledConnectionFactoryConfiguration.propertyFile 将 Data Grid 配置为使用您的属性文件。

注意

您应该将 PooledConnectionFactory 用于独立部署,而不是 servlet 容器中的部署。

ManagedConnectionFactoryConfigurationBuilder

可与受管环境(如应用服务器)一起使用的连接工厂。此连接工厂可以探索 JNDI 树中的可配置位置,并将连接管理委派给 DataSource

SimpleConnectionFactoryConfigurationBuilder

一个连接工厂,用于在每个调用时创建数据库连接。您应该只对测试或开发环境使用此连接工厂。

7.2.3.2. 基于 JDBC 字符串的缓存存储配置

您可以以编程方式或声明性地配置 JdbcStringBasedStore

声明性配置

  • 使用 PooledConnectionFactory
<persistence>
   <string-keyed-jdbc-store xmlns="urn:infinispan:config:store:jdbc:11.0" shared="true">
      <connection-pool connection-url="jdbc:h2:mem:infinispan_string_based;DB_CLOSE_DELAY=-1"
                       username="sa"
                       driver="org.h2.Driver"/>
      <string-keyed-table drop-on-exit="true"
                          prefix="ISPN_STRING_TABLE">
         <id-column name="ID_COLUMN" type="VARCHAR(255)" />
         <data-column name="DATA_COLUMN" type="BINARY" />
         <timestamp-column name="TIMESTAMP_COLUMN" type="BIGINT" />
         <segment-column name="SEGMENT_COLUMN" type="INT" />
      </string-keyed-table>
   </string-keyed-jdbc-store>
</persistence>
Copy to Clipboard Toggle word wrap
  • 使用 ManagedConnectionFactory
<persistence>
  <string-keyed-jdbc-store xmlns="urn:infinispan:config:store:jdbc:11.0" shared="true">
    <data-source jndi-url="java:/StringStoreWithManagedConnectionTest/DS" />
    <string-keyed-table drop-on-exit="true"
                        create-on-start="true"
                        prefix="ISPN_STRING_TABLE">
        <id-column name="ID_COLUMN" type="VARCHAR(255)" />
        <data-column name="DATA_COLUMN" type="BINARY" />
        <timestamp-column name="TIMESTAMP_COLUMN" type="BIGINT" />
        <segment-column name="SEGMENT_COLUMN" type="INT"/>
    </string-keyed-table>
  </string-keyed-jdbc-store>
</persistence>
Copy to Clipboard Toggle word wrap

编程配置

  • 使用 PooledConnectionFactory
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.persistence().addStore(JdbcStringBasedStoreConfigurationBuilder.class)
      .fetchPersistentState(false)
      .ignoreModifications(false)
      .purgeOnStartup(false)
      .shared(true)
      .table()
         .dropOnExit(true)
         .createOnStart(true)
         .tableNamePrefix("ISPN_STRING_TABLE")
         .idColumnName("ID_COLUMN").idColumnType("VARCHAR(255)")
         .dataColumnName("DATA_COLUMN").dataColumnType("BINARY")
         .timestampColumnName("TIMESTAMP_COLUMN").timestampColumnType("BIGINT")
         .segmentColumnName("SEGMENT_COLUMN").segmentColumnType("INT")
      .connectionPool()
         .connectionUrl("jdbc:h2:mem:infinispan_string_based;DB_CLOSE_DELAY=-1")
         .username("sa")
         .driverClass("org.h2.Driver");
Copy to Clipboard Toggle word wrap
  • 使用 ManagedConnectionFactory
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.persistence().addStore(JdbcStringBasedStoreConfigurationBuilder.class)
      .fetchPersistentState(false)
      .ignoreModifications(false)
      .purgeOnStartup(false)
      .shared(true)
      .table()
         .dropOnExit(true)
         .createOnStart(true)
         .tableNamePrefix("ISPN_STRING_TABLE")
         .idColumnName("ID_COLUMN").idColumnType("VARCHAR(255)")
         .dataColumnName("DATA_COLUMN").dataColumnType("BINARY")
         .timestampColumnName("TIMESTAMP_COLUMN").timestampColumnType("BIGINT")
         .segmentColumnName("SEGMENT_COLUMN").segmentColumnType("INT")
      .dataSource()
         .jndiUrl("java:/StringStoreWithManagedConnectionTest/DS");
Copy to Clipboard Toggle word wrap

7.2.4. JPA Cache Stores

JPA (Java Persistence API)缓存存储、JpaStore、使用正式模式来持久保留数据。然后,其他应用程序可以从持久性存储中读取,以从 Data Grid 加载数据。但是,其他应用程序不应与 Data Grid 同时使用持久性存储。

使用 JpaStore 时,您应该考虑以下问题:

  • 密钥应该是实体的 ID。值应该是实体对象。
  • 只允许单个 @Id@EmbeddedId 注释。
  • 不支持使用 @GeneratedValue 注释自动生成的 ID。
  • 所有条目都存储为 immortal。
  • JpaStore 不支持分段。

声明性配置

<local-cache name="vehicleCache">
   <persistence passivation="false">
      <jpa-store xmlns="urn:infinispan:config:store:jpa:11.0"
         persistence-unit="org.infinispan.persistence.jpa.configurationTest"
         entity-class="org.infinispan.persistence.jpa.entity.Vehicle">
		/>
   </persistence>
</local-cache>
Copy to Clipboard Toggle word wrap

Expand
参数描述

persistence-unit

指定 JPA 配置文件 persistence.xml 中的 JPA persistence 单元名称,其中包含 JPA 实体类。

entity-class

指定应该存储在此缓存中的完全限定域名。只允许一个类。

编程配置

Configuration cacheConfig = new ConfigurationBuilder().persistence()
             .addStore(JpaStoreConfigurationBuilder.class)
             .persistenceUnitName("org.infinispan.loaders.jpa.configurationTest")
             .entityClass(User.class)
             .build();
Copy to Clipboard Toggle word wrap

Expand
参数描述

persistenceUnitName

指定 JPA 配置文件 persistence.xml 中的 JPA persistence 单元名称,其中包含 JPA 实体类。

entityClass

指定应该存储在此缓存中的完全限定域名。只允许一个类。

7.2.4.1. JPA Cache Store Usage Example

本节提供了使用 JPA 缓存存储的示例。

先决条件

  • 配置数据网格以汇总您的 JPA 实体。默认情况下,Data Grid 使用 ProtoStream 进行 marshalling Java 对象。要 marshall JPA 实体,您必须创建一个 SerializationContextInitializer 实现,该实现使用 SerializationContext 注册 .proto 模式和 marshaller。

流程

  1. persistence.xml 中定义持久性单元 "my PersistenceUnit"。

    <persistence-unit name="myPersistenceUnit">
    	...
    </persistence-unit>
    Copy to Clipboard Toggle word wrap
  2. 创建用户实体类。

    @Entity
    public class User implements Serializable {
    	@Id
    	private String username;
    	private String firstName;
    	private String lastName;
    
    	...
    }
    Copy to Clipboard Toggle word wrap
  3. 使用 JPA 缓存存储配置名为"usersCache"的缓存。

    然后,您可以将缓存"usersCache"配置为使用 JPA Cache Store,以便在将数据放入缓存中时,数据将基于 JPA 配置保留到数据库中。

    EmbeddedCacheManager cacheManager = ...;
    
    Configuration cacheConfig = new ConfigurationBuilder().persistence()
                .addStore(JpaStoreConfigurationBuilder.class)
                .persistenceUnitName("org.infinispan.loaders.jpa.configurationTest")
                .entityClass(User.class)
                .build();
    cacheManager.defineCache("usersCache", cacheConfig);
    
    Cache<String, User> usersCache = cacheManager.getCache("usersCache");
    usersCache.put("raytsang", new User(...));
    Copy to Clipboard Toggle word wrap
    • 使用 JPA 缓存存储的缓存只能存储一种类型的数据,如下例所示:

      Cache<String, User> usersCache = cacheManager.getCache("myJPACache");
      // Cache is configured for the User entity class
      usersCache.put("username", new User());
      // Cannot configure caches to use another entity class with JPA cache stores
      Cache<Integer, Teacher> teachersCache = cacheManager.getCache("myJPACache");
      teachersCache.put(1, new Teacher());
      // The put request does not work for the Teacher entity class
      Copy to Clipboard Toggle word wrap
    • @EmbeddedId 注释允许您使用复合键,如下例所示:

      @Entity
      public class Vehicle implements Serializable {
      	@EmbeddedId
      	private VehicleId id;
      	private String color;	...
      }
      
      @Embeddable
      public class VehicleId implements Serializable
      {
      	private String state;
      	private String licensePlate;
      	...
      }
      Copy to Clipboard Toggle word wrap

7.2.5. 远程缓存存储

远程缓存存储 RemoteStore,使用 Hot Rod 协议在 Data Grid 集群中存储数据。

以下是一个 RemoteStore 配置示例,它将数据存储在两个 Data Grid Server 实例(名为 "one" 和 "two" 的缓存中:

注意

如果您将远程缓存存储配置为共享,则无法预加载数据。换句话说,如果您的配置中是 shared="true",则必须设置 preload="false"

声明性配置

<persistence>
   <remote-store xmlns="urn:infinispan:config:store:remote:11.0" cache="mycache" raw-values="true">
      <remote-server host="one" port="12111" />
      <remote-server host="two" />
      <connection-pool max-active="10" exhausted-action="CREATE_NEW" />
      <write-behind />
   </remote-store>
</persistence>
Copy to Clipboard Toggle word wrap

编程配置

ConfigurationBuilder b = new ConfigurationBuilder();
b.persistence().addStore(RemoteStoreConfigurationBuilder.class)
      .fetchPersistentState(false)
      .ignoreModifications(false)
      .purgeOnStartup(false)
      .remoteCacheName("mycache")
      .rawValues(true)
.addServer()
      .host("one").port(12111)
      .addServer()
      .host("two")
      .connectionPool()
      .maxActive(10)
      .exhaustedAction(ExhaustedAction.CREATE_NEW)
      .async().enable();
Copy to Clipboard Toggle word wrap

分段

RemoteStore 支持分段,并且可以按网段发布密钥和条目,从而提高批量操作的效率。但是,只有 Data Grid Hot Rod 协议版本 2.3 或更高版本才提供分段。

警告

当您为 RemoteStore 启用分段时,它会使用您在 Data Grid 服务器配置中定义的片段数量。

如果源缓存被分段并使用与 RemoteStore 不同的片段数,则返回不正确的值用于批量操作。在这种情况下,您应该禁用 RemoteStore 的分段。

7.2.6. RocksDB Cache Stores

RocksDB 为高并发环境提供具有高性能和可靠性的基于键值的文件系统存储。

RocksDB 缓存存储( RocksDBStore )使用两个数据库。一个数据库为内存中的数据提供主要缓存存储;其他数据库包含 Data Grid 从内存中过期的条目。

声明性配置

<local-cache name="vehicleCache">
   <persistence>
      <rocksdb-store xmlns="urn:infinispan:config:store:rocksdb:11.0" path="rocksdb/data">
         <expiration path="rocksdb/expired"/>
      </rocksdb-store>
   </persistence>
</local-cache>
Copy to Clipboard Toggle word wrap

编程配置

Configuration cacheConfig = new ConfigurationBuilder().persistence()
				.addStore(RocksDBStoreConfigurationBuilder.class)
				.build();
EmbeddedCacheManager cacheManager = new DefaultCacheManager(cacheConfig);

Cache<String, User> usersCache = cacheManager.getCache("usersCache");
usersCache.put("raytsang", new User(...));
Copy to Clipboard Toggle word wrap

Properties props = new Properties();
props.put("database.max_background_compactions", "2");
props.put("data.write_buffer_size", "512MB");

Configuration cacheConfig = new ConfigurationBuilder().persistence()
				.addStore(RocksDBStoreConfigurationBuilder.class)
				.location("rocksdb/data")
				.expiredLocation("rocksdb/expired")
        .properties(props)
				.build();
Copy to Clipboard Toggle word wrap
Expand
表 7.1. RocksDBStore 配置参数
参数描述

位置

指定提供主缓存存储的 RocksDB 数据库的路径。如果您没有设置位置,则会自动创建它。请注意,路径必须相对于全局持久位置。

expiredLocation

指定用于为过期数据提供缓存存储的 RocksDB 数据库的路径。如果您没有设置位置,则会自动创建它。请注意,路径必须相对于全局持久位置。

expiryQueueSize

为过期条目设置内存中队列的大小。当队列达到大小时,Data Grid flushes 已过期到 RocksDB 缓存存储中。

clearThreshold

在删除和重新初始化(re-init) RocksDB 数据库前设置最大条目数。对于较小的缓存存储,迭代所有条目并删除每个条目可以更快速的方法。

RocksDB 调优参数

您还可以指定以下 RocksDB 调优参数:

  • compressionType
  • blockSize
  • cacheSize

RocksDB 配置属性

另外,还可在配置中设置属性,如下所示:

  • 带有 数据库 的前缀属性,用于调整和调优 RocksDB 数据库。
  • 数据 添加前缀属性,以配置 RocksDB 存储数据的列系列。
<property name="database.max_background_compactions">2</property>
<property name="data.write_buffer_size">64MB</property>
<property name="data.compression_per_level">kNoCompression:kNoCompression:kNoCompression:kSnappyCompression:kZSTD:kZSTD</property>
Copy to Clipboard Toggle word wrap

分段

RocksDBStore 支持分段,并为每个网段创建单独的列系列。分段 RocksDB 缓存存储提高了查找性能和迭代,但写入操作的性能略低。

注意

您不应该配置超过几百个片段。RocksDB 没有设计为无数列系列。太多片段也会显著增加缓存存储启动时间。

7.2.7. soft-Index 文件存储

Soft-Index 文件缓存存储( SoftIndexFileStore )提供基于文件的本地存储。

SoftIndexFileStore 是一个 Java 实现,它使用使用 Java 软引用缓存内存的 B+ Tree 变体。B+ Tree,名为 Index,将文件系统上的一个文件卸载到单个文件,每次缓存存储重启时都会进行重新构建。

SoftIndexFileStore 将数据存储在一组文件中,而不是单个文件中。当任何文件使用量低于 50% 时,文件中的条目会被覆盖给另一个文件,然后删除该文件。

SoftIndexFileStore 在一组使用附加方法写入的文件中保留数据。因此,如果您在传统的 magnetic 磁盘中使用 SoftIndexFileStore,则不需要在编写突发条目时看到它。

SoftIndexFileStore 中的大多数结构都绑定了,因此内存不足异常不会带来风险。您还可以为同时打开文件配置限制。

默认情况下,索引中节点的大小限制为 4096 字节。这个大小还限制密钥长度;更精确地限制序列化密钥的长度。因此,您无法使用超过节点大小的密钥 15 字节。另外,密钥长度存储为 "short",这会将密钥长度限制为 32767 字节。如果键在进行序列化后较长,SoftIndexFileStore 会抛出异常。

SoftIndexFileStore 无法检测到过期的条目,这可能导致过度使用文件系统中的空间。

注意

AdvancedStore.purgeExpired () 没有在 SoftIndexFileStore 中实施。

声明性配置

<persistence>
    <soft-index-file-store xmlns="urn:infinispan:config:store:soft-index:11.0">
        <index path="testCache/index" />
        <data path="testCache/data" />
    </soft-index-file-store>
</persistence>
Copy to Clipboard Toggle word wrap

编程配置

ConfigurationBuilder b = new ConfigurationBuilder();
b.persistence()
    .addStore(SoftIndexFileStoreConfigurationBuilder.class)
        .indexLocation("testCache/index");
        .dataLocation("testCache/data")
Copy to Clipboard Toggle word wrap

分段

soft-Index 文件缓存存储支持分段,并为每个片段创建一个单独的实例,这会导致您配置的路径中的多个目录。每个目录都是代表数据映射的网段的数字。

7.2.8. 实施自定义缓存存储

您可以通过 Data Grid persistent SPI 创建自定义缓存存储。

7.2.8.1. Data Grid Persistence SPI

Data Grid Service Provider Interface (SPI)通过 NonBlockingStore 接口为外部存储启用读取和写入操作,并具有以下功能:

JCache 兼容供应商的可移植性
Data Grid 使用处理阻塞代码的适配器维护 NonBlockingStore 接口和 JSR-107 JCache 规格之间的兼容性。
简化的事务集成
Data Grid 会自动处理锁定,因此您的实施不需要协调对持久性存储的并发访问。根据您使用的锁定模式,通常不会发生对同一密钥的并发写入。但是,您应该预期持久性存储上的操作源自多个线程,并创建实施来容许此行为。
并行迭代
借助 Data Grid,您可以并行迭代具有多个线程的持久性存储中的条目。
减少序列化结果,从而减少 CPU 用量
Data Grid 以序列化格式公开存储的条目,可以远程传输。因此,Data Grid 不需要从持久性存储检索的反序列化条目,然后在写入有线时再次序列化。

7.2.8.2. 创建缓存存储

通过实施 NonBlockingStore 接口创建自定义缓存存储。

  1. 实施适当的 Data Grid 持久 SPI。
  2. 如果有自定义配置,给存储类标上 @ConfiguredBy 注释。
  3. 如果需要,创建自定义缓存存储配置和构建器。

    1. 扩展 AbstractStoreConfigurationAbstractStoreConfigurationBuilder.
    2. (可选)在存储配置类中添加以下注解,以确保您的自定义配置构建器从 XML 解析您的缓存存储配置:

      • @ConfigurationFor
      • @BuiltBy

        如果没有添加这些注解,则 CustomStoreConfigurationBuilder 会解析 AbstractStoreConfiguration 中定义的通用存储属性,并且忽略任何其他元素。

        注意

        如果配置没有声明 @ConfigurationFor 注释,则 Data Grid 初始化缓存时会记录警告消息。

7.2.8.3. 配置数据网格以使用自定义存储

创建自定义缓存存储实施后,将 Data Grid 配置为使用它。

声明性配置

<local-cache name="customStoreExample">
  <persistence>
    <store class="org.infinispan.persistence.dummy.DummyInMemoryStore" />
  </persistence>
</local-cache>
Copy to Clipboard Toggle word wrap

编程配置

Configuration config = new ConfigurationBuilder()
            .persistence()
            .addStore(CustomStoreConfigurationBuilder.class)
            .build();
Copy to Clipboard Toggle word wrap

7.2.8.4. 部署自定义缓存存储

您可以将自定义缓存打包到 JAR 文件中,并将它们部署到 Data Grid 服务器中,如下所示:

  1. 将自定义缓存存储实施打包在 JAR 文件中。
  2. 将您的 JAR 文件添加到 Data Grid 服务器的 server/lib 目录中。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

Theme

© 2025 Red Hat