Nivelle 开拓视野冲破艰险看见世界 身临其境贴近彼此感受生活

应用级缓存

2017-10-11
nivelle

缓存命中率

缓存命中率是从缓存中读取数据的次数与总读取次数的比率,命中率越高越好.缓存命中率=从缓存中读取次数/(总读取次数[从缓存中读取次数+从慢速设备上读取次数])

缓存回收策略

  • 基于空间

基于空间指缓存设置了存储空间,如设置10MB,当达到存储空间上限时,按照一定的策略移除数据.

  • 基于容量

基于容量指缓存设置了最大大小,当缓存的条目超过最大大小时,按照一定的策略移除旧数据.

  • 基于时间

TTL(Time To Live):存活期,即缓存数据从创建开始直到到期的一个时间段(不管在这个时间段内有没有被访问,缓存数据都将过期)

TTI(Time To Idle):空闲期,即缓存数据多久没有被访问后移除缓存的时间.

  • 基于Java对象引用

    • 软引用:如果一个对象是软引用,那么当JVM堆内存不足时,垃圾回收器可以回收这些对象.软引用适合用来做缓存,从而当jvm堆内存不足时,可以回收这些对象腾出一些空间供强引用对象使用,从而避免OOM. -弱引用:当垃圾回收器回收内存时,如果发现弱引用,则将它立即回收.相对于软引用,弱引用有更短的生命周期.
  • 回收算法

    使用基于空间和基于容量的缓存会使用一定的策略移除旧数据,常见的如下:

    • FIFO:先进先出算法,即先放入缓存的先被移除
    • LRU:最近最少使用算法,使用时间距离现在最久的那个被移除.
    • LFU:最不常用算法,一定时间段内使用次数最少的那个被移除.
  • Java缓存类型

堆缓存: 使用java堆内存来存储缓存对象.使用堆缓存的好处是没有序列化/反序列化是最快的缓存.缺点也很明显,当缓存数量很大的时候,GC暂停时间会变长,存储容量受限于堆空间设计.一般通过软引用/弱引用来存储缓存对象,即但堆内存不足时,可以强制回收这部分内存释放堆内存空间.一般使用堆内存存储较热数据,可以使用guava cahe,ehcache 3.x ,MapDB实现.

堆外缓存: 即缓存数据存储在堆外内存,可以减少GC暂停时间(堆对象转移到堆外,GC扫描和移动的对象变少了),可以支持更大的缓存空间(只受机器内存大小限制,不受堆空间的影响).但是,读取数据时需要序列化和反序列化,因此会比堆缓存慢很多.可以使用Ehcache 3.x,MapDB实现.

磁盘缓存: 即缓存数据存储在磁盘上,在Jvm重启时数据环视存在的,儿堆缓存/堆外缓存数据将会丢失,需要重新加载.可以使用Echache3.x,MapDB实现.

分布式缓存: 上面的缓存都是进程内缓存和磁盘缓存,在多JVM实例的情况下,会存在两个问题:1.单机容量问题;2.数据一致性问题(多态JVM实例的缓存数据不一致);3.缓存不命中时,需要回溯到DB/服务请求多变问题:每个实例在缓存不命中的情况下都会回溯到DB加载数据,因此,多实例后DB整体的访问量就变多了,解决办法是可以使用如一致性哈希分片算法.可以使用ehcache-clustered实现java进程间分布式缓存.当然也可以使用如redis实现分布式缓存.

两种模式如下:

  • 单机时:存储最热的数据到堆缓存,相对热的数据到堆外缓存,不热的数据到磁盘缓存
  • 集群时:存储最热的数据到堆缓存,相对热的数据到堆外缓存,全量数据到分布式缓存.

上一篇 jvm内存区域

下一篇 java内存模型.

评论