多级缓存之JVM进程缓存

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本地缓存、RedisTomcat的查询

  • 另一个就是在Tomcat中实现JVM进程缓存

2. 初识Caffeine

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们把缓存分为两类:

  • 分布式缓存,例如Redis
    • 优点:存储容量更大、可靠性更好、可以在集群间共享
    • 缺点:访问缓存有网络开销
    • 场景:缓存数据量较大、可靠性要求较高、需要在集群间共享
  • 进程本地缓存,例如HashMapGuavaCache
    • 优点:读取本地内存,没有网络开销,速度更快
    • 缺点:存储容量有限、可靠性较低、无法共享
    • 场景:性能要求较高,缓存数据量较小

利用Caffeine框架来实现JVM进程缓存。

Caffeine 是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是CaffeineGitHub地址: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);
}

Caffeine既然是缓存的一种,肯定需要有缓存的清除策略,不然的话内存总会有耗尽的时候。

Caffeine提供了三种缓存驱逐策略:

  • 基于容量:设置缓存的数量上限

    // 创建缓存对象
    Cache<String, String> cache = Caffeine.newBuilder().maximumSize(1) // 设置缓存大小上限为 1.build();
    
  • 基于时间:设置缓存的有效时间

    // 创建缓存对象
    Cache<String, String> cache = Caffeine.newBuilder()// 设置缓存有效期为 10 秒,从最后一次写入开始计时 .expireAfterWrite(Duration.ofSeconds(10)) .build();
  • 基于引用:设置缓存为软引用或弱引用,利用GC来回收缓存数据。性能较差,不建议使用。

注意:在默认情况下,当一个缓存元素过期的时候,Caffeine不会自动立即将其清理和驱逐。而是在一次读或写操作后,或者在空闲时间完成对失效数据的驱逐。

3. 实现JVM进程缓存

3.1. 需求

利用Caffeine实现下列需求:

  • 给根据id查询商品的业务添加缓存,缓存未命中时查询数据库
  • 给根据id查询商品库存的业务添加缓存,缓存未命中时查询数据库
  • 缓存初始大小为100
  • 缓存上限为10000

3.2. 实现

首先,我们需要定义两个Caffeine的缓存对象,分别保存商品、库存的缓存数据。

item-servicecom.dcxuexi.item.config包下定义CaffeineConfig类:

package com.dcxuexi.item.config;import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.dcxuexi.item.pojo.Item;
import com.dcxuexi.item.pojo.ItemStock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CaffeineConfig {@Beanpublic Cache<Long, Item> itemCache(){return Caffeine.newBuilder().initialCapacity(100).maximumSize(10_000).build();}@Beanpublic Cache<Long, ItemStock> stockCache(){return Caffeine.newBuilder().initialCapacity(100).maximumSize(10_000).build();}
}

然后,修改item-service中的com.dcxuexi.item.web包下的ItemController类,添加缓存逻辑:

@RestController
@RequestMapping("item")
public class ItemController {@Autowiredprivate IItemService itemService;@Autowiredprivate IItemStockService stockService;@Autowiredprivate Cache<Long, Item> itemCache;@Autowiredprivate Cache<Long, ItemStock> stockCache;// ...其它略@GetMapping("/{id}")public Item findById(@PathVariable("id") Long id) {return itemCache.get(id, key -> itemService.query().ne("status", 3).eq("id", key).one());}@GetMapping("/stock/{id}")public ItemStock findStockById(@PathVariable("id") Long id) {return stockCache.get(id, key -> stockService.getById(key));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/134825.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】了解文件的inode元信息,以及日志分析

目录 一、inode表结构&#xff0c;以及元信息 1、了解inode信息有哪些 2、关于inode表的说明 Linux中访问文件的过程&#xff1a; 3、硬连接与软连接的区别&#xff0c;&#xff08;请看前面&#xff0c;写过的&#xff09; 二、文件系统的备份与恢复 三、几种常见的日志…

idea 模板参数注释 {@link}

1. 新增组 2. 设置方法注释及变量 增加模板文本 ** * $param$ * return {link $return$} */3. 设置变量表达式 勾选跳过param 参数表达式 groovyScript("def result ;def params \"${_1}\".replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).toList();def param…

小白学爬虫:手机app分享商品短连接获取淘宝商品链接接口|淘宝淘口令接口|淘宝真实商品链接接口|淘宝商品详情接口

通过手机APP分享的商品短链接&#xff0c;我们可以调用相应的接口来获取淘口令真实URL&#xff0c;进而获取到PC端的商品链接及商品ID。具体步骤如下&#xff1a; 1、通过手机APP分享至PC端的短链接&#xff0c;调用“item_password”接口。 2、该接口将返回淘口令真实URL。 3…

kafka集群部署

1、首先部署zookeeper apiVersion: v1 kind: Service metadata:labels:app: zookeeper-clusternamespace: kafka-risktechname: zookeeper-cluster spec:selector:app: zookeeper-clusterports:- name: clientport: 2181targetPort: 2181- name: followerport: 2888targetPort…

[Linux] GRUB引导 学习笔记(一)

目录 概念 2.1 BIOS 2.2 UEFI 2.3 MBR与GPT 2.3.1 MBR 2.3.2 GPT 2.3.3 总结 2.4 GRUB GRUB2和GRUB Legacy区别 进入GRUB命令行 命令 GRUB工具命令 GRUB2配置 1.主要配置文件 2. 通过/etc/default/grub文件生成grub.cfg 定制GRUB的步骤 概念 BIOS、UEFI、MBR、G…

Programming abstractions in C阅读笔记:p184-p195

《Programming Abstractions In C》学习第61天&#xff0c;p184-p195总结。 一、技术总结 1.mutual recursion 2.natural number (1)定义 p184, If you limit the domain of possible values to the set of natural numbers,which are defined simply as the set of nonne…

visual studio 启用DPI识别功能

在开发widow程序时&#xff0c;有时必须将电脑 设置-->显示-->缩放与布局-->更改文本、应用项目的大小-->100%后&#xff0c;程序的画面才能正确运行&#xff0c;居说这是锁定了dpi的原因&#xff0c;需要启dpi识别功能。设置方法如下&#xff1a; 或者

C/S架构学习之组播

组播&#xff1a;过多的广播会占用网络带宽&#xff0c;产生广播风暴的现象&#xff0c;从而影响正常的通信活动&#xff1b;组播&#xff08;或者多播&#xff09;是局域网内部的通信&#xff0c;只有加入到某个多播组的主机才能收到数据&#xff1b;组播的方式既可以发给多个…

2023中国视频云市场报告:腾讯云音视频解决方案份额连续六次蝉联榜首,加速全球化布局

近日&#xff0c;国际数据公司&#xff08;IDC&#xff09;发布了《中国视频云市场跟踪&#xff08;2023上半年&#xff09;》报告&#xff0c;腾讯云音视频的解决方案份额连续六次蝉联榜首&#xff0c;并在视频生产创作与媒资管理市场份额中排名第一。同时&#xff0c;在实时音…

虹科示波器 | 汽车免拆检测 | 2017款长安福特翼虎车发动机故障灯异常点亮

一、故障现象 一辆2017款长安福特翼虎车&#xff0c;搭载CAF488WQ9发动机&#xff0c;累计行驶里程约为8.9万km。该车因发动机故障灯异常点亮在其他维修厂检修&#xff0c;维修人员用故障检测仪检测&#xff0c;提示气缸3失火&#xff0c;调换火花塞、点火线圈及喷油器&#xf…

动态、静态IP地址设置方法

目录 一、三种网络模式应用场景以及区别 1、 NAT&#xff08;Network Address Translation&#xff09;模式&#xff1a; 2、仅主机&#xff08;Host-Only&#xff09;模式&#xff1a; 3、桥接&#xff08;Bridged&#xff09;模式&#xff1a; 二、配置步骤 &#xff1a…

poi多sheet,模板导出数据

/*** 导出Excel* param response 响应对象* param headName 表头* param List 数据*/public static void exportExcel(HttpServletResponse response, String headName, List<数据对象> list) throws IOException {//读取模板Resource resourcenew ClassPathResourc…

SSM之spring注解式缓存redis

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.Redis与SSM的整合 1.1.添加Redis依赖 在Maven中添加Redis的依赖 <redis.version>2.9.0</redis.…

0X03

红包题第二弹 看到源码里面的提示 ?cmdphpinfo(); 看到源码 kk 关键点就是有两个正则表达式 第一个 preg_match("/[A-Za-oq-z0-9$]/",$cmd) 第二个 preg_match("/\~|\!|\|\#|\%|\^|\&|\*|\(|\)|\&#xff08;|\&#xff09;|\-|\_|\{|\}|\[|\]|\|\&q…

蓝绿部署:实现无缝可靠的软件发布

在快节奏的软件开发世界中&#xff0c;在不造成中断或停机的情况下向用户提供新功能和更新是一项至关重要的挑战。这就是蓝绿部署策略有用的地方。组织可以通过使用称为“蓝绿部署”的发布管理策略&#xff0c;以安全有效的方式推出其软件的新版本。在快节奏的软件开发世界中&a…

【独家揭秘】跨境电商源码独立开发,软著认证,前后端全开源,无加密,交付源码,商用无忧!

在这个数字化快速发展的时代&#xff0c;跨境电商已成为全球商业的重要趋势。为了帮助您快速进入这个潜力巨大的市场&#xff0c;我们独家推出了一款经过全面验证的跨境电商源码解决方案!这款源码具有独立开发、软著认证、前后端全开源、无加密等特点&#xff0c;为您的商业运营…

html中使用JQ自定义锚点偏移量

问题&#xff1a;一般情况下使用href跳转达到效果。如果页面中头部固定住了&#xff0c;点击瞄点的时候自动是最上面&#xff0c;头部会给它覆盖掉一部分&#xff0c;所以要在点击之后额外再加头部高度 <a href"#aa">Technical Documents</a><div id&…

批量迁移redis实例的key

我们知道migrate 命令可以迁移redis的多个key&#xff0c;但是如果redis的key有非常多&#xff0c;那用起来就很不方便了。 所以下面分享一个脚本来实现批量key的迁移&#xff0c;主要使用的命令为dump和restore 脚本如下&#xff1a; #!/bin/bash redis-cli -h host1 -p 63…

浅谈开源策略的实例:CGAL计算几何库

免责声明&#xff1a;本博客旨在分享我对开源策略的理解和体会&#xff0c;不代表任何组织或机构的立场或观点&#xff0c;也不构成任何商业或投资的建议或担保。本博客的内容可能存在错误或遗漏&#xff0c;也可能随着时间的推移而变得过时或不适用。请在使用或依赖本博客的内…

吴恩达《机器学习》6-1->6-3:分类问题、假设陈述、决策界限

一、什么是分类问题&#xff1f; 在分类问题中&#xff0c;我们试图预测的变量&#x1d466;是离散的值&#xff0c;通常表示某种类别或标签。这些类别可以是二元的&#xff0c;也可以是多元的。分类问题的示例包括&#xff1a; 判断一封电子邮件是否是垃圾邮件&#xff08;二…