数据缓存的意义
数据缓存机制的主要目的是加速运算。
具体来说,就是当应用执行过程中,数据缓存机制对某些需要多次使用(重用)的数据进行缓存。这样,当应用再次访问这些数据时,可以从缓存中读取,避免再次运算,从而减少应用的执行时间。
在设计一个高效的缓存机制,包括诸多内容,我们此处就Spark中缓存数据的替换,即LRU算法进行一点分析。
SparkLRU的实现
LRU,即最近最少使用,在Spark缓存机制中的体现就是优先替换掉当前最久未被使用的RDD。
但是在Spark源码中似乎没有相关的LRU算法实现代码。
在参考了《大数据处理框架Apache Spark设计与实现》一书后知道,实际上,Spark直接利用了 LinkedHashMap 自带的LRU功能实现了缓存替换。
借助LinkedHashMap这一数据机构,将最近插入或者被读取的分区数据放在表尾,这样表头则是最近最少使用的,在替换时可以直接删除。之所以可以实现如此方便的插入删除和访问,是因为LinkedHashMap的底层是由哈希表+双链表组成的,我们借助leetcode146题,LRU缓存的设计来看一下具体实现。
代码如下:
package liu.ds;
import java.util.LinkedHashMap;
public class LRUcache {
int cap;
//使用LinkedHashMap来构造,底层是双链表
LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
//构造器
public LRUcache(int capacity) {
cap = capacity;
}
public int get(int key) {
if(!cache.containsKey(key)){
return -1;
}
makeRecently(key);
return cache.get(key);
}
public void put(int key, int value) {
if(cache.containsKey(key)){
//修改key的值
cache.put(key, value);
makeRecently(key);
return;
}
//淘汰策略,即核心代码
if(cache.size() >= cap){
//链表头部就是最久未使用的key
//keySet() 方法返回映射中所有 key 组成的 Set 视图。
int oldestkey = cache.keySet().iterator().next();
cache.remove(oldestkey);
}
cache.put(key, value);
}
//如果对某个key值进行过访问,那么就将其设置为最近访问过,即插到队尾
public void makeRecently(int key){
int val = cache.get(key);
//删除key,重新插到队尾
cache.remove(key);
cache.put(key, val);
}
}