1.什么是多级缓存
传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,如图:
存在下面的问题:
- 请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈
- Redis缓存失效时,会对数据库产生冲击
多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat压力,提升服务性能:
浏览器访问静态资源时,优先读取浏览器本地缓存
访问非静态资源(ajax查询数据)时,访问服务端
请求到达Nginx后,优先读取Nginx本地缓存
如果Nginx本地缓存未命中,则去直接查询Redis(不经过Tomcat)
如果Redis查询未命中,则查询Tomcat
请求进入Tomcat后,优先查询JVM进程缓存
如果JVM进程缓存未命中,则查询数据库
在多级缓存架构中,Nginx内部需要编写本地缓存查询、Redis查询、Tomcat查询的业务逻辑,因此这样的nginx服务不再是一个反向代理服务器,而是一个编写业务的Web服务器了。
因此这样的业务Nginx服务也需要搭建集群来提高并发,再有专门的nginx服务来做反向代理,如图:
另外,我们的Tomcat服务将来也会部署为集群模式:
可见,多级缓存的关键有两个:
一个是在nginx中编写业务,实现nginx本地缓存、Redis、Tomcat的查询
另一个就是在Tomcat中实现JVM进程缓存
其中Nginx编程则会用到OpenResty框架结合Lua这样的语言。
2.JVM进程缓存
为了演示多级缓存的案例,我们先准备一个商品查询的业务。
2.1.导入案例
参考课前资料的:《案例导入说明.md》
2.2.初识Caffeine
缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们把缓存分为两类:
分布式缓存,例如Redis:
优点:存储容量更大、可靠性更好、可以在集群间共享
缺点:访问缓存有网络开销
场景:缓存数据量较大、可靠性要求较高、需要在集群间共享
进程本地缓存,例如HashMap、GuavaCache:
优点:读取本地内存,没有网络开销,速度更快
缺点:存储容量有限、可靠性较低、无法共享
场景:性能要求较高,缓存数据量较小
我们今天会利用Caffeine框架来实现JVM进程缓存。
Caffeine是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是Caffeine。GitHub地址:https://github.com/ben-manes/caffeine
Caffeine的性能非常好,下图是官方给出的性能对比:
可以看到Caffeine的性能遥遥领先!
缓存使用的基本API:
@Test void testBasicOps() { // 构建cache对象 Cache<String, String> cache = Caffeine.newBuilder().build(); // 存数据 cache.put("gf", "迪丽热巴"); // 取数据 String gf = cache.getIfPresent("gf"); System.out.println("gf = " + gf); // 取数据,包含两个参数: // 参数一:缓存的key // 参数二:Lambda表达式,表达式参数就是缓存的key,方法体是查询数据库的逻辑 // 优先根据key查询JVM缓存,如果未命中,则执行参数二的Lambda表达式 String defaultGF = cache.get("defaultGF", key -> { // 根据key去数据库查询数据 return "柳岩"; }); System.out.println("defaultGF = " + defaultGF); }