【翻译】【ehcache】如何设置缓存的大小

本文详细介绍了Ehcache缓存的大小配置方法,包括堆内存、堆外内存及本地磁盘的配置方式,以及如何通过百分比、混合配置等方式进行缓存大小的分配。
原文地址: [url]http://www.ehcache.org/documentation/2.8/configuration/cache-size[/url]
文章性质: 官方文档
注: 阅读本文需要一定的Ehcache的基础。本文主要是针对缓存的大小这方面进行详述,并不是入门示例。有时间我会翻译Ehcache的所有官方文档。[b]若转载请注明本文地址。 [/b]

--------------
[b]目录 [/b]
1. 简介
2. 设置缓存大小
3. CacheManager级别、Cache级别
3.1 堆内存 (Local Heap)
3.2 大空间内存(堆外内存 Local Off-Heap)
3.3 本地磁盘(Local Disk)
4. 缓存大小的一些例子
4.1 统一配置
4.2 明确Cache大小
4.3 混合配置
4.4 使用百分比
4.5 只配置Cache级别
4.6 溢出 (Overflows)
5. 分布式缓存大小
6. 建立计算缓存大小机制
6.1 忽略计算大小
6.2 限制遍历对象的配置


--------------
[b]1. 简介[/b]

本篇文章我们来说说如何正确的限制Ehcache的大小,Ehcache提供了一系列的方法通过cache-configuration来设置不同的数据。这些限制大小的属性通过设置不同的节点信息来影响服务器内存和磁盘。

[b]2. 设置缓存大小[/b]

下面这张表总结了缓存大小的属性:
[table]
|存储器缓存类别|属性|CacheManager级别是否可用|描述|
|Heap (堆内存)|maxEntriesLocalHeap \ maxBytesLocalHeap|在CacheManager级别上,只能设定属性maxBytesLocalHeap|用来限制缓存在堆内存中所能使用的最大的字节数。当我们在CacheManager级别设定了属性maxBytesLocalHeap时,在这个CacheManager下面的所有Cache都会生效,这个设定可以在每个Cache上设置,或者在CacheManager级别设定。|
|Off-heap (堆外内存)|maxBytesLocalOffHeap|可以|堆外内存在BigMemory Go(企业版Ehcache)下有效。用来限制缓存在非堆内存的最大字节数。当我们CacheManager级别设定了属性maxBytesLocalOffHeap时,在这个CacheManager下面的所有Cache都会生效。|
|Local disk (本地磁盘) |maxEntriesLocalDisk \ maxBytesLocalDisk|在CacheManager级别上,只能设定属性maxBytesLocalDisk |用来限制缓存所能使用的磁盘的最大字节数。只有单机环境下才能便用本地磁盘。
当在CacheManager级别设定了maxBytesLocalDisk属性时,在这个CacheManager下面的所有Cache都会生效。但并不包括隐式指定的Cache。(隐式Cache是指overflowToDisk=true的Cache)。另外:这些设定只用于临时将缓存写入磁盘。并不适用于持久化的写入磁盘。|
[/table]

以上这些属性在设定值时用的都是整数数字,单位可以是K,M,G,(比如500K,200M,2G等),也可以使用百分符号(比如20%),在使用百分符号时,必须先指定CacheManager级别。

下面的图形结构说明了缓存在每个存储器的属性设制:
[img]http://dl.iteye.com/upload/picture/pic/131449/6670b8ce-c335-3365-abf2-14eba87488ee.png[/img]

[b]3. CacheManager级别、Cache级别[/b]

你可以通过配置来限制缓存在各个存储器的大小。你也可以在CacheManager级别上对它下属的所有缓存进行统一限制。

如果在CacheManager级别没有配置,那么也可以在单个的cache配置相应的属性。如果在CacheManager级别有配置,那么单个的cache就可以共享那个配置。(当Cache自己有配置该属性时,以自己配置的为先)。

例如,CacheManager有8个缓存节点,如我们在CacheManager级别限制了堆内存的最大使用数maxBytesLocalHeap为1G,,另外在两个单个cache节点分别配置了200M的内存,剩下的6个节点没有单独配置大小,那么这意味着剩下的6个cache共享剩余的624M。值得注意的是cache级别的配置必须用比特级别(bytes-based)的属性来配置,而不能便用实体级别(entries-based)的属性(例如maxEntriesLocal)。

在程序启动时,都会检查CacheManager级别的配置是否过度分配了。如有任何一个配置过度分配了,那么就会抛错InvalidConfigurationException。比如在一个总配置中,我们给其中一个Cache配置maxBytesLocalHeap=30%,那么所有的Cache的配置总和不能超过100%,否则就会报错。

如果在Cache级别指定了任何的一种缓存类别正好等于CacheManager级别定义给所有的Cache的大小,那么就会打印出警告。也就是说,单个Cache的配置不能和CacheManager级别的定义相等,因为这样就没有留给其它节点的定义空间了。

[b]3.1 堆内存 (Local Heap)[/b]

使用堆内存的大小是必须设置的,可以是定义在CacheManager级别的(只能设定maxBytesLocalHeap),或者是定义在单个有Cache上的(maxBytesLocalHeap或者maxEntriesLocalHeap)。如果不定义堆内存的大小会导致程序抛错:InvalidConfigurationException

在一个配置文件中,我们可以结合CacheManager级别和单个Cache级别来分配大小,比如我们在CacheManager级别定义了属性maxBytesLocalHeap的总大小,然后对单个Cache进行maxBytesLocalHeap大小的分配(可以是百分比,也可以是具体的值)。

[color=red]在任何情况下,每个缓存都必须有堆内存的配置,不管是单独配置在每个Cache节点上还是统一定义在CacheManager级别上。[/color]

[b]3.2 大空间内存(堆外内存 Local Off-Heap)[/b]

堆外内存只有在BigMemory Go(企业版Ehcache)下才有效。堆外内存的配置只能用比特-类别的(bypes),而不能用实体-类别的(entries)。

如果CacheManager级别定义了堆外内存的配置,那么你的应用就不能动态的增加缓存配置——否则就会报错。如果程序运行过程中删除了任何一个缓存,另外的缓存就不能再定义那些未使用的堆内存部分的大小。所以说为了分配所有的堆内存的大小,那么就要从Ehcache的配置中删除那些不想要的Cache,然后重新加载配置。

要使用堆外内存,单个Cache的overflowToOffHeap属性必须是”true”。如果在CacheManager级别定义了堆外内存,那么就会自动的把所有的Cache节点的overflowToOffHeap属性改为“true”。在这种情况下,你可以在单个Cache下重写overflowToOffHeap的值为“false”,这样就不会被CacheManager统一改掉了。

[b]3.3 本地磁盘(Local Disk)[/b]

缓存可以被写入本地磁盘,注意点:
• 隐式缓存(Distributed)不能被写入本地磁盘。
• 缓存的persistenceStrategy属性必须设定为"localTempSwap"。
• 本地磁盘是最慢的缓存类别模式。

[b]4. 缓存大小的一些例子[/b]

以下演示了统一配置和单个Cache配置。

[b]4.1 统一配置[/b]

CacheManager级别的统一配置:

<ehcache xmlns...
Name="CM1"
maxBytesLocalHeap="100M"
maxBytesLocalOffHeap="10G"
maxBytesLocalDisk="50G">
...
<cache name="Cache1" ... </cache>
<cache name="Cache2" ... </cache>
<cache name="Cache3" ... </cache>
</ehcache>

名叫CM1的CacheManager自动的给每个缓存(Cache1,Cache2,Cache3)分配属性大小值。每个缓存都会得到三分之一的堆内存(maxBytesLocalHeap="100M"),堆外内存(maxBytesLocalOffHeap="10G")以及本地内存(maxBytesLocalDisk="50G")。
[color=red]注,在CacheManager级别只能分配比特-类型(bytes)相关的属性。[/color]

[b]4.2 明确Cache大小[/b]

你也可以明确的每个缓存分配大小:

<ehcache xmlns...
Name="CM1"
maxBytesLocalHeap="100M"
maxBytesLocalOffHeap="10G"
maxBytesLocalDisk="60G">
...
<cache name="Cache1" ...
maxBytesLocalHeap="50M"
...
</cache>

<cache name="Cache2" ...
maxBytesLocalOffHeap="5G"
...
</cache>
<cache name="Cache3" ... </cache>

</ehcache>

以上的例子中,Cache1分配获得了50M的堆内存;其它缓存(Cache2\Cache3)再平均分配剩余的堆内存空间(100M-50M=50M)。Cache2的堆外内存配置是5G,那么其它的缓存再平均分配剩余的堆外内存空间(10G-5G=5G)。所以虽然Cache3没有单独配置,根据头部公用配置(也就是CacheManager级别),我们可以得知,Cache3的堆内存是25M,堆外内存为2.5G以及本地磁盘大小是20Gb。

在缓存中配置了某个属性,获得了一部分的公用配置的大小,但并不意味着就必须要使用。比如Cache1配置了50M的堆内存,那么就可以使用50Mb中的任何大小。

值得注意的是缓存配置必须使用相同的属性来创建一个公用的配置(pool)。比如Cache1就不能再使用属性maxEntriesLocalHeap来从公用配置中获得堆内存(节点-类型)的大小(因为公用头部配置的是属性maxBytesLocalHeap)。

[b]4.3 混合配置[/b]

如果一个CacheManager没有配置某一属性,单个节点的Cache仍然能够单独配置,具体示例如下:

<ehcache xmlns...
Name="CM2"
maxBytesLocalHeap="100M">
...

<cache name="Cache4" ...
maxBytesLocalHeap="50M"
maxEntriesLocalDisk="100000"
...
</cache>

<cache name="Cache5" ...
maxBytesLocalOffHeap="10G"
...
</cache>
<cache name="Cache6" ... </cache>

</ehcache>


名叫CM2的CacheManager创建了一个配置,堆内存大小为100M。它下面的所有缓存都将受这个配置的约束。单个Cache可以再配置其它自己的属性。例如Cache4配置了本地磁盘的最大值,Cache5配置了堆外内存空间,因为Cache6虽然没有Cache级别的配置,但因为CacheManager级别有配置堆内存,所以Cache6能获得(100M-50M)/2 = 25M的堆内存。

[b]4.4 使用百分比[/b]

我们也可以使用百分比来配置,具体示例如下:

<ehcache xmlns...
Name="CM1"
maxBytesLocalHeap="1G"
maxBytesLocalOffHeap="10G"
maxBytesLocalDisk="50G">
...

<!-- Cache1 gets 400Mb of heap, 2.5Gb of off-heap, and 5Gb of disk. -->
<cache name="Cache1" ...
maxBytesLocalHeap="40%">
</cache>

<!-- Cache2 gets 300Mb of heap, 5Gb of off-heap, and 5Gb of disk. -->
<cache name="Cache2" ...
maxBytesLocalOffHeap="50%">
</cache>

<!-- Cache2 gets 300Mb of heap, 2.5Gb of off-heap, and 40Gb of disk. -->
<cache name="Cache3" ...
maxBytesLocalDisk="80%">
</cache>
</ehcache>


你可以使用百分比来配置属性maxBytesLocalHeap。如果在CacheManager级别配置了百分比,那么表示占总的JVM内存的百分之多少。如果是在Cache级别配置了百分比,那么表示它占它所属的CacheManager配置的百分之多少。

[b]4.5 只配置Cache级别[/b]

本示例中,在CacheManager级别不配置,而只在Cache级别配置:


<ehcache xmlns...
Name="CM3"
... >
...

<cache name="Cache7" ...
maxBytesLocalHeap="50M"
maxEntriesLocalDisk="100000"
...
</cache>

<cache name="Cache8" ...
maxEntriesLocalHeap="1000"
maxBytesLocalOffHeap="10G"
...
</cache>
<cache name="Cache9" ...
maxBytesLocalHeap="50M"
...
</cache>
</ehcache>

在不配置CacheManager级别时,缓存也可以单个独立配置。需要注意的是单个缓存的配置必须声明堆内存的配置,这是因为堆内存没有统一声明配置。总之,堆内存的配置是必须存在的,要么在CacheManager上统一配置,要么在Cache级别上单独配置。

[b]4.6 溢出 (Overflows)[/b]
Caches that do not specify overflow will overflow if a pool is set for off-heap and disk.
如果配置了堆外内存和本地磁盘,当堆内存满后,会自动溢出到堆外内存和本地磁盘,若没有配置,则不会溢出:

<ehcache maxBytesLocalHeap="1g" maxBytesLocalOffHeap="4g"
maxBytesLocalDisk="100g" >

<cache name="explicitlyAllocatedCache1"
maxBytesLocalHeap="50m"
maxBytesLocalOffHeap="200m"
timeToLiveSeconds="100">
</cache>

<!—当堆内存溢出后,不会使用堆外内存(off-heap),因为堆外内存使用标识为false -->
<cache name="automaticallyAllocatedCache2"
timeToLiveSeconds="100"
overflowToOffHeap="false">
</cache>
</ehcache>

<!—不会使用本地磁盘,因为配置中使用了Fast Restart(快速重启)。(该处磁盘的用处为:它可以在重启的时候将堆内存或者非堆内存里面的元素持久化到硬盘上,重启之后再从硬盘上恢复元素到内存中。该策略只对企业版Ehcache有用。)
-->
<cache name="explicitlyAllocatedCache2"
maxLocalHeap="10%"
maxBytesLocalOffHeap="200m"
timeToLiveSeconds="100">
<persistence strategy="localRestartable"/>
</cache>

<!—当堆内存满后,会自动溢出到堆外内存和本地磁盘,因为在CacheManager级别没有特殊的配置。 -->
<cache name="automaticallyAllocatedCache1"
timeToLiveSeconds="100">
</cache>


[b]5. 分布式缓存大小[/b]

分布式缓存在企业式Ehcache下有效,也可以按以上的例子进行配置,除了不能使用本地磁盘(换句话说不能使用*LocalDisk来配置)。分布式缓存可以使用堆内存[b]Terracotta[/b]集群技术来(一款由美国Terracotta公司开发的著名开源Java集群平台)来存储资原(堆内存或磁盘)。

分布式缓存中,每个节点下可以为相同的缓存配置独立的属性。那意味着当相同的要素和属性被Ehcache配置所加载时,在同一个缓存下,这些配置在不同的节点上的属性都可以同时被多个节点所使用。

例如:一个缓存可能有以下这样的配置:


<cache name="myCache"
maxEntriesOnHeap="10000"
maxBytesLocalOffHeap="8g"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800">
<persistence strategy="distributed"/>
<terracotta/>
</cache>


同样名叫myCache的缓存在另一个节点上可能有以下这样的配置:

<cache name="myCache"
maxEntriesOnHeap="10000"
maxBytesLocalOffHeap="10g"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800">
<persistence strategy="distributed"/>
<terracotta/>
</cache>


如果一个缓存超出了节点所配置的最大值,那么Terracotta会提供给名为myCache的缓存一个不限制大小的磁盘空间来备份溢出数据。如果要做限制,可以使用属性maxEntriesInCache,其值可配值任意一个正数。

<cache name="myCache"
maxEntriesOnHeap="10000"
maxBytesLocalOffHeap="10g"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
maxEntriesInCache="1000000">
<persistence strategy="distributed"/>
<terracotta/>
</cache>

Terracotta将会回收myCache的超出属性maxEntriesInCache配置的部分。对于任何一个缓存,Terracotta回收机制都是基于那个最大的配置。除此之外,Terracotta不会回收已经存在于客户端的缓存节点,同样的新配置的属性maxEntriesInCache在已经生效于客户端的缓存也同样无效。

[b]6. 建立计算缓存大小机制[/b]

Ehcache建立缓存大小机制的步骤分为计算数据元素的大小和按照CacheManager中的配置来强制限制其大小。

众所周知,JAVA是面向对象语言,那么类的属性可以是另一个对象。在每个元素在存入内存(或磁盘)时会被计算其大小,包括键值(Key)和元素值(Value)的大小,也包括这个类的属性引用其它类型的值的大小。这个可以看成是递归形式的计算。

这意味着一个被很多其它类引用的对象,在每次被引用的时候都会被计算。这个被引用的对象我们称之为“引用对象”,这会导致计算结果过份庞大。“引用对象”应该被忽略计算。

[b]6.1 忽略计算大小[/b]

我们可以使用annotation标签@IgnoreSizeOf来标记为可以忽略计算“引用对象”。这个annotation标签可以是方法级别的,类级别的或是包级别的。也可以定义一个忽略名单的文件包含类名、方法名、包名。

@IgnoreSizeOf是不能被继承的,子类如果没有标记,那么当别的类引用它时,还是会计算其大小。

以下示例:忽略[u]Dog.class[/u]

@IgnoreSizeOf
public class Dog {
private Gender gender;
private String name;
}


以下示例:忽略属性[u]sharedInstance[/u]

public class MyCacheEntry {
@IgnoreSizeOf
private final SharedClass sharedInstance;
...
}


以下示例:当在包[u]com.pany.ignore package[/u]上加入标签@IgnoreSizeOf,那么在计算缓存大小时,会忽略整个包下的资源

@IgnoreSizeOf
package com.pany.ignore;
import net.sf.ehcache.pool.sizeof.filter.IgnoreSizeOf;


我们也可以定义一个文件来声明要忽略的类和属性,这个文件需要用系统属性[b]net.sf.ehcache.sizeof.filter[/b]来标明出处。

# That field references a common graph between all cached entries
com.pany.domain.cache.MyCacheEntry.sharedInstance

# This will ignore all instances of that type
com.pany.domain.SharedState

# This ignores a package
com.pany.example


注:[color=red]这些衡量方法和配置忽略大小的方法只针对堆内存有效。[/color]如果一个元素已经被存在了堆外内存或磁盘中,或企业级的Terracotta中,那么他们会被序列化成比特数组。这个计算就变的简单多了,我们只需要计算这些比特数据的大小,而不用在意引用关系等。

[b]6.2 限制遍历对象的配置[/b]

综上所述,缓存的大小与引用的对象有关。我们可以使用annotations标签来标明是否需要计算。另一方面,CacheManager和cache级别都定义了其缓存的配置大小。

注:以下配置对分布式缓存无效。

[b]6.2.1 CacheManager级别计算[/b]

以下配置表明,在CacheManager级别中,size-of引擎可以计算多少深度的堆内存的元素:(译者注:如果理解深度这个概念,介于JAVA都是引用型的对象,所以可以用树的深度来类比)


<sizeOfPolicy maxDepth="100" maxDepthExceededBehavior="abort"/>


这个配置有以下两个属性:
• maxDepth – 表示size-of引擎可以目标对象可以访问其引用的对象的最大深度。若配置了sizeOfPolicy,那么该元素是必须要配置的。
• maxDepthExceededBehavior – 标明当超出最大深度(>maxDepth)时的措施:可以配置的值:continue/abort
"continue" - 默认配置。表示当计算的值超出最大深度时,会打印WARN级别的log,并且会继续执行(不会强制退出报错)。
"abort" - 当SizeOf引擎计算失败时,会打印WARN级别的log,并返回错误。在这个配置下,方法 Ehcache.hasAbortedSizeOf() 返回true。

该SizeOf的配置可以放在CacheManager级别的配置下(即<ehcache>),也可放在cache配置级别下(即<cache>或<defaultCache>),在cache级别下的配置优先级要高于CacheManager级别下的(即两者都有配置的话,以cache的为先)。
注:sizeOfPolicy对分布式缓存无效。

[b]6.2.2 Cache级别计算[/b]

在Cache级别(<cache>)使用<sizeOfPolicy>来定义size-of引擎的计算规则时,如同上一段落所说的,优先级别比CacheManager级别要高。

[b]6.2.3 调试Size-Of[/b]

当计算大小的过程中出现警告或错误时(通常是size-of引擎报错),可采取以下方法来获得更多的调试信息:
• 将系统属性(system property)=net.sf.ehcache.sizeof.verboseDebugLogging设成 [b]true[/b]
• 若你的log是用SLF4J实现的,那么将LOG信息为DEBUG级别设为可见(即打印到控制台或文件)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值