缓存-基础理论和Guava Cache介绍

缓存-基础理论和Guava Cache介绍

缓存基础理论

       缓存的容量和扩容

       缓存初始容量、最大容量,扩容阈值以及相应的扩容实现。

       缓存分类

       本地缓存:运行于本进程中的缓存, 如Java的 concurrentHashMap,  Ehcache,Guava Cache。

       分布式缓存:支持分布式环境读取的缓存, 如Redis,

       另外还有其他特定场景的缓存,如:浏览器缓存、CDN、反向代理、数据库缓存。

      

       多级缓存

       缓存在系统中根据作用域形成的层次级的缓存,如mybatis的一级(sqlSession级)、二级缓存(跨sqlSession mapper级); 本地缓存+分布式缓存的多级组合;

      

缓存过期策略

缓存数据的过期清理算法。通常有:设置key的过期时间,当内存不足时的数据淘汰算法,常见的淘汰算法如:LRU (Least Recently Used)最近最少使用算法,FIFO先进先出算法,LFU (Least Frequently Used)剔除最近使用频率最低的数据,随机算法等。

缓存更新策略

缓存更新策略是指定时对缓存中数据进行更新的策略。包括定时刷新,另外也指缓存和后台数据源的数据同步策略。如常见的三种更新策略:

Cache Aside Pattern(旁路缓存模式):写数据:先更新db,删除缓存;读数据时如果存在,则直接返回;如果不存在从db加载写入缓存。

Read/Write Through Pattern(读写穿透模式):缓存作为主数据源,写入数据写入缓存,缓存再负责更新到db。读取时如读取不到则将数据从db加载到缓存再从缓存返回。

Write Behind Pattern (异步缓存写入模式):和Read/Write Through Pattern区别是更新db时是异步的批量更新模式。

       缓存预热

       根据业务场景,提前将缓存数据加载到缓存中,可以避免使用时才查询数据库。

       缓存命中率

缓存命中是指通过缓存读取数据时直接从缓存获取数据,未命中是指无法从缓存获取数据,或者是缓存中不存在,或者是数据已过期,需要重新从该数据库或其他敌法加载数据到缓存中。缓存命中率是缓存使用的最重要指标,命中率越高缓存的提升越高。缓存框架应提供缓存命中率的统计和查看工具。

       缓存命中率的影响因素主要包括:业务场景、缓存粒度、缓存容量、过期策略等因素。

       缓存雪崩/缓存穿透/缓存击穿

       缓存雪崩:缓存大量数据失效或则缓存系统出现异常,造成大量请求直接形成对数据库的巨大压力。解决方法:缓存失效随机;缓存集群; key永不失效; 请求加锁等。

       缓存穿透:请求数据库中不存在的数据,缓存失效。解决方案:布隆过滤器;缓存空对象。

       缓存击穿:指当缓存中热点数据过期,在热点数据重新载入缓存之前,大量的查询请求穿过缓存,直接查询数据库。 解决方案:key 永不过期;分布式锁。

      

Guava Cache

       Guava Cache 是Guava Java工具包中提供的本地缓存工具,可以作为独立的本地缓存或多级缓存中的本地缓存使用。  

数据结构

图1 Guava Cache存储数据结构

Guava Cache 将缓存换分为多个段(Segment[]), 每个段都是ReentrantLock的子类,段和段之间是完全并行,段内是写入加锁,读取不加锁的并发控制。

       Segment内部数据结构使用AtomicReferenceArray来表示Hash入口,相同hash在AtomicReferenceArray的同一位置形成一个链表。

有多少个Segment?

  1. 由配置参数ConcurrencyLevel决定:ConcurrencyLevel 默认是4,最大是65536(1<<16)
  2. (!evictsBySize() ||segmentCount * 20 <= maxWeight):当制定了最大数据权值时,通过段数*20 < 最大权值来避免过于稀疏的端。

int segmentShift = 0;

int segmentCount = 1;

while (segmentCount < concurrencyLevel && (!evictsBySize() || segmentCount * 20 <= maxWeight)) {

   ++segmentShift;

   segmentCount <<= 1;

}

this.segmentShift = 32 - segmentShift;

segmentMask = segmentCount - 1;

如 segmentCount = 4时, segmentShift = 32 – 2 = 30, segmentMask = 0x03

无符号Hash, 最高的两位用于识别Segment位置, segments[(hash >>> segmentShift) & segmentMask]。

数据的释放

       除了根据缓存协议的过期时间、数据替换策略对缓存元素进行释放外, Guava Cache可以设置缓存key/value应用强度,是的在内存不足时缓存数据可以得到释放。

      

       Java引用强度

       强引用:普通对象引用,当对象存在引用时不会回收。

软引用: SoftReference<String> ref = new SoftReference<String>(“test”);,当内存足够时,对象不会被回收, 当内存不足时,对象会被回收。

弱引用:WeakReference<T> 垃圾回收中,不管内存是否充足,如果对象只存在弱引用则被回收。如果WeakReference指定ReferenceQueue的话,在释放的时候就把这个Reference放到ReferenceQueue里面。

虚引用: PhantomReference<T>虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

查找过程

  1. 定位Segment
  2. 定位Segment内数组Hash索引: table.get(hash & (table.length() - 1));
  3. 遍历同hash的队列找出相等的key
  4. 检查是否过期, 如不过期返回,过期则尝试加载后返回。

过期检查

       accessQueue 缓存元素引用的队列,当元素被使用(包括加载)时加入accessQueue的队尾,也就是accessQueue中包含缓存所有元素的引用。

writeQueue: 缓存元素引用的队列,当元素被写入时,加入到writeQueue队尾。

当每次获取某个元素时,都对段内元素按AccessQueue和WriteQueue顺序检查元素是否过期,因为两个队列都是按照操作顺序(加载或写)加入队列的, 所以只需要从头移除过期元素直到碰到第一个未过期的元素即可。

注: 将元素提前进行排序或分组以加快后续功能的查找速度是常用的优化方法,类似如RocketMQ延期队列按延期时间划分到不同的子主题中,也体现了性能优化:分而治之、提前部署、异步非阻塞的思维之一:提前部署。 缓存本身也是该思维的体现。

加载

       当查找无法找到元素或元素已过期时将触发一个元素加载的过程, 元素加载细分为两个操作: 在Segment中加入引用;实际进行元素加载。

  1. 在Segment上加锁,完成添加引用操作后释放Segment锁。
  2. 在新的引用入口上加同步锁,完成实际的元素加载后释放。如果是新建的引用,针对引用对象进行枷锁,完成加载。如其他线程此时读取对象,发现该引用对象属于加锁状态,则等待元素的加载完成后获取。

注:分段加锁体现了多并发所操作的重要原则之一:正确确定锁的作用范围。 引入更多层次上的锁,避免粗放使用,造成锁的范围扩大。其他类似如:数据库的表锁、行锁。

新增/更新(put)

Put操作时,在Segment中根据key对应hash值查找到元素, 如查找则更新值,如无法找到,新建元素引用并加入到响应的索引位置。新增元素将放置于AtomicRefereceArray中索引位置, 新增元素的Next引用指向原索引位置的元素。

吸入之前将对Segment进行清除: 已过期的,或因弱引用已经被释放的key/value对象。

扩容

       当Segment中元素数量超过指定阈值时将触发扩容。阈值是当前AtomicReferencyArray长度的3/4。扩容在Segment锁下进行。

       扩容过程:

  1. 新建一个常度为原长度两倍的AtomicReferenceArray。
  2. 遍历原AtomicReferenceArray 所有元素,计算Key的hash值,按照新的长度取余插入新引用数组中, 插入方式同新增。
  3. 使用新的AtomicReferenceArray。

数据同步方案

       Guava Cache 的数据同步有三种模式:

  1. 客户PUT或REPLACE数据。
  2. 查找时无法找到或则元素已经过期时进行同步的加载。
  3. 异步批量刷新。

过期策略

       设置过期时间

Guava Cache 通过设置expireAfterAccess(读取后过期时间),expireAfterWrite(写入后过期时间),refreshAfterWrite(写入后刷新过期时间)三个过期时间触发数据刷新

最近最少使用替换算法

       当设置了缓存的最大权重并且当前段的总权重已经超过最大权重,则需要进行数据的主动清理,也就是缓存中的过期策略或替换算法。

       Guava Cache使用最近最少使用的算法。 当超过是使用AccessQueue将最早的元素释放,直到总权重小于最大权重。

命中率

       Guava cache使用 StatsCounter 统计缓存的命中,当缓存命中或未命中时进行计数。通过Cache接口的CacheStats stats()方法展示信息。

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

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

相关文章

Mac上好用的翻译软件推荐 兼容m

Mac翻译软件可以用在学习&#xff0c;工作&#xff0c;生活当中&#xff0c;一款好用的翻译软件&#xff0c;具有翻译准确&#xff0c;翻译快速等基本特点&#xff0c;能够帮您提高工作效率。Mac上有什么好用的翻译软件呢&#xff1f;今天小编为大家整理了6款好用的Mac翻译软件…

C语言--typedef的使用

前言 在C语言中使用结构体时必须加上struct这个关键字,那有没有办法省略这个呢?要想达到这个目的就 需要用到关键字typedef,顾名思义”类型定义”。 typedef 数据类型 新的别名; 它是用来操作数据类型。其主要作用有两个: 1.给一个较长较复杂的类型取一个简单的别名。 2.给类…

MySQL数据库入门到大牛_03_SQL概述、基本的SELECT语句、显示表结构、过滤数据

文章目录 1. SQL概述1.1 SQL背景知识1.2 SQL语言排行榜1.3 SQL 分类1.4 数据库内容 2. SQL语言的规则与规范2.1 基本规则2.2 SQL大小写规范 &#xff08;建议遵守&#xff09;2.3 注 释2.4 命名规则&#xff08;暂时了解&#xff09;2.5 数据导入指令2.5.1 source 文件全路径名…

零代码编程:用ChatGPT批量将Mp4视频转为Mp3音频

文件夹中有很多mp4视频文件&#xff0c;如何利用ChatGPT来全部转换为mp3音频呢&#xff1f; 在ChatGPT中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个批量将Mp4视频转为Mp3音频的任务&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;…

Springboot中解析JSON字符串(jackson库ObjectMapper解析JSON字符串)

1、ObjectMapper与JSONObject比较 1、ObjectMapper属于jackson库的一部分,JSONObject属于alibaba的fastjson&#xff0c;两者各有优劣&#xff0c;可根据自己的系统环境选择使用哪种技术。 2、目前来看&#xff0c;Jackson社区相对活跃&#xff0c;Spring MVC和Spring Boot都…

IDEA项目下不显示target目录或者target目录不完整没有新添加的资源,idea隐藏target目录

文章目录 一、前言二、idea隐藏target目录2.1、idea隐藏target目录2.2、git提交时隐藏target目录 三、idea下显示target目录3.1、解决idea下不显示target目录问题3.2、target显示目录不完整 一、前言 在idea-2020.1.4版本下讲解idea怎么显示或隐藏target目录。 需要知道:如果…

聊一聊 tcp/ip 在.NET故障分析的重要性

一&#xff1a;背景 1. 讲故事 这段时间分析了几个和网络故障有关的.NET程序之后&#xff0c;真的越来越体会到计算机基础课的重要&#xff0c;比如 计算机网络 课&#xff0c;如果没有对 tcpip协议 的深刻理解&#xff0c;解决这些问题真的很难&#xff0c;因为你只能在高层…

线性代数之 伪逆矩阵

目录 一、伪逆矩阵 ◼ A的伪逆矩阵与SVD ◼ 用Python代码计算A的伪逆矩阵 ◼ 笔算A的伪逆矩阵 一、伪逆矩阵 ◼ A的伪逆矩阵与SVD 逆矩阵并不总是存在&#xff0c;即使是方阵。然而&#xff0c;对于非正方形矩阵&#xff0c;存在一个伪逆矩阵&#xff0c;也叫摩尔-彭罗斯…

OPCUA 行业配套标准:机器人

OPC UA 定义了对象&#xff0c;对象类型&#xff0c;结构化组织能力和定义对象之间关系的能力&#xff0c;利用这些基础和衍生类型及对象&#xff0c;用户还可以搭建出更复杂的类型&#xff0c;关系和对象。 如果不同的厂商或者用户定义的信息模型不同&#xff0c;将会影响系统…

qml添加滚动条

import QtQuick.Controls 2.15ScrollBar.vertical: ScrollBar {visible: flick1.contentHeight > flick1.heightanchors.right: parent.rightanchors.rightMargin: 40width: 10active: truecontentItem: Rectangle {radius: 6opacity: 0.5color: "#7882A0"} }

Linux 安装 Nginx 并配置为系统服务(超详细)

目录 前言安装 Nginx安装依赖项下载Nginx解压Nginx编译和安装防火墙设置启动Nginx 配置 Nginx 为系统服务配置 Nginx 服务文件启动 Nginx 服务设置开机自启动检查 Nginx 状态停止 Nginx 服务重启 Nginx 服务 卸载 Nginx结语 前言 Nginx是一款卓越的高性能Web服务器&#xff0c…

MySQL(11):数据处理之增删改

插入数据 方式1&#xff1a; 一条一条的添加数据 为表的所有字段按默认顺序插入数据 INSERT INTO 表名 VALUES (value1,value2,....);# 没有指明添加的字段 INSERT INTO emp1 VALUES (1,TOM,2023-11-06,3400);没有指明添加的字段&#xff0c;要按照声明顺序&#xff0c;进行…

Voice Control for ChatGPT简单高效的与ChatGPT进行交流学习。

快捷又不失灵活性 日常生活中&#xff0c;我们与亲人朋友沟通交流一般都是喜欢语音的形式来完成的&#xff0c;毕竟相对于文字来说语音就不会显的那么的苍白无力&#xff0c;同时最大的好处就是能解放我们的双手吧&#xff0c;能更快实现两者间的对话&#xff0c;沟通便更高效…

排序算法的分析及实现

目录​​​​​​​ 1. 排序 1.1. 排序的概念 1.2. 排序的稳定性 1.3. 内部排序和外部排序 2. 直接插入排序 2.1. 直接插入排序 2.2. 直接插入排序的两种情况 1. 情况一 2. 情况二 2.3. 直接插入排序的单趟排序 2.4. 直接插入排序的完整实现 2.5. 直接插入排序的时…

如何手动获取spring/springboot中的IOC容器(全局上下文对象)?

IDE&#xff1a;IntelliJ IDEA 2022.2.3 x64 操作系统&#xff1a;win10 x64 位 家庭版 JDK: 1.8 文章目录 前言一、如何手动获取spring容器[ApplicationContext]&#xff1f;方式①&#xff1a;在启动类中获取spring容器方式②&#xff1a;自定义工具类实现ServletContextList…

Typecho V1.2.1 博客更换域名还原

网站老是到期或则要换服务器&#xff08;IP地址&#xff09;&#xff0c;单独改IP老是有图片不能加载&#xff0c;出个完整的迁移教程&#xff1a; 系统环境&#xff1a;Ubuntu 2204 宝塔面板 8.0.3 Nginx1.22 PHP 8.1 MySQL 5.7 备份 进入宝塔将网站根目录直接压缩&#xff0…

pytorch复现_UNet

什么是UNet U-Net由收缩路径和扩张路径组成。收缩路径是一系列卷积层和汇集层&#xff0c;其中要素地图的分辨率逐渐降低。扩展路径是一系列上采样层和卷积层&#xff0c;其中特征地图的分辨率逐渐增加。 在扩展路径中的每一步&#xff0c;来自收缩路径的对应特征地图与当前特征…

MySQL -- 索引

MySQL – 索引 文章目录 MySQL -- 索引一、索引简介1.简介2.索引效率的案例 二、认识磁盘1.磁盘2.结论3.磁盘随机访问(Random Access)与连续访问(Sequential Access) 三、MySQL 与磁盘交互基本单位1.基本单位2.MySQL中的数据管理 五、索引的理解1.索引案例2.单页mysql page3.管…

ts学习01-开发环境搭建

环境 nodejs 18 npm 安装typescript npm install typescript # 如果上面太慢&#xff0c;可以执行下面的方法 npm install typescript --registryhttps://registry.npm.taobao.orgHelloWorld 新建index.ts console.log("hello ts");执行下面命令进行编译 npx t…

【ArcGIS Pro二次开发】(74):Python、C#实现Excel截图导出图片

以村庄规划制图为例&#xff0c;通过对现状和规划用地的统计&#xff0c;生成Excel格式的【空间功能结构调整表】后&#xff0c;需要进一步将表格导出成图片&#xff0c;并嵌入到图集中&#xff0c;这样可以实现全流程不用手动参与&#xff0c;让制图的流程完全自动化。 关于E…