摘要
在上一篇文章 万字长文聊缓存(上)中,我们主要如何围绕着Http做缓存优化,在后端服务器的应用层同样有很多地方可以做缓存,提高服务的效率;本篇我们就来继续聊聊应用级的缓存。
缓存的命中率
缓存的命中率是指从缓存中获取到数据的次数和总读取次数的比率,命中率越高证明缓存的效果越好。这是一个很重要的指标,应该通过监控这个指标来判断我们的缓存是否设置的合理。
缓存的回收策略
基于时间
存活期:在设置缓存的同时设置该缓存可以存活多久,不论在存活期内被访站长交易问了多少次,时间到了都会过期
空闲期:是指缓存的数据多久没有被访问就过期
基于空间
设置缓存的存储空间,比如:设置缓存的空间是 1G,当达到了1G之后就会按照一定的策略将部分数据移除
基于缓存数量
设置缓存的最大条目数,当达到了设置的最大条目数之后按照一定的策略将旧的数据移除
基于Java对象引用
弱引用:当垃圾回收器开始回收内存的时候,如果发现了弱引用,它将立即被回收。
软引用:当垃圾回收器发现内存已不足的情况下会回收软引用的对象,从而腾出一下空间,防止发生内存溢出。软引用适合用来做堆缓存
缓存的回收算法
FIFO 先进先出算法
LRU 最近最少使用算法
LFU 最不常用算法
Java缓存的类型
堆缓存
堆缓存是指把数据缓存在JVM的堆内存中,使用堆缓存的好处是没有序列化和反序列化的操作,是最快的缓存。如果缓存的数据量很大,为了避免造成OOM通常情况下使用的时软引用来存储缓存对象;堆缓存的缺点是缓存的空间有限,并且垃圾回收器暂停的时间会变长。
Gauva Cache实现堆缓存
Cache<string, string> cache = CacheBuilder.newBuilder()
.build();
通过CacheBuilder构建缓存对象
Gauva Cache的主要配置和方法
put : 向缓存中设置key-value
V get(K key, Callable loader) : 获取一个缓存值,如果缓存中没有,那么就调用loader获取一个然后放入到缓存
expireAfterWrite : 设置缓存的存活期,写入数据后指定时间之后失效
expireAfterAccess : 设置缓存的空闲期,在给定的时间内没有被访问就会被回收
maximumSize : 设置缓存的最大条目数
weakKeys/weakValues : 设置弱引用缓存
softValues : 设置软引用缓存
invalidate/invalidateAll: 主动失效指定key的缓存数据
recordStats : 启动记录统计信息,可以查看到命中率
removalListener : 当缓存被删除的时候会调用此监听器,可以用于查看为什么缓存会被删除
Caffeine实现堆缓存
Caffeine是使用Java8对Guava缓存的重写版本,高性能Java本地缓存组件,也是Spring推荐的堆缓存的实现,与spring的集成可以查看文档https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-store-configuration-caffeine。
由于是对Guava缓存的重写版本,所以很多的配置参数都是和Guava缓存一致:
initialCapacity: 初始的缓存空间大小
maximumSize: 缓存的最大条数
maximumWeight: 缓存的最大权重
expireAfterAccess: 最后一次写入或访问后经过固定时间过期
expireAfterWrite: 最后一次写入后经过固定时间过期
expireAfter : 自定义过期策略
refreshAfterWrite: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
weakKeys: 打开key的弱引用
weakValues:打开value的弱引用
softValues:打开value的软引用
recordStats:开启统计功能
Caffeine的官方文档:https://github.com/ben-manes/caffeine/wiki
pom.xml中添加依赖

com.github.ben-manes.caffeine
caffeine
2.8.4
Caffeine Cache提供了三种缓存填充策略:手动、同步加载和异步加载。
手动加载:在每次get key的时候指定一个同步的函数,如果key不存在就调用这个函数生成一个值
public Object manual(String key) {
Cache<string, object> cache = Caffeine.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS) //设置空闲期时长
.maximumSize(10)
.build();
return cache.get(key, t -> setValue(key).apply(key));
}
public Function<string, object> setValue(String key){
return t -> “https://silently9527.cn”;
}
同步加载:构造Cache时候,build方法传入一个CacheLoader实现类。实现load方法,通过key加载value。
public Object sync(String key){
LoadingCache<string, object> cache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(1, TimeUnit.MINUTES) //设置存活期时长
.build(k -> setValue(key).apply(key));
return cache.get(key);
}
public Function<string, object> setValue(String key){
return t -> “https://silently9527.cn”;
}
异步加载:AsyncLoadingCache是继承自LoadingCache类的,异步加载使用Executor去调用方法并返回一个CompletableFuture
public CompletableFuture async(String key) {
AsyncLoadingCache<string, object> cache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(1, TimeUnit.MINUTES)
.buildAsync(k -> setAsyncValue().get());
return cache.get(key);
}
public CompletableFuture setAsyncValue() {
return CompletableFuture.supplyAsync(() -> “公众号:贝塔学JAVA”);
}
监听缓存被清理的事件
public void removeListener() {
Cache<string, object> cache = Caffeine.newBuilder()
.removalListener((String key, Object value, RemovalCause cause) -> {
System.out.println(“remove lisitener”);
System.out.println(“remove Key:” + key);
System.out.println(“remove Value:” + value);
})
.build();
cache.put(“name”, “silently9527”);
cache.invalidate(“name”);
}
统计
public void recordStats() {
Cache<string, object> cache = Caffeine.newBuilder()
.maximumSize(10000)
.recordStats()
.build();
cache.put(“公众号”, “贝塔学JAVA”);
cache.get(“公众号”, (t) -> “”);
cache.get(“name”, (t) -> “silently9527”);

CacheStats stats = cache.stats();
System.out.println(stats);

}
通过 Cache.stats() 获取到CacheStats。CacheStats提供以下统计方法:
hitRate(): 返回缓存命中率
evictionCount(): 缓存回收数量
averageLoadPenalty(): 加载新值的平均时间
EhCache实现堆缓存
EhCache 是老牌Java开源缓存框架,早在2003年就已经出现了,发展到现在已经非常成熟稳定,在Java应用领域应用也非常广泛,而且和主流的Java框架比如Srping可以很好集成。相比于 Guava Cache,EnCache 支持的功能更丰富,包括堆外缓存、磁盘缓存,当然使用起来要更重一些。使用 Ehcache 的Maven 依赖如下:

org.ehcache
ehcache
3.6.3
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);

ResourcePoolsBuilder resource = ResourcePoolsBuilder.heap(10); //设置最大缓存条目数

CacheConfiguration<string, string> cacheConfig = CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, String.class, resource)
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMinutes(10)))
.build();

Cache<string, string> cache = cacheManager.createCache(“userInfo”, cacheConfig);
ResourcePoolsBuilder.heap(10)设置缓存的最大条目数,这是简写方式,等价于ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES);
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, MemoryUnit.MB)设置缓存最大的空间10MB
withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMinutes(10))) 设置缓存空闲时间
withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(10))) 设置缓存存活时间
remove/removeAll主动失效缓存,与Guava Cache类似,调用方法后不会立即去清除回收,只有在get或者put的时候判断缓存是否过期
withSizeOfMaxObjectSize(10,MemoryUnit.KB)限制单个缓存对象的大小,超过这两个限制的对象则不被缓存
堆外缓存
堆外缓存即缓存数据在堆外内存中,空间大小只受本机内存大小限制,不受GC管理,使用堆外缓存可以减少GC暂停时间,但是堆外内存中的对象都需要序列化和反序列化,KEY和VALUE必须实现Serializable接口,因此速度会比堆内缓存慢。在Java中可以通过 -XX:MaxDirectMemorySize 参数设置堆外内存的上限
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);// 堆外内存不能按照存储条目限制,只能按照内存大小进行限制,超过限制则回收缓存
ResourcePoolsBuilder resource = ResourcePoolsBuilder.newResourcePoolsBuilder().offheap(10, MemoryUnit.MB);

CacheConfiguration<string, string> cacheConfig = CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, String.class, resource)
.withDispatcherConcurrency(4)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(10)))
.withSizeOfMaxObjectSize(10, MemoryUnit.KB)
.build();

Cache<string, string> cache = cacheManager.createCache(“userInfo2”, cacheConfig);
cache.put(“website”, “https://silently9527.cn”);
System.out.println(cache.get(“website”));
磁盘缓存
把缓存数据存放到磁盘上,在JVM重启时缓存的数据不会受到影响,而堆缓存和堆外缓存都会丢失;并且磁盘缓存有更大的存储空间;但是缓存在磁盘上的数据也需要支持序列化,速度会被比内存更慢,在使用时推荐使用更快的磁盘带来更大的吞吐率,比如使用闪存代替机械磁盘。
CacheManagerConfiguration persistentManagerConfig = CacheManagerBuilder
.persistence(new File("/Users/huaan9527/Desktop", “ehcache-cache”));

PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(persistentManagerConfig).build(true);
//disk 第三个参数设置为 true 表示将数据持久化到磁盘上
ResourcePoolsBuilder resource = ResourcePoolsBuilder.newResourcePoolsBuilder().disk(100, MemoryUnit.MB, true);

CacheConfiguration<string, string> config = CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, String.class, resource).build();
Cache<string, string> cache = persistentCacheManager.createCache(“userInfo”,
CacheConfigurationBuilder.newCacheConfigurationBuilder(config));

cache.put(“公众号”, “贝塔学JAVA”);
System.out.println(cache.get(“公众号”));
persistentCacheManager.close();
在JVM停止时,一定要记得调用persistentCacheManager.close(),保证内存中的数据能够dump到磁盘上。

万字长文聊缓存(下)- 应用级缓存相关推荐

  1. 万字长文:Stable Diffusion 保姆级教程

    万字长文:Stable Diffusion 保姆级教程 2022年绝对是人工智能爆发的元年,前有 stability.ai 开源 Stable Diffusion 模型,后有 Open AI 发布 C ...

  2. java l1 l2缓存,Java 两级缓存框架

    概述介绍 J2Cache 是 OSChina 目前正在使用的两级缓存框架(要求至少 Java 8).第一级缓存使用内存(同时支持 Ehcache 2.x.Ehcache 3.x 和 Caffeine) ...

  3. nuxt渲染html文件,Nuxt页面级缓存

    虽然 Vue 的服务器端渲染 (SSR) 相当快速,但是由于需要为每次请求为了避免交叉请求状态污染,都创建一个新的根Vue实例,创建组件实例和虚拟 DOM 节点的开销,无法与纯基于字符串拼接的模板的性 ...

  4. Hibernate缓存 - 第一级缓存

    Hibernate缓存 - 第一级缓存 欢迎使用Hibernate缓存 - 一级缓存示例教程.最近我们研究了Hibernate架构,hibernate映射以及如何使用HQL以面向对象的方式触发SQL查 ...

  5. SpringBoot 集成 layering-cache 实现两级缓存调研与实践

    前言 对于系统查多改少的数据,可以通过缓存来提升系统的访问性能.一般情况下我们会采用 Redis ,但是如果仅仅依赖 Redis 很容易出现缓存雪崩的情况.为了防止缓存雪崩可以通过 Redis 高可用 ...

  6. Springboot+caffeine 实现两级缓存

    目录: 缓存.两级缓存 spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明 spring boot + spring cache caffeine简介 sp ...

  7. 【Caffeine进阶】Redis+Caffeine 两级缓存实战,性能爆缸

    往期回顾 博主前面发过一篇[缓存框架Caffeine]初级篇,主要介绍了Caffeine的入门级使用!地址https://blog.csdn.net/Number_oneEngineer/articl ...

  8. Redis+Caffeine两级缓存

    1.前言 在高性能的服务架构设计中,缓存是一个不可或缺的环节.在实际的项目中,我们通常会将一些热点数据存储到Redis或MemCache这类缓存中间件中,只有当缓存的访问没有命中时再查询数据库.在提升 ...

  9. hibernate mysql缓存机制_Hibernate的缓存机制

    面试常问到的问题: 首先说下hibernate缓存的作用(即为什么要用缓存机制),然后再具体说说Hibernate中缓存分类情况,最后可以举例: Hibernate缓存的作用: Hibernate是一 ...

最新文章

  1. AI实验室•西安站 教你用人脸识别打造爆款应用
  2. python流程控制-Python流程控制常用工具详解
  3. 区块链BaaS云服务(24)秘猿科技CITA
  4. 【完结篇】专栏 | 基于 Jupyter 的特征工程手册:特征降维
  5. OpenGL编程指南7:视图-
  6. python 处理xml pandas_Python数据处理分析,解决pandas中所有的Excel疑难杂症(上)
  7. [css] 如何阻止:hover、:active等鼠标行为状态的触发?
  8. ant4 多个form 验证_爬虫遇到头疼的验证码?Python实战讲解弹窗处理和验证码识别...
  9. python计算最大回撤_Python做量化投资评价策略风险 如何计算最大回撤?
  10. wpf label字体为斜体_快来收下这份字体设计必备知识点
  11. 编写模块时的声明(含MODULE_LICENSE等)
  12. svn拉取文件失败_转自: linux svn命令行无法拉取中文名称的文件
  13. python if else break_Python条件判断 if-else for循环 while循环 break continue
  14. HTTP 405错误解决方法
  15. Python:对已有内容的TXT文件追加读写
  16. 全球及中国毫米波人体安检仪行业竞争格局分析与投资战略规划研究报告2022-2028年
  17. android 涨潮动画加载_这是迪士尼动画片《长发公主》中王国的原型,涨潮时才浮出海面...
  18. Prometheus 系列开篇:为什么要学 Prometheus ?
  19. 豆瓣APP上线7.0新版本,从工具到社区的进化之路
  20. HTTP基本使用方法

热门文章

  1. 关于膝盖矫形器的功能用途
  2. 多语言笔记系列:开篇 Polyglot Notebooks 概要与使用
  3. 20170408 mofan pandas:code lesson 06
  4. appsync for ios7.x安装
  5. 如何删除iphone中的文稿与数据
  6. 核验大量数据是否重复
  7. Dell开机时报错smartaudio无法运行
  8. 我的电磁学讲义14:动生电动势和感生电动势
  9. python最佳实践指南试题_8.1. 关于这份指南
  10. 计算机考研备考指南,计算机考研备考指南