一、前沿:
引自: Java本地缓存技术选型(Guava Cache、Caffeine、Encache)
对一个java后台开发者而言,提到缓存,第一反应就是redis和memcache。利用这类缓存足以解决大多数的性能问题了,并且java针对这两者也都有非常成熟的api可供使用。但是我们也要知道,这两种都属于remote cache(分布式缓存),应用的进程和缓存的进程通常分布在不同的服务器上,不同进程之间通过RPC或HTTP的方式通信。这种缓存的优点是缓存和应用服务解耦,支持大数据量的存储,缺点是数据要经过网络传输,性能上会有一定损耗。
与分布式缓存对应的是本地缓存,缓存的进程和应用进程是同一个,数据的读写都在一个进程内完成,这种方式的优点是没有网络开销,访问速度很快。缺点是受JVM内存的限制,不适合存放大数据。
本地缓存和应用同属于一个进程,使用不当会影响服务稳定性,所以通常需要考虑更多的因素,例如容量限制、过期策略、淘汰策略、自动刷新等。常用的本地缓存方案有:
- 根据HashMap自实现本地缓存
- Guava Cache
- Caffeine
- Encache
二、Guava Cache
源码解析:git地址
(必看,重点关注)Google Guava Cache 全解析:底层结构,方法解析,(全)
1、Guava Cache有以下两种创建方式
- CacheLoader
- Callable
2、LRU缓存回收算法
Guava Cache中借助读写队列来实现LRU算法。
LRU(Least?recently?used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
- 1.新数据插入到链表头部;
- 2.每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
- 3.当链表满的时候,将链表尾部的数据丢弃。
3、LocalCache数据结构
LocalCache为Guava Cache的核心类,先看一个该类的数据结构: LocalCache的数据结构与ConcurrentHashMap很相似,都由多个segment组成,且各segment相对独立,互不影响,所以能支持并行操作。每个segment由一个table和若干队列组成。缓存数据存储在table中,其类型为AtomicReferenceArray。
三、Caffeine
四、三种缓存对比:
从性能上进行比较,Caffeine最优、GuavaCache次之,Encache最差。
从易用性角度,Guava Cache、Caffeine和Encache都有十分成熟的接入方案,使用简单。
从功能性角度,Guava Cache和Caffeine功能类似,都是只支持堆内缓存,Encache相比功能更为丰富。
总体来说,对于本地缓存的方案中,
- 笔者比较推荐Caffeine,性能上遥遥领先。
- 虽然Encache功能更为丰富,甚至提供了持久化和集群的功能,但是这些功能完全可以依靠其他方式实现。
- 真实的业务工程中,建议使用Caffeine作为本地缓存,另外使用redis或者memcache作为分布式缓存,构造多级缓存体系,保证性能和可靠性。