java技术--本地缓存进化史

1.原始状态:查库

 (1)原始开发中,没有使用缓存机制(Ehcache,Redis)时,直接查库
 (2)在用户量量不大的时候,查数据库或者读取文件是最为方便,能完全满足我们的业务要求

2.基于直接查库的优化JVM内置缓存:HashMap

1)有一定用户量之后或者查询数据库特别频繁
(2)就可以使用的java中自带的HashMap或者ConcurrentHashMap
  代码演示如下:
public class CuatomerService{
    private HashMap<String.String> hashMap = new HashMap<>();
    private CuatomerMapper customerMapper;
    public String getCustomer(String name){
        String customer = hashMap.get(name);
        if(customer ==null){
        customer = customerMapper.get(name);
        hashMap.put(name,customer )
       }
        reruen customer;
       }
       }
   <1>这样做就有个问题HashMap无法进行数据淘汰
   <2>内存会无限制的增长,所以hashMap很快也被淘汰了
   <3>hashMap可以在某些场景下作为缓存:
      1.不需要淘汰机制的时候,利用反射
      2.如果每次都通过反射去搜索Method,field,性能必定低效,这时我们用HashMap将其缓存起来,性能能提升很多

3.基于HashMap的优化:LRUHashMap

1)HashMap问题在于无法进行数据淘汰,这样会导致内存无限膨胀
(2)引入淘汰算法,解决无法进行数据淘汰的问题
(3)常见的三种FIFO,LRU,LFU(还有一些ARC,MRU)
     <1>FIFO:先进先出
        1.先进入缓存的会先被淘汰
        2.但是会导致命中率很低
        3.会把首个数据但是他的访问频率很高给挤出
    <2>LRU:最近最少使用算法
        1.每次访问数据都会将其放在队尾   
        2.需要淘汰数据,就只需要淘汰队首即可
        3.会把热点数据被淘汰
    <3>LFU:最近最少频率使用
        1.利用额外的空间记录每个数据的使用频率
        2.选出频率最低进行淘汰   
        3.避免了LRU不能处理时间段的问题  
(4)对于这三种,实现成本是一个比一个高,同样的命中率也是一个比一个好
(5)一般来说选择的方案居中即可,即实现成本不是太高,而命中率也还行的LRU        
实现一个LRUMap的代码演示:
    <1>可以通过继承LinkedHashMap
    <2>重写removeEldestEntry方法,即可完成一个简单的LRUMap
public class LRUMap extends LinkedHashMap{
     private final int max;
     private  object lock;
     public LRUMap (int max.Object lock){
    //无序扩容
    super((int) (max*1.4f),0.75f,true);
    this.max=max;
    this.lock=lock;
}
/**
  *(1)重写LinkedHashMap的removeEldestEntry方法即可
  *(2)在Put的时候判断,如果为true,就会删除最老的
  */
 @Override
 protected boolean removeEldestEntry(Map.Entry eldest){
     return size()>max;
}
public Object getValue(Object key){
   synchronized(lock){
   return get(key);
}
}
public Object putValue(Object key,Object value){
   synchronized(lock){
   put(key,value);
}
public boolean removeValue(Object key){
    synchronized(lock){
    return remove(key) != null;
}
}
public boolean removeAll(){
     clear();
     return true;
}
}
   <3>在LinkedHashMap中维护了一个entry(用来放key和value的对象)链表
   <4>每一次get或者put的时候都会把插入的新entry,或查询到的老entry放在链表末尾
   <5>在构造方法中,设置的大小特意设置到max*1.4,在下面的removeEldestEntry方法中只需要size>max就淘汰
   <6>这个map永远也走不到扩容的逻辑了,通过重写LinkedHashMap,几个简单的方法实现了LruMap
(6)LRUMap用来进行缓存数据的淘汰,但是有几个问题:
   <1>锁竞争严重:Lock是全局锁,在方法级别上面的,当调用量较大时,性能必然会比较低
   <2>不支持过期时间
   <3>不支持自动刷新

4.基于LRUHashMap的优化:Guava cache

(1)对于LRUHashMapd1这些问题,发明了Guava cache
(2)Guava cache代码演示如下:

在这里插入图片描述

(3)将会从guava cache原理中,解释guava cache是如何解决LRUMap的几个问题的
    <1>锁竞争
       1.guava cache采用了类似ConcurrentHashMap的思想,分段加锁,在每个段里面各自负责自己的淘汰的事情
       2.段太少那竞争依然很严重,如果段太多会容易出现随机淘汰
       3.在guava cache中通过代码,计算出应该如何分段
       4.在guava cache中对于写操作直接加锁
       5.对于读操作,如果读取的数据没有过期,且已经加载就绪,不需要进行加锁
       6.如果没有读到会再次加锁进行二次读
       7.如果还没有需要进行缓存加载,也就是通过配置的CacheLoader,这里配置的是直接返回Key,在业务中通常配置从数据库中查询
  <2>过期时间
      1.相比于LRUMap多了两种过期时间,一个是写后多久过期expireAfterWrite,一个是读后多久过期expireAfterAccess
  <3>自动刷新
     1.直接通过查询,判断其是否满足刷新条件,进行刷新
  <4>其他特性
     1.虚引用
     2.在Guava cache中,key和value都能进行虚引用的设定
     3.用来记录被回收的引用,其中每个队列记录了每个被回收的Entry的hash
     4.回收了之后通过这个队列中的hash值就能把以前的Entry进行删除
     5.删除监听器
     6.在guava cache中,当有数据被淘汰时,但是不知道他到底是过期,还是被驱逐,还是因为虚引用的对象被回收
     7.可以调用这个方法removalListener(RemovalListener listener)添加监听器进行数据淘汰的监听,可以打日志或者一些其他处理,可以用来进行数据淘汰分析
     8.在RemovalCause记录了所有被淘汰的原因:被用户删除,被用户替代,过期,驱逐收集,由于大小淘汰
 (4)guava cache的总结
    <1>是一个性能不错的,api丰富的LRU Map   
    <2>通过对guava cache的二次开发,让其可以进行java应用服务之间的缓存更新

5.基于Guava cache的优化:W-TinyLFU(LFU+LRU算法的变种)

 (1)guava cache的功能的确是很强大,满足了绝大多数的人的需求,但是其本质上还是LRU的一层封装
   (2)命中率W-TinyLFU 优于了guava cache,是最接近理想命中率的
   (3)读写吞吐量上面也是完爆guava cache
   (4)在W-TinyLFU,对这些事件的操作是通过异步操作,他将事件提交至队列,这里的队列的数据结构是RingBuffer
   (5)在W-TinyLFU中认为缓存读比写多很多,所以对于写操作是所有线程共享一个Ringbuffer
   (6)W-TinyLFU所有的数据都在ConcurrentHashMap中
   (7)W-TinyLFU的api借鉴了Guava的api,可以发现其基本一模一样

6.上面5种本地缓存不适于与分布式、微服务架构
7.本地缓存Ehcache可以支持分布式、微服务架构,弥补了上面5种的不足

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值