正文
Guava Cache实现
LoadingCache
> getCache =
CacheBuilder.newBuilder()
.softValues()
.maximumSize(5000).expireAfterWrite(2, TimeUnit.MINUTES)
.build(new CacheLoader
>() {
@Override
public Result
load(final Integer sortId) throwsException {
return categoryService.get(sortId);
}
});
在build Cache时,传入一个CacheLoader用来加载缓存,操作流程如下。
1.应用业务代码直接调用getCache.get(sortId)。
2.首先查询Cache,如果缓存中有,则直接返回缓存数据。
3.如果缓存没有命中,则委托给CacheLoader,CacheLoader会回源到SoR查询源数据(返回值必须不为null,可以包装为Null对象),然后写入缓存。
使用CacheLoader后有几个好处。
● 应用业务代码更简洁了,不需要像Cache-Aside模式那样缓存查询代码和SoR代码交织在一起。如果缓存使用逻辑散落在多处,则使用这种方式很简单的消除了重复代码。
● 解决Dog-pile effect,即当某个缓存失效时,又有大量相同的请求没命中缓存,从而同时请求到后端,导致后端压力太大,此时限制一个请求去拿即可。
if (firstCreateNewEntry) {//第一个请求加载缓存的线程去SoR加载源数据
try {
synchronized (e) {
returnloadSync(key, hash, loadingValueReference, loader);
}
} finally{
statsCounter.recordMisses(1);
}
} else {//其他并发线程等待“第一个线程”加载的数据
return waitForLoadingValue(e, key,valueReference);
}
Guava Cache还支持get(K key, Callable extends V> valueLoader)方法,传入一个Callable实例,当缓存没命中时,会调用Callable#call来查询SoR加载源数据。
Ehcache 3.x实现
CacheManager cacheManager = CacheManagerBuilder. newCacheManagerBuilder(). build(true);
org.ehcache.Cache
myCache =cacheManager. createCache ("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class,String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(100,MemoryUnit.MB))
.withDispatcherConcurrency(4)
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(10,TimeUnit.SECONDS)))
.withLoaderWriter(newDefaultCacheLoaderWriter
() {
@Override
public String load(String key) throws Exception {
return readDB(key);
}
@Override
public Map
loadAll(Iterable extendsString> keys) throws BulkCacheLoadingException, Exception {
return null;
}
}));
Ehcache 3.x使用CacheLoaderWriter来实现,通过load(K key)和loadAll(Iterable extends K> keys)分别来加载单个KEY和批量KEY。Ehcache 3.1没有自己去解决Dog-pile effect。
Write-Through,称之为穿透写模式/直写模式,业务代码首先调用Cache写(新增/修改)数据,然后由Cache负责写缓存和写SoR,而不是业务代码。使用Write-Through模式需要配置一个CacheWriter组件用来回写SoR。Guava Cache没有提供支持。Ehcache 3.x支持该模式。Ehcache需要配置一个CacheLoaderWriter,CacheLoaderWriter知道如何去写SoR。当Cache需要写(新增/修改)数据时,首先调用CacheLoaderWriter来同步(立即)到SoR,成功后会更新缓存。
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);
org.ehcache.Cache
myCache =cacheManager.createCache ("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class,String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(100,MemoryUnit.MB))
.withDispatcherConcurrency(4)
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(10,TimeUnit.SECONDS)))
.withLoaderWriter(newDefaultCacheLoaderWriter
() {
@Override
public void write(String key, String value) throws Exception{
//write
}
@Override
public void writeAll(Iterable extends Map.Entry extendsString, ? extends String>> entries) throws BulkCacheWritingException,Exception {
for(Object entry: entries) {
//batch write
}
}
@Override
public void delete(Stringkey) throws Exception {
//delete
}
@Override
public void deleteAll(Iterable extends String>keys) throws BulkCacheWritingException, Exception {
for(Object key :keys) {
//batch delete
}
}
}).build());
Ehcache 3.x还是使用CacheLoaderWriter来实现,通过write(String key, String value)、writeAll(Iterable extends Map.Entry extends String, ?extends String>> entries)和delete(String key)、deleteAll(Iterable extends String> keys)分别来支持单个写、批量写和单个删除、批量删除操作。