第 5 章 管理内存


配置数据容器,其中 Data Grid 存储条目。指定缓存条目的编码,将数据保存在非堆内存中,并使用驱除或过期策略来只在内存中保留活动条目。

5.1. 配置驱除和过期

驱除和过期是通过删除旧、未使用的条目来清理数据容器的两个策略。虽然驱除和过期也类似,但它们有一些重要的区别。

  • 当容器大于配置的阈值时,Data Grid 驱除可让 Data Grid 通过删除条目来控制数据容器的大小。
  • mvapich 过期日期限制了存在时间条目的数量。Data Grid 使用调度程序定期删除过期条目。过期但还没有被删除的条目会在访问时立即被删除 ; 在这种情况下,过期条目的 get () 调用会返回 "null" 值。
  • criu 驱除是 Data Grid 节点的本地驱除。
  • mvapich 过期时间跨数据网格集群发生。
  • 您可以组合使用驱除和过期,也可以相互独立使用。
  • 您可以在 infinispan.xml 中配置驱除和过期,以对条目应用缓存范围默认值。
  • 您可以为特定条目显式定义过期设置,但您无法基于每个条目定义驱除。
  • 您可以手动驱除条目并手动触发过期。

5.1.1. 驱除

驱除允许您通过从内存中删除条目来控制数据容器的大小。驱除会一次从数据容器丢弃一个条目,并且对发生它的节点是本地的。

重要

驱除会从内存中删除条目,而不是从持久性缓存存储中删除条目。为确保在 Data Grid 驱除它们后条目仍然可用,并防止数据不一致,您应该配置持久的缓存存储。

Data Grid 驱除依赖于两个配置:

  • 数据容器的最大大小。
  • 删除条目的策略。

数据容器大小

借助数据网格,您可以将条目存储在 Java 堆或原生内存(off-heap)中,并为数据容器设置最大大小。

您可以通过以下两种方式之一配置数据容器的最大大小:

  • 条目总数(max-count)。
  • 最大内存量(max-size)。

    要根据内存量执行驱除,您可以以字节为单位定义最大大小。因此,您必须使用二进制存储格式(如 application/x-protostream )对条目进行编码。

驱除缓存条目

当您配置 内存时,Data Grid 大约是数据容器的当前内存用量。添加或修改条目时,Data Grid 会将数据容器的当前内存用量与最大大小进行比较。如果大小超过最大值,Data Grid 将执行驱除。

在线程中立即发生驱除,添加超过最大大小的条目。

请考虑以下配置作为示例:

<memory max-count="50"/>

在这种情况下,缓存可以有总计 50 个条目。缓存达到条目总数后,写入操作会触发 Data Grid 来执行驱除。

驱除策略

策略控制数据网格执行驱除的方式。您可以手动执行驱除,或将 Data Grid 配置为执行以下操作之一:

  • 删除旧条目来为新条目腾出空间。
  • 抛出 ContainerFullException 并防止创建新条目。

    异常驱除策略只适用于使用 2 阶段提交的事务缓存,不适用于 1 阶段提交或同步优化。

注意

Data Grid 包括 Caffeine 缓存库,它实现了 Least Frequently Used (LFU)缓存替换算法(称为 TinyLFU)。对于非堆存储,Data Grid 使用 Least Recently Used (LRU)算法的自定义实现。

5.1.1.1. 为数据网格缓存配置总条目数

将缓存条目的数据容器的大小限制为条目总数。

流程

  1. 使用适当的存储格式配置数据网格缓存编码。
  2. 指定缓存在 Data Grid 执行驱除前可以包含的条目总数。

    • declarative :设置 max-count 属性。
    • programmatic :调用 maxCount () 方法。
  3. 配置驱除策略,以控制 Data Grid 如何删除条目。

    • declarative :设置 when-full 属性。
    • Programmatic :调用 whenFull () 方法。

声明性配置

<local-cache name="maximum_count">
  <encoding media-type="application/x-protostream"/>
  <memory max-count="500" when-full="REMOVE"/>
</local-cache>

编程配置

ConfigurationBuilder cfg = new ConfigurationBuilder();

cfg
  .encoding()
    .mediaType("application/x-protostream")
  .memory()
    .maxCount(500)
    .whenFull(EvictionStrategy.REMOVE)
  .build());

5.1.1.2. 为数据网格缓存配置最大内存量

将缓存条目的数据容器的大小限制为最大内存量。

流程

  1. 将您的数据网格缓存配置为使用支持二进制编码的存储格式。

    您必须使用二进制存储格式根据最大内存量执行驱除。

  2. 配置缓存在数据网格执行驱除前可以使用的最大内存量(以字节为单位)。

    • declarative :设置 max-size 属性。
    • programmatic :使用 maxSize () 方法。
  3. (可选)指定测量的字节单位。默认值为 B (字节)。对于支持的单元,请参阅 配置模式。
  4. 配置驱除策略,以控制 Data Grid 如何删除条目。

    • declarative :设置 when-full 属性。
    • Programmatic :使用 whenFull () 方法。

声明性配置

<local-cache name="maximum_size">
  <encoding media-type="application/x-protostream"/>
  <memory max-size="1.5GB" when-full="REMOVE"/>
</local-cache>

编程配置

ConfigurationBuilder cfg = new ConfigurationBuilder();

cfg
  .encoding()
    .mediaType("application/x-protostream")
  .memory()
    .maxSize("1.5GB")
    .whenFull(EvictionStrategy.REMOVE)
  .build());

5.1.1.3. 驱除示例

将驱除配置为缓存定义的一部分。

默认内存配置

不启用驱除,这是默认配置。Data Grid 将缓存条目作为对象存储在 JVM 堆中。

<distributed-cache name="default_memory">
  <memory />
</distributed-cache>

根据条目总数进行驱除

Data Grid 将缓存条目作为对象存储在 JVM 堆中。当数据容器中有 100 个条目,Data Grid 会收到创建新条目的请求时发生驱除:

<distributed-cache name="total_number">
  <memory max-count="100"/>
</distributed-cache>

基于驱除的最大大小(以字节为单位)

如果您使用二进制存储格式对缓存条目进行编码,例如: application/x-protostream 格式,请将缓存条目存储为 byte[] 阵列。

在以下示例中,当数据容器的大小达到 500 MB (megabytes)时,Data Grid 会执行驱除,并获得创建新条目的请求:

<distributed-cache name="binary_storage">
  <!-- Encodes the cache with a binary storage format. -->
  <encoding media-type="application/x-protostream"/>
  <!-- Bounds the data container to a maximum size in MB (megabytes). -->
  <memory max-size="500 MB"/>
</distributed-cache>

off-heap 存储

Data Grid 将缓存条目存储为原生内存的字节数。当数据容器中有 100 个条目,Data Grid 会收到创建新条目的请求时发生驱除:

<distributed-cache name="off_heap">
  <memory storage="OFF_HEAP" max-count="100"/>
</distributed-cache>

带有例外策略的 off-heap 存储

Data Grid 将缓存条目存储为原生内存的字节数。当数据容器中有 100 个条目,并且 Data Grid 获取创建新条目的请求时,它会抛出异常,且不允许新条目:

<distributed-cache name="eviction_exception">
  <memory storage="OFF_HEAP" max-count="100" when-full="EXCEPTION"/>
</distributed-cache>

手动驱除

Data Grid 将缓存条目作为对象存储在 JVM 堆中。驱除没有被启用,而是使用 evict () 方法手动执行。

提示

此配置可防止在启用传递但没有配置驱除时发出警告信息。

<distributed-cache name="eviction_manual">
  <memory when-full="MANUAL"/>
</distributed-cache>

使用驱除进行传递

当数据网格驱除条目时,传递保留数据到缓存存储。如果启用了传递,您应该始终启用驱除,例如:

<distributed-cache name="passivation">
  <persistence passivation="true">
   <!-- Persistence configuration goes here. -->
  </persistence>
  <memory max-count="100"/>
</distributed-cache>

参考

5.1.2. 过期

当过期达到以下时间限制之一时,过期会从缓存中删除条目:

Lifespan
设置条目可以存在的最大时间。
最大闲置

指定条目可以保持闲置的时长。如果没有为条目发生操作,它们就变为空闲状态。

重要

最大闲置过期时间目前不支持带有持久性缓存存储的缓存配置。

当使用基于例外的驱除策略时,会过期但还没有从缓存数中删除到数据容器大小的条目。

5.1.2.1. Expiration 工作方式

当您配置过期时,Data Grid 使用用来决定条目何时过期的元数据存储密钥。

  • Lifespan 使用 创建 时间戳,以及 lifespan 配置 属性的值。
  • 最大闲置 使用最后使用 的时间戳和 max-idle 配置属性的值。

Data Grid 检查是否设置了 lifespan 或 maximum idle 元数据,然后将值与当前时间进行比较。

如果 (creation + lifespan < currentTime)(lastUsed + maxIdle < currentTime),则 Data Grid 会检测到条目已过期。

每当被过期者访问或找到条目时,都会发生过期。

例如,k1 达到最大闲置时间,客户端发出 Cache.get (k1) 请求。在这种情况下,Data Grid 会检测到条目已过期,并从数据容器中删除它。Cache.get () 返回 null

Data Grid 还过期了来自缓存存储的条目,但仅具有寿命到期。最大闲置过期时间不适用于缓存存储。如果是缓存加载程序,Data Grid 无法使条目过期,因为加载程序只能从外部存储读取。

注意

只要 用于缓存条目,Data Grid 增加了过期元数据。这可能会将密钥的大小增加到 32 字节。

5.1.2.2. expiration Reaper

Data Grid 使用定期运行的已回收线程来检测和删除过期条目。expiration takinger 可确保不再被访问的过期条目被删除。

Data Grid ExpirationManager 接口处理过期时间,并公开 processExpiration () 方法。

在某些情况下,您可以通过调用 processExpiration () 来禁用过期程序并手动使条目过期;例如,如果您使用本地缓存模式以及定期运行维护线程的自定义应用程序。

重要

如果您使用集群缓存模式,则不应禁用过期时间。

在使用缓存存储时,Data Grid 总是使用 expiration 回收程序。在这种情况下,您无法禁用它。

5.1.2.3. 最大空闲和集群缓存

因为最大闲置过期时间依赖于缓存条目的最后一次访问时间,所以集群缓存模式有一些限制。

随着寿命到期,缓存条目的创建时间提供在集群缓存之间保持一致的值。例如,所有节点上的 k1 创建时间始终相同。

对于使用集群缓存的最大闲置过期时间,所有节点上的条目最后一次访问时间并不相同。为确保条目在集群中有相同的相对访问时间,Data Grid 会在访问密钥时向所有所有者发送 touch 命令。

Data Grid send 的 touch 命令有以下注意事项:

  • cache.get () 请求不会返回,直到所有 touch 命令完成为止。这个同步行为会增加客户端请求的延迟。
  • touch 命令还会更新所有所有者上的缓存条目的"集中访问"元数据,用于数据网格用于驱除。
  • 通过分散的缓存模式,数据网格向所有节点发送 touch 命令,而不只是主和备份所有者。

附加信息

  • 最大闲置过期时间不适用于 invalidation 模式。
  • 集群缓存之间的迭代可能会返回超过最大闲置时间限制的过期条目。这个行为可确保性能,因为迭代过程中不会执行远程调用。另请注意,迭代不会刷新任何过期条目。

5.1.2.4. 过期示例

当您将 Data Grid 配置为过期条目时,您可以为以下设置 lifespan 和最大闲置时间:

  • 缓存中的所有条目(缓存范围)。您可以在 infinispan.xml 中配置缓存范围的过期时间,或者以编程方式使用 ConfigurationBuilder
  • 每个条目,其优先级高于缓存范围的过期值。您可以在创建时为特定条目配置过期。
注意

当您为缓存条目明确定义 lifespan 和最大闲置时间值时,Data Grid 会将这些值与缓存条目一起复制。同样,如果您配置缓存存储,Data Grid 会保留过期值以及条目。

为所有缓存条目配置过期

在 2 秒后使所有缓存条目过期:

<expiration lifespan="2000" />

在最后一次访问时间后使所有缓存条目 1 秒过期:

<expiration max-idle="1000" />

禁用带有 interval 属性的过期时间,并在最后一次访问时间后手动使条目 1 秒过期:

<expiration max-idle="1000" interval="-1" />

在最后一次访问时间后 5 秒或 1 秒后使所有缓存条目过期,以首先发生:

<expiration lifespan="5000" max-idle="1000" />

在创建缓存条目时配置过期

以下示例演示了如何在创建缓存条目时配置 lifespan 和最大闲置值:

// Use the cache-wide expiration configuration.
cache.put("pinot noir", pinotNoirPrice); 1

// Define a lifespan value of 2.
cache.put("chardonnay", chardonnayPrice, 2, TimeUnit.SECONDS); 2

// Define a lifespan value of -1 (disabled) and a max-idle value of 1.
cache.put("pinot grigio", pinotGrigioPrice,
          -1, TimeUnit.SECONDS, 1, TimeUnit.SECONDS); 3

// Define a lifespan value of 5 and a max-idle value of 1.
cache.put("riesling", rieslingPrice,
          5, TimeUnit.SECONDS, 1, TimeUnit.SECONDS); 4

如果 Data Grid 配置为所有条目定义了 lifespan 值 1000,则前面的 Cache.put () 请求会导致条目过期:

1
1 秒后。
2
2 秒后。
3
最后一次访问时间后 1 秒。
4
最后一次访问时间后 5 秒或 1 秒后,以先者为准。
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.