专栏名称: 亿级流量网站架构
开涛技术点滴
目录
相关文章推荐
OSC开源社区  ·  AI ... ·  昨天  
京东零售技术  ·  京东率先开启“3D信息流时代” 让购物更有趣 ·  昨天  
程序员的那些事  ·  12 ... ·  昨天  
阿里云云栖号  ·  国通星驿与阿里云共同启动AI战略合作! ·  昨天  
51好读  ›  专栏  ›  亿级流量网站架构

应用级缓存之缓存使用模式实践—《亿级流量》

亿级流量网站架构  · 公众号  · 程序员  · 2017-05-04 08:55

正文

请到「今天看啥」查看全文



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

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)分别来支持单个写、批量写和单个删除、批量删除操作。







请到「今天看啥」查看全文