带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(2)

简介: 带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(2)

带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(1)https://developer.aliyun.com/article/1338386?groupCode=taobaotech

下面来看看我是如何优化的。核心主要关注:区分下游返回的结果是真的空还是假的空,本身就为空的情况下,就该缓存空集合(非大促期间或者某些榜没有数据,数据本身就为空)

 

 

 

image.png

 

 

在redis中拉长value缓存的时间,同时新增一个可更新时间的缓存(比如60s过期),当判断更新时间缓存过期了,就重新读取数据源,将value值重新赋值,这里需要注意,我会对比新老数据,如果新数据为空,老数据不为空,则只是更新时间,不置换value。value随着自己的过期时间结束,改造后的代码如下:

  return LOCAL_CACHE.get(key, () -> {
  String updateKey = getUpdateKey(key);
  String value = rdbCommonTairCluster.get(key);
  List<ItemShow> cache = StringUtils.isBlank(cache) ? Collections.emptyList()
:  JSON.parseObject(value, new TypeReference<List<ItemShow>>(){});
  if (rdbCommonTairCluster.exists(updateKey)) {
  return cache;
 }
  rdbCommonTairCluster.set(updateKey, currentTime, cacheUpdateSecond);
  List<ItemShow> itemShows = getRankingItemOriginal(context, rankingRequest);
  if (CollectionUtils.isNotEmpty(itemShows)) {
   rdbCommonTairCluster.set(key, JSON.toJSONString(itemShows), new SetParams().ex(Common- Switch.rankingExpireSecond));
 }
 return itemShows;
 });

 

为了使这段代码能够复用,我将该多级缓存抽象出来一个独立对象,代码如下:

 

  public class GatherCache<V> {
@Setter
  private Cache<String, List<V>> localCache;
  @Setter
  private CenterCache centerCache; 6
public List<V> get(boolean needCache, String key, @NonNull Callable<List<V>> loader, Func- tion<String, List<V>> parse) {
try {
// 是否需要是否缓存
return needCache ? localCache.get(key, () -> getCenter(key, loader, parse)) : loader.call();
} catch (Throwable e) {
GatherContext.error(this.getClass().getSimpleName() + " get catch exception", e);
}
return Collections.emptyList();
}
private List<V> getCenter(String key, Callable<List<V>> loader, Function<String, List<V>> parse) throws Exception {
String updateKey = getUpdateKey(key); String value = centerCache.get(key);
boolean blankValue = StringUtils.isBlank(value);
List<V> cache = blankValue ? Collections.emptyList() : parse.apply(value); if (centerCache.exists(updateKey)) {
return cache;
}
centerCache.set(updateKey, currentTime, cacheUpdateSecond); List<V> newCache = loader.call();
if (CollectionUtils.isNotEmpty(newCache)) {
centerCache.set(key, JSON.toJSONString(newCache), cacheExpireSecond);
}
return newCache;
}
}

 

将从数据源获取数据的代码交与外部实现,使用Callable的形式,同时通过泛型约束数据源类型,这里还有一点瑕   疵还没得到解决,就是通过fastJson转换String到对象时,没法使用泛型直接转,我这里就采用了外部化的处理, 就是跟获取数据源方式一样,由外部来决定如何解析从redis中获取到的字符串value。调用方式如下:

 

 

 

  List<ItemShow> itemShowList = gatherCache.get(true, rankingRequest.getKey(),
  () -> getRankingItemOriginal(rankingRequest, context.getRequestContext()),
  v -> JSON.parseObject(v, new TypeReference<List<ItemShow>>() {}));


同时我还采用的建造者模式,方便gatherCache类快速生成,代码如下:

 

  @PostConstruct
  public void init() {
  this.gatherCache = GatherCacheBuilder.newBuilder()
  localMaximumSize(500)
  localExpireAfterWriteSeconds(30)
build(rdbCenterCache); 7 }

带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(3)https://developer.aliyun.com/article/1338379?groupCode=taobaotech

相关文章
|
10月前
|
设计模式 算法 搜索推荐
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(7)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(7)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(7)
|
10月前
|
存储 缓存 前端开发
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(8)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(8)
|
10月前
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(5)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(5)
|
10月前
|
设计模式 双11 索引
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(11)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(11)
|
10月前
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(6)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(6)
|
10月前
|
缓存 NoSQL Redis
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(1)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(1)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(1)
|
10月前
|
设计模式
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(4)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(4)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(4)
|
10月前
|
缓存 NoSQL Redis
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(3)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(3)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(3)
|
10月前
|
前端开发
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(10)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(10)
|
10月前
|
前端开发
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(9)
带你读《2022技术人的百宝黑皮书》——谈一谈凑单页的那些优雅设计(9)