第 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. 为数据网格缓存配置总条目数
将缓存条目的数据容器的大小限制为条目总数。
流程
- 使用适当的存储格式配置数据网格缓存编码。
指定缓存在 Data Grid 执行驱除前可以包含的条目总数。
-
declarative :设置
max-count
属性。 -
programmatic :调用
maxCount ()
方法。
-
declarative :设置
配置驱除策略,以控制 Data Grid 如何删除条目。
-
declarative :设置
when-full
属性。 -
Programmatic :调用
whenFull ()
方法。
-
declarative :设置
声明性配置
<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. 为数据网格缓存配置最大内存量
将缓存条目的数据容器的大小限制为最大内存量。
流程
将您的数据网格缓存配置为使用支持二进制编码的存储格式。
您必须使用二进制存储格式根据最大内存量执行驱除。
配置缓存在数据网格执行驱除前可以使用的最大内存量(以字节为单位)。
-
declarative :设置
max-size
属性。 -
programmatic :使用
maxSize ()
方法。
-
declarative :设置
- (可选)指定测量的字节单位。默认值为 B (字节)。对于支持的单元,请参阅 配置模式。
配置驱除策略,以控制 Data Grid 如何删除条目。
-
declarative :设置
when-full
属性。 -
Programmatic :使用
whenFull ()
方法。
-
declarative :设置
声明性配置
<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
() 请求会导致条目过期: