容量限制时的Size与Weight区别
弄清Size与Weight
Guava Cache提供了对缓存总量的限制,并且支持从两个维度进行限制,这里我们首先要厘清size
与weight
两个概念的区别与联系。
- 限制缓存条数size
public Cache<String, User> createUserCache() {
return CacheBuilder.newBuilder().maximumSize(10000L).build();
}
复制代码
- 限制缓存权重weight
public Cache<String, String> createUserCache() {
return CacheBuilder.newBuilder()
.maximumWeight(50000)
.weigher((key, value) -> (int) Math.ceil(value.length() / 1000))
.build();
}
复制代码
一般而言,我们限制容器的容量的初衷,是为了防止内存占用过大导致内存溢出
,所以本质上是限制内存的占用量。从实现层面,往往会根据总内存占用量与预估每条记录字节数进行估算,将其转换为对缓存记录条数的限制。这种做法相对简单易懂,但是对于单条缓存记录占用字节数差异较大的情况下,会导致基于条数控制的结果不够精准。
比如:
需要限制缓存最大占用
500M
总量,缓存记录可能大小范围是1k~100k,按照每条50k
进行估算,设定缓存容器最大容量为限制最大容量1w
条。如果存储的都是1k大小的记录,则内存总占用量才10M(内存没有被有效利用起来);若都存储的是100k大小的记录,又会导致内存占用为1000M,远大于预期的内存占用量(容易造成内存溢出)。
为了解决这个问题,Guava Cache中提供了一种相对精准的控制策略,即基于权重的总量控制,根据一定的规则,计算出每条value记录所占的权重值,然后以权重值进行总量的计算。
还是上面的例子,我们按照权重进行设定,假定1k对应基础权重1,则100k可转换为权重100。这样一来:
限制缓存最大占用
500M
,1k
对应权重1,Nk
代表权重N,则我们可以限制总权重为50w
。这样假如存储的都是1k的记录,则最多可以缓存5w条记录;而如果都是100k大小的记录,则最多仅可以缓存5000条记录。根据存储数据的大小不同,最大存储的记录条数也不相同,但是最终占用的总体量可以实现基本吻合。
所以,基于weight
权重的控制方式,比较适用于这种对容器体量控制精度有严格诉求的场景,可以在创建容器的时候指定每条记录的权重计算策略(比如基于字符串长度或者基于bytes数组长度进行计算权重)。