当前位置: 首页 > news >正文

缓存-基础理论和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()方法展示信息。

相关文章:

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

缓存-基础理论和Guava Cache介绍 缓存基础理论 缓存的容量和扩容 缓存初始容量、最大容量&#xff0c;扩容阈值以及相应的扩容实现。 缓存分类 本地缓存&#xff1a;运行于本进程中的缓存&#xff0c; 如Java的 concurrentHashMap, Ehcache&#xff0c;Guava Cache。 分布式缓…...

机器人伺服驱动控制环

伺服驱动器​的控制环&#xff0c;包括&#xff1a;位置环、速度环、电流环这三种类型。 对于伺服的控制回路&#xff0c;内侧控制环的响应带宽一般会是外侧控制环的5到10倍。也就是说&#xff0c;电流环带宽大致是速度环的5到10倍&#xff0c;速度环带宽则约为位置环的5到10倍…...

单链表(3)

现在有一个指针p&#xff0c;指向数据2所在的结点的地址——那么如何访问这个数据2 前面说过指针访问数据成员使用的是 指向符->。则访问这个数据2就是——p->data.因为p一开始就指向数据2的结点地址了 那么如何访问数据3,4往后等等 访问3就是——p->next->data…...

Android14前台服务适配指南

Android14前台服务适配指南 Android 10引入了android:foregroundServiceType属性&#xff0c;用于帮助开发者更有目的地定义前台服务。这个属性在Android 14中被强制要求&#xff0c;必须指定适当的前台服务类型。以下是可选择的前台服务类型&#xff1a; camera: 相机应用。…...

Spring Boot中使用Spring Data JPA访问MySQL

Spring Data JPA是Spring框架提供的用于简化JPA&#xff08;Java Persistence API&#xff09;开发的数据访问层框架。它通过提供一组便捷的API和工具&#xff0c;简化了对JPA数据访问的操作&#xff0c;同时也提供了一些额外的功能&#xff0c;比如动态查询、分页、排序等。 …...

Go 语言函数闭包(匿名函数)

Go 语言函数闭包&#xff08;匿名函数&#xff09; 在Go语言中&#xff0c;闭包是一种特殊的匿名函数&#xff0c;它可以捕获并访问其周围的变量。闭包允许将函数与其引用的环境捆绑在一起&#xff0c;使得函数可以在其创建的范围之外继续使用这些变量。以下是关于Go语言闭包的…...

2023年11月编程语言流行度排名

点击查看最新编程语言流行度排名&#xff08;每月更新&#xff09; 2023年11月编程语言流行度排名 编程语言流行度排名是通过分析在谷歌上搜索语言教程的频率而创建的 一门语言教程被搜索的次数越多&#xff0c;大家就会认为该语言越受欢迎。这是一个领先指标。原始数据来自…...

apache-maven-3.6.3 安装配置教程

链接&#xff1a;https://pan.baidu.com/s/1RkMXipnvac9EKcZyUStfGQ?pwdl32m 提取码&#xff1a;l32m 1. 将 maven 压缩包解压至指定文件夹 2. 配置环境变量 &#xff08;1&#xff09;打开此电脑-> 鼠标右键选择属性->点击高级系统设置 &#xff08;2&#xff09;点…...

你一般什么时候使用GPT

一般在寻求帮助的时候才使用gpt 一个优秀的gpt项目gpt-on-web...

kubernetes (k8s)的使用

一、kubernetes 简介 谷歌2014年开源的管理工具项目&#xff0c;简化微服务的开发和部署。 提供功能&#xff1a;自愈和自动伸缩、调度和发布、调用链监控、配置管理、Metrics监控、日志监控、弹性和容错、API管理、服务安全等。官网&#xff1a;https://kubernetes.io/zh-cn…...

RK3568平台开发系列讲解(音视频篇)RTMP 推流

🚀返回专栏总目录 文章目录 一、RTMP 的工作原理二、RTMP 流媒体服务框架2.1、Nginx 流媒体服务器2.2、FFmpeg 推流沉淀、分享、成长,让自己和他人都能有所收获!😄 📢目前常见的视频监控和视频直播都是使用了 RTMP、RTSP、HLS、MPEG-DASH、 WebRTC流媒体传输协议等。 R…...

掌握这几个技巧,才敢称为Jenkins大神!

01、Performance插件兼容性问题 自由风格项目中&#xff0c;有使用 Performance 插件收集构建产物&#xff0c;但是截至到目前最新版本&#xff08;Jenkins v2.298&#xff0c;Performance&#xff1a;v3.19&#xff09;&#xff0c;此插件和Jenkins都存在有兼容性问题&#xf…...

帷幄内容管理系统:从立人设、做内容到定向投流,品牌 KOS 体系打造「百万导购」

随着公域流量越来越贵&#xff0c;获客成本越来越高&#xff0c;品牌们已经越来越不满足于高曝光&#xff0c;而是更多地关注起销售转化率。继 KOL、KOC&#xff08;关键意见消费者&#xff09; 之后&#xff0c;KOS&#xff08;关键意见销售&#xff09;营销模式走入品牌的视野…...

5.vue3项目(五):实现顶部导航栏功能:导航栏静态搭建,菜单折叠功能实现,面包屑动态展示路径,刷新页面功能,全屏功能

目录 一、左侧菜单栏刷新,不要合并菜单 二、顶部tabbar静态搭建 1.新建文件 2.编辑页面 3.结果测试...

unittest 统计测试执行case总数,成功数量,失败数量,输出至文件,生成一个简易的html报告带饼图

这是一个Python的单元测试框架的示例代码&#xff0c;主要用于执行测试用例并生成测试报告。其中&#xff0c;通过unittest模块创建主测试类MainTestCase&#xff0c;并加载其他文件中的测试用例&#xff0c;统计用例的执行结果并将结果写入文件&#xff0c;最后生成一个简单的…...

推荐一款功能强大的在线文件预览工具-kkFileView

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…...

【Linux】磁盘阵列,了解不同raid的特点

一、raid和阵列卡介绍 1、什么是磁盘阵列&#xff1a; 磁盘阵列是利用虚拟化存储技术把很多块独立的磁盘组合成一个容量巨大的磁盘组&#xff0c;利用个别磁盘提供数据所产生加成效果提升整个磁盘系统效能。利用这项技术&#xff0c;将数据切割成许多区段&#xff0c;分别存放…...

Go 语言初探:从基础到实战

1.Go概述 程序是一段计算机指令的有序组合。程序算法数据结构。任何程序都可以将模块通过三种基本的控制结构&#xff08;顺序、分支、循环&#xff09;进行组合来实现。 Go&#xff08;也称为Golang&#xff09;是一种由Google开发的开源编程语言。设计目标是使编程更简单、…...

Kotlin文件和类为什么不是一对一关系

在Java中&#xff0c;一个类文件的public类名必须和文件名一致&#xff0c;如何不一致就会报异常&#xff0c;但是在kotlin的文件可以和类名一致&#xff0c;也可以不一致。这种特性&#xff0c;就跟c有点像&#xff0c;毕竟c的.h 和 .cpp文件是分开的。只要最终编译的时候对的…...

Kubernetes实战(四)-部署docker harbor私有仓库

1 Docker原生私有仓库Registry 1.1 原生私有仓库Registry概述 Docker的仓库主要分两类&#xff1a; 私有仓库公有仓库 共有仓库只要在官方注册用户&#xff0c;登录即可使用。但对于仓库的使用&#xff0c;企业还是会有自己的专属镜像&#xff0c;所以私有库的搭建也是很有…...

IDEA JAVA项目 导入JAR包,打JAR包 和 JAVA运行JAR命令提示没有主清单属性

一、导入JAR包 1、java项目在没有导入该jar包之前&#xff0c;如图&#xff1a;2、点击 File -> Project Structure&#xff08;快捷键 Ctrl Alt Shift s&#xff09;&#xff0c;点击Project Structure界面左侧的“Modules”如图&#xff1a;3.在 “Dependencies” 标签…...

c#输入和输出

第一个c#程序 /* c#在编译时首先编译为通用中间语言&#xff08;IL代码&#xff09;&#xff0c;并且将其存在程序集中 c#的程序集包括扩展名为.exe的可执行文件和扩展名为.dll的可供其他程序调用的库文件c#在执行时首先将程序集加载到CLR中&#xff0c;然后通过即时编译器编译…...

设置区块链节点输出等级为警告级,并把日志存储阈值位100MB并验证;

题目 获取指定区块链节点输出等级为警告级&#xff0c;并设置日志存储阈值位100MB并验证&#xff1b; 操作步骤 1.切换目录 cd nodes/127.0.0.1/node0 2.打开配置文件并修改 vim config.ini warn&#xff1a;警告...

perl列表创建、追加、删除

简介 perl 列表追加元素 主要是通过push和unshift函数来实现。其中&#xff0c;push是追加到列表尾&#xff0c;unshift是追加到列表头。 perl列表删除元素 主要是通过pop和shift函数来实现。其中&#xff0c;pop是从列表尾删除一个元素&#xff0c; shift是从列表头删除一…...

leetcode刷题日记:94. Binary Tree Inorder Traversal(二叉树的中序遍历)

给出二叉树的根结点&#xff0c;返回二叉树的中序遍历序列。 二叉树的中序遍历序列是先遍历左子树再遍历根结点然后再遍历右子树&#xff0c;在遍历左子树是这个结点是左子树的根结点&#xff0c;左子树有左子树和根结点右子树&#xff0c;也就是说在遍历的时候我们要递归遍历。…...

【漏洞复现】Aapache_Tomcat_AJP协议_文件包含漏洞(CVE-2020-1938)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 说明内容漏洞编号CVE-2020-1938漏洞名称Aapache_Tomcat_AJP文件包含漏洞漏洞评级高…...

RabbitMQ消息可靠性投递

RabbitMQ消息投递的路径为&#xff1a; 生产者 —> 交换机 —> 队列 —> 消费者 在RabbitMQ工作的过程中&#xff0c;每个环节消息都可能传递失败&#xff0c;那么RabbitMQ是如何监听消息是否成功投递的呢&#xff1f; 确认模式&#xff08;confirm&#xff09;可以监…...

汽车网络安全渗透测试概述

目录 1.汽车网络安全法规概述 1.1 国外标准 1.2 国内标准 2.汽车网络安全威胁分析 2.1 汽车网络安全资产定义 2.2 汽车网络安全影响场景及评级示例 3.汽车网络安全渗透测试描述 3.1 参考法规 3.2 渗透测试内容 4.小结 1.汽车网络安全法规概述 近年来&#xff0c;汽车…...

NOIP2023模拟14联测35 charlotte

题目大意 给你一棵有 n n n个节点的树&#xff0c;并用 01 01 01串告诉你哪些节点上有棋子&#xff08;恰好一棵&#xff09;。 你可以进行若干次操作&#xff0c;每次操作可以将两颗距离至少为 2 2 2的棋子向彼此移动一步。 问能否通过若干次操作使得所有的棋子都在一个点上…...

绿色科技和可持续发展技术

一、绿色科技和可持续发展技术的定义 绿色科技和可持续发展技术是指那些利用可再生资源、减少环境污染和促进可持续发展的技术。这些技术不仅可以提高人们的生活质量&#xff0c;同时也可以减少对自然环境的破坏&#xff0c;并且能够为未来的可持续发展提供保障。 二、绿色科…...