应用级缓存
让数据更贴近使用者
9.3 缓存回收策略
1. 基于空间:到达存储空间上限
2. 基于容量:缓存的条目超过上限
3. 基于时间
TTL(Time To Live):存活期,超过过期时间被回收
TTI(Time To Idle):空闲期,空闲多长时间被回收
4. 基于Java对象引用:软引用/弱引用引用的对象
5. 回收算法:FIFO、LRU、LFU
9.4 Java缓存类型
堆缓存:使用Java堆内存缓存对象,没有序列化和反序列化,也没有网络开销,是最快的缓存。缺点是占用堆内存,导致GC变得频繁。一般使用软引用/弱引用来存储缓存对象,当内存不足时可以顺利回收。使用Guava Cache、Ehcache 3.x、MapDB实现
堆外缓存:存储在堆外内存,减少GC,并且支持更大的缓存空间,但需要序列化和反序列化数据。使用Ehcache 3.x、MapDB实现
磁盘缓存:缓存数据存储在磁盘上,重启后缓存依然在。使用Ehcache 3.x、MapDB实现
分布式缓存:处理多JVM实例的情况
1. 数据一致性问题:多台JVM实例缓存数据不一致?书上写使用缓存则表示允许一定程度的不一致。
2. 缓存失效,多实例都去请求数据库造成访问浪费。可以使用一致性哈希分片算法,不同实例缓存不同数据
使用ehcache-clustered(配合Terracotta server)或者Redis
单机时:堆缓存存最热的数据、堆外缓存存相对热的数据、不热的数据存磁盘
集群时:堆缓存存最热的数据、堆外缓存存相对热的数据、全量数据存分布式缓存
9.6 缓存使用模式实践
1. Cache-Aside
读:先读缓存,缓存失效再读数据库,并将数据库内容放入缓存
写:先写数据库,写入成功后立即 同步/删除 缓存
业务代码负责维护缓存
2. Cache-As-SoR
将缓存当成数据库,所有操作都针对缓存,后续将操作同步到数据库,有三种模式:read-through、write-through、write-behind
1. Read-Through
业务代码调用Cache读,如果Cache不命中,由Cache而不是由业务代码回源到数据库并设置到缓存。使用该模式需要配置一个CacheLoader组件去数据库查询。使用CacheLoader的优势是(1)应用代码更简洁(2)其内部使用锁,保证只有一条线程读库,这一条是Guava Cache实现的
2. Write-Through
穿透写/直写模式。业务代码调用Cache写,由Cache负责同步写缓存和写数据库。需要配置一个CacheWriter组件来回写数据库。Guava Cache不支持,Ehcache支持
3. Write-Behind
回写模式。异步写数据库和Cache。异步之后可以实现批量写、合并写、延时和限流。