深入分布式缓存-从原理到实践(二)


深入分布式缓存-从原理到实践(二)

规划定义

JSR

JSR是java Specification Requests的缩写,是java定义的一种对java对象临时在内存中进行缓存的方法,包括对象的创建\访问\失效\一致性等

缓存常用方法

接口 说明 Ehcache Guava
put() 添加缓存
putIfAbsent() 如果key不存在则添加缓存
replace() 如果key存在则替换缓存
get() 获取缓存
getAll() 获取所有缓存
getAllPresent(key) 存在key在进行加载
putAll(entries) 添加所有缓存
keySet() 获取所有key
remove() 移除缓存
clear() 清空缓存

可以看到常见的缓存操作就三类:添加<B>获取<B>移除

下面介绍两类缓存的实现方式:本地缓存分布式缓存

本地缓存

Ehcache

暂且将Ehcache划分到本地缓存中,因为在使用中大多数场景下还是将Ehcache作为本地缓存来进行使用

Ehcache2的核心淘汰策略逻辑如下:

selectedBasedOnPolicy

AbstractPolicy.selectedBasedOnPolicy

  • compare
/**
 * Compares the desirableness for eviction of two elements
 *
 * @param element1 the element to compare against
 * @param element2 the element to compare
 * @return true if the second element is preferable for eviction to the first element
 * under ths policy
 */
boolean compare(Element element1, Element element2);

可以看到compare()方法是核心的比较方法,下层有LRUPolicy<B>LFUPolicy<B>FIFOPolicy底层实现

  • LruPolicy
  // 最近最少使用算法
  public boolean compare(Element element1, Element element2) {
    // 比较最后访问时间
    return element2.getLastAccessTime() < element1.getLastAccessTime();
}

LruPolicy.compare

  • LFU
  // 最近最少使用算法
  public boolean compare(Element element1, Element element2) {
    // 比较访问次数
    return element2.getHitCount() < element1.getHitCount();
}

LfuPolicy.compare

  • FIFO
  // 最近最少使用算法
  public boolean compare(Element element1, Element element2) {
    // 比较创建和更新时间
    return element2.getLatestOfCreationAndUpdateTime() < element1.getLatestOfCreationAndUpdateTime();
}

FIFOPolicy.compare

Guava Cache

Guava Cache是Google对java集合的一种封装来实现缓存功能;

Guava Cache 提供缓存的失效时间和定时更新功能,下面介绍Guava Cache定时更新方法

  • scheduleRefresh()
V scheduleRefresh(
    ReferenceEntry<K, V> entry,
    K key,
    int hash,
    V oldValue,
    long now,
    CacheLoader<? super K, V> loader) {
  if (map.refreshes()//map.refreshes()判断是否存在过期时间
      && (now - entry.getWriteTime() > map.refreshNanos)//判断是否已经过期
      && !entry.getValueReference().isLoading()) {//判断是否当前正在加载新值
    V newValue = refresh(key, hash, loader, true);//重新加载数据
    if (newValue != null) {
      return newValue;
    }
  }
  return oldValue;
}

scheduleRefresh()方法是在get()方法中调用的
LocalCache.scheduleRefresh

Caffine

二级缓存

在使用集中式或者数据库热点配置数据时,我们往往将这些数据放到应用进程空间中中,这样可以提高缓存的命中率;可以用Echache/Guava作为二级缓存来进行使用
下面介绍两种常用的设计方案:

  • 定时轮询

定时轮询

  • 消息通知

消息通知

消息通知的方案可以保证准实时下的推送,但是会带来一定的开销,比如消息通知的推送频率是每秒一次,那么每秒钟的消息会被推送到缓存中,这样会带来一定的开销,通过这样的消耗来保证实时性;还需要注意一点的是应用的重启后一定要消费最新的消息或从redis中获取最新的数据

参考资料

https://github.com/hazelcast/hazelcast


  TOC