java 缓存
外存:
也就是我们经常说的(CDEF盘的大小)外储存器是指除计算机内存及CPU缓存以外的储存器,此类储存器一般断电后仍然能保存数据。常见的外存储器有硬盘、软盘、光盘、U盘等,一般的软件都是安装在外存中
内存:
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行,此类储存器一般断电后数据就会被清空
高速缓存:
高速缓存是用来协调CPU与主存之间存取速度的差异而设置的。一般情况下,CPU的工作速度高,但内存的工作速度相对较低,为了解决这个问题,通常使用高速缓存,高速缓存的存取速度介于CPU和主存之间。系统将一些CPU在近几个时间段经常访问的内容存入高速缓冲,当CPU需要使用数据时,先在高速缓存中找,如果找到,就不必访问内存了,找不到时,再找内存,这样就在一定程度上缓解了由于主存速度低造成的CPU“停工待料”的情况
---------------------------------------------------------------------------------------------------------------------------
之前一直很不理解这个缓存那个缓存,其实缓存就是把一些外存上的数据保存到内存上而已,怎么保存到内存上呢,我们运行的所有程序,里面的变量值都是放在内存上的,所以说如果要想使一个值放到内存上,实质就是在获得这个变量之后,用一个生存期较长的变量存放你想存放的值,在java中一些缓存一般都是通过map集合来做的。
在Java中经常用到缓存,在SSh框架中也会用到一级缓存和二级缓存,到底缓存是怎么实现的呢?
简单讲就是,如果某些资源或者数据会被频繁的使用,而这些资源或数据存储在系统外部,比如数据库、硬盘文件等,那么每次操作这些数据的时候都从数据库或者硬盘上去获取,速度会很慢,会造成性能问题。
一个简单的解决方法就是:把这些数据缓存到内存里面,每次操作的时候,先到内存里面找,看有没有这些数据,如果有,那么就直接使用,如果没有那么就获取它,并设置到缓存中,下一次访问的时候就可以直接从内存中获取了。从而节省大量的时间,当然,缓存是一种典型的空间换时间的方案。
在Java中最常见的一种实现缓存的方式就是使用Map, 基本的步骤是:
先到缓存里面查找,看看是否存在需要使用的数据
如果没有找到,那么就创建一个满足要求的数据,然后把这个数据设置回到缓存中,以备下次使用
如果找到了相应的数据,或者是创建了相应的数据,那就直接使用这个数据。
https://blog.csdn.net/zhengzhaoyang122/article/details/82184029 转载:
1、什么是缓存?
☞ 缓存就是数据交换的缓冲区(称作:Cache),当某一硬件要读取数据时,会首先从缓存汇总查询数据,有则直接执行,不存在时从内存中获取。由于缓存的数据比内存快的多,所以缓存的作用就是帮助硬件更快的运行。
☞ 缓存往往使用的是RAM(断电既掉的非永久存储),所以在用完后还是会把文件送到硬盘等存储器中永久存储。电脑中最大缓存就是内存条,硬盘上也有16M或者32M的缓存。
☞ 高速缓存是用来协调CPU与主存之间存取速度的差异而设置的。一般CPU工作速度高,但内存的工作速度相对较低,为了解决这个问题,通常使用高速缓存,高速缓存的存取速度介于CPU与主存之间。系统将一些CPU在最近几个时间段经常访问的内容存在高速缓存,这样就在一定程度上缓解了由于主存速度低造成的CPU“停工待料”的情况。
☞ 缓存就是把一些外存上的数据保存在内存上而已,为什么保存在内存上,我们运行的所有程序里面的变量都是存放在内存中的,所以如果想将值放入内存上,可以通过变量的方式存储。在JAVA中一些缓存一般都是通过Map集合来实现的。
▁▂▃▅▆ :缓存在不同的场景下,作用是不一样的具体举例说明:
✔ 操作系统磁盘缓存 ——> 减少磁盘机械操作。
✔ 数据库缓存——>减少文件系统IO。
✔ 应用程序缓存——>减少对数据库的查询。
✔ Web服务器缓存——>减少应用服务器请求。
✔ 客户端浏览器缓存——>减少对网站的访问。
2、常见的缓存策略有哪些,如何做到缓存(比如redis)与DB里的数据一致性,你们项目中用到了什么缓存系统,如何设计的。
1)、由于不同系统的数据访问模式不同,同一种缓存策略很难在不同的数据访问模式下取得满意的性能,研究人员提出不同缓存策略以适应不同的需求。
缓存策略的分类:
1)、基于访问的时间:此类算法按各缓存项被访问时间来组织缓存队列,决定替换对象。如LRU
2)、基于访问频率:此类算法用缓存项的被访问频率来组织缓存。如LFU、LRU2、2Q、LIRS。
3)、访问时间与频率兼顾:通过兼顾访问时间和频率。使得数据模式在变化时缓存策略仍有较好性能。如FBR、LRUF、ALRFU。多数此类算法具有一个可调或自适应参数,通过该参数的调节使缓存策略在基于访问时间与频率间取得一个平衡。
4)、基于访问模式:某些应用有较明确的数据访问特点,进而产生与其相适应的缓存策略。如专用的VoD系统设计的A&L缓存策略,同时适应随机、顺序两种访问模式的SARC策略。
2)、数据不一致性产生的原因:
【1】、先操作缓存,再写数据库成功之前,如果有读请求发生,可能导致旧数据入缓存,引发数据不一致。在分布式环境下,数据的读写都是并发的,一个服务多机器部署,对同一个数据进行读写,在数据库层面并不能保证完成顺序,就有可能后读的操作先完成(读取到的是脏数据),如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。
【解决办法】:1)、可采用更新前后双删除缓存策略。
2)、可以通过“串行化”解决,保证同一个数据的读写落在同一个后端服务上。
【2】、先操作数据库,再清除缓存。如果删缓存失败了,就会出现数据不一致问题。
【解决办法】:1)、将删除失败的key值存入队列中重复删除,如下图:
(1)更新数据库数据。
(2)缓存因为种种问题删除失败。
(3)将需要删除的key发送至消息队列。
(4)自己消费消息,获得需要删除的key。
(5)继续重试删除操作,直到成功。
缺点:对业务线代码造成大量的侵入。于是有了方案二。
2)、方案二:通过订阅binlog获取需要重新删除的Key值数据。在应用程序中,另起一段程序,获得这个订阅程序传来的消息,进行删除缓存操作。
(1)更新数据库数据
(2)数据库会将操作信息写入binlog日志当中
(3)订阅程序提取出所需要的数据以及key
(4)另起一段非业务代码,获得该信息
(5)尝试删除缓存操作,发现删除失败
(6)将这些信息发送至消息队列
(7)重新从消息队列中获得该数据,重试操作。
3、如何防止缓存穿透、缓存击穿、缓存雪崩和缓存刷新。
【1】、缓存穿透:缓存穿透是说收到一个请求,但是该请求缓存中不存在,只能去数据库中查询,然后放进缓存。但当有好多请求同时访问同一个数据时,业务系统把这些请求全发到了数据库;或者恶意构造一个逻辑上不存在的数据,然后大量发送这个请求,这样每次都会被发送到数据库,最总导致数据库挂掉。
解决的办法:对于恶意访问,一种思路是先做校验,对恶意数据直接过滤掉,不要发送至数据库层;第二种思路是缓存空结果,就是对查询不存在的数据也记录在缓存中,这样就可以有效的减少查询数据库的次数。非恶意访问,结合缓存击穿说明。
【2】、缓存击穿:上面提到的某个数据没有,然后好多请求查询数据库,可以归为缓存击穿的范畴:对于热点数据,当缓存失效的一瞬间,所有的请求都被下放到数据库去请求更新缓存,数据库被压垮。
解决的办法:防范此类问题,一种思路是加全局锁,就是所有访问某个数据的请求都共享一个锁,获得锁的那个才有资格去访问数据库,其他线程必须等待。但现在大部分系统都是分布式的,本地锁无法控制其他服务器也等待,所以要用到全局锁,比如Redis的setnx实现全局锁。另一种思想是对即将过期的数据进行主动刷新,比如新起一个线程轮询数据,或者比如把所有的数据划分为不同的缓存区间,定期分区间刷新数据。第二个思路与缓存雪崩有点关系。
【3】、缓存雪崩:缓存雪崩是指当我们给所有的缓存设置了同样的过期时间,当某一时刻,整个缓存的数据全部过期了,然后瞬间所有的请求都被抛向了数据库,数据库就崩掉了。
解决的办法:解决思路要么是分治,划分更小的缓存区间,按区间过期;要么给每个key的过期时间加一个随机值,避免同时过期,达到错峰刷新缓存的目的。
【4】、缓存刷新:既清空缓存 ,一般在insert、update、delete操作后就需要刷新缓存,如果不执行就会出现脏数据。但当缓存请求的系统蹦掉后,返回给缓存的值为null。
————————————————
版权声明:本文为CSDN博主「程序猿进阶」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhengzhaoyang122/article/details/82184029
总结缓存的测试点:
1.缓存的读写与数据库是否一致;
2.缓存的降级逻辑;
3.缓存加入新的Key值后,会不会顺序不一致;
4.缓存的key是否过滤了恶意数据;
5.value为空的时候,缓存值是否也更新了;
6.缓存的过期时间设置,检查是否是同一个值,避免雪崩;