- 外文名
- cache
- 类 别
- 高速缓存、磁盘缓存
- 原 理
- 程序局部性原理
- 中文名
- 缓存
- 学 科
- 计算机
- 目 的
- 提高数据存取速度
-
缓存
2020-02-26 11:39:45服务器缓存 优先去缓存中查找数据 数据不存在,再去数据库中查找 django 内置缓存系统 (参考博客) 提供缓存api 少的代码实现缓存 多种缓存 扩展性 setting中配置 set/get/delete 支持过期 常见问题 缓存雪崩 ...- 服务器优化,减少磁盘IO
- 服务器缓存
- 优先去缓存中查找数据
- 数据不存在,再去数据库中查找
- django 内置缓存系统 (参考博客)
- 提供缓存api
- 少的代码实现缓存
- 多种缓存
- 扩展性
- setting中配置
- set/get/delete
- 支持过期
- 常见问题
- 缓存雪崩 -> 缓存时间错开、多台设备缓存
- 穿透 -> 缓存过期,同时来了多个用户访问此数据(导致此条数据被同时查询多遍)
- 添加标记,已经有人在查询,其他人等待
- 缓存时间 结合具体的业务场景
- 新闻
- 电影
-
缓存穿透、缓存击穿、缓存雪崩区别和解决方案
2018-09-19 14:35:57一、缓存处理流程 前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。 二、缓存穿透 描述: 缓存...一、缓存处理流程
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。
二、缓存穿透
描述:
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
- 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
- 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
三、缓存击穿
描述:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:
- 设置热点数据永远不过期。
- 加互斥锁,互斥锁参考代码如下:
说明:
1)缓存中有数据,直接走上述代码13行后就返回结果了
2)缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待100ms,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。
3)当然这是简化处理,理论上如果能根据key值加锁就更好了,就是线程A从数据库取key1的数据并不妨碍线程B取key2的数据,上面代码明显做不到这点。
四、缓存雪崩
描述:
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
- 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
- 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
- 设置热点数据永远不过期。
-
浅谈 MyBatis 三级缓存
2020-03-15 21:38:101、一级缓存 MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的。即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存到缓冲中,...1、一级缓存
MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的。即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存到缓冲中,以后直接先从缓存中取出数据,不会直接去查数据库。但是不同的SqlSession对象,因为不用的SqlSession都是相互隔离的,所以相同的Mapper、参数和方法,它还是会再次发送到SQL到数据库去执行,返回结果。
2、二级缓存
为了解决这个问题,需要手动开启二级缓存,在SqlSessionFactory层面给各个SqlSession 对象共享。默认二级缓存是不开启的,需要手动进行配置。
在mybatis-config.xml文件中添加<setting name="cacheEnabled" value="true"/>
在xxxMapper.xml文件中添加
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" ></cache>
各个属性意义如下:
eviction:缓存的回收策略。
LRU - 最近最少使用,移除最长时间不被使用的对象。
FIFO - 先进先出,按对象进入缓存的顺序来移除它们。
SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象。
WEAK - 弱引用,更积极地移除基于垃圾收集器和弱引用规则的对象。
默认的是LRU。
flushInterval:缓存刷新间隔。
缓存多长时间清空一次,默认不清空,设置一个毫秒值。
readOnly:是否只读。
true:只读:mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。mybatis为了加快获取数据,直接就会将数据在缓存中的引用交给用户 。不安全,速度快。
false:读写(默认):mybatis觉得获取的数据可能会被修改,mybatis会利用序列化&反序列化的技术克隆一份新的数据给你。安全,速度相对慢。
size:缓存存放多少个元素。
type:指定自定义缓存的全类名(实现Cache接口即可)。ps:要使用二级缓存,对应的POJO必须实现序列化接口 。
useCache="true"是否使用一级缓存,默认false。sqlSession.clearCache();只是清除当前session中的一级缓存。
useCache配置:如果一条句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为false,如:<select id="selectUserById" resultMap="map" useCache="false">
刷新缓存(就是清空缓存)
二级缓存默认会在insert、update、delete操作后刷新缓存,可以手动配置不更新缓存,如下:<update id="updateUserById" parameterType="User" flushCache="false" />
3、自定义缓存
自定义缓存对象,该对象必须实现 org.apache.ibatis.cache.Cache 接口。
为了方便日后的开发工作和降低学习成本,我们可以使用第三方缓存,在这里笔者推荐使用EhCache。EhCache是一个快速的、轻量级的、易于使用的、进程内的缓存。它支持read-only和read/write缓存,内存和磁盘缓存。是一个非常轻量级的缓存实现,而且从1.2之后就支持了集群,目前的最新版本是2.8。
部署
3.1. 导入所需jar:
核心包:ehcache-core-2.6.8.jar
整合包:mybatis-ehcache-1.0.3.jar
依赖jar包:slf4j-api-1.6.6.jar,slf4j-jdk14-1.6.6.jar 3.2. 导入所需配置文件:
ehcache.xml,下面是对配置文件的一些讲解<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盘保存路径 --> <diskStore path="D:\java\ehcache" /> <defaultCache maxElementsInMemory="10000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache> <!-- 属性说明: diskStore:指定数据在磁盘中的存储位置。 defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略。 以下属性是必须的: maxElementsInMemory - 在内存中缓存的element的最大数目。 maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大。 eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。 overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上。 以下属性是可选的: timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大。 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区。 diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作。 memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)。 -->
3.3. 在xxxMapper.xml文件中添加
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
如果在其他的xxxMapper.xml文件中也想要使用,只需在该文件下配置,namespace为配置过得命名空间地址。
<cache-ref namespace="dao.UserMapper"/>
mybatis默认是启用cache的,所以对于某一条不想被cache的sql需要把useCache="false"加上。例如:
<select id="selectUserById" useCache="false">
进行测试后,会在
“磁盘保存路径”
中产生了相关的文件。混〔IT〕的小学生 → 热爱编程,喜欢挑战新事物!
-
Redis缓存穿透、缓存雪崩问题分析
2018-06-01 22:16:35把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数据量很大的时候,经典的几个问题如下: (一)缓存和数据库间数据一致性问题 分布式环境下(单机就不用说了)非常容易出现...把redis作为缓存使用已经是司空见惯,当redis中的数据量起来了以后你就得考虑以下几个问题:
(一)缓存和数据库间数据一致性问题
分布式环境下(单机就不用说了)非常容易出现缓存和数据库间的数据一致性问题,针对这一点的话,只能说,如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。我们只能采取合适的策略来降低缓存和数据库间数据不一致的概率,而无法保证两者间的强一致性。合适的策略包括 合适的缓存更新策略,更新数据库后要及时更新缓存、缓存失败时增加重试机制,例如MQ模式的消息队列。
(二)缓存穿透问题
现象:用户大量并发请求的数据(key)对应的数据在redis和数据库中都不存在,导致尽管数据不存在但还是每次都会进行查DB。
为什么key对应数据在缓存和db中不存在还会每次都进行DB查询呢?因为很多开发同学写的代码写的逻辑都是先从redis缓存中查一把,如果缓存中为空则从DB中查,如果DB中查到的数据不为空则设置到缓存并返回给接口。那么问题来了,如果从DB中查询的数据为空呢??
解决方案:
- 从DB中查询出来数据为空,也进行空数据的缓存,避免DB数据为空也每次都进行数据库查询;
- 使用布隆过滤器,但是会增加一定的复杂度及存在一定的误判率;
bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小,下面先来简单的实现下看看效果,我这里用guava实现的布隆过滤器:
<dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version> </dependency> </dependencies>
public class BloomFilterTest { private static final int capacity = 1000000; private static final int key = 999998; private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), capacity); static { for (int i = 0; i < capacity; i++) { bloomFilter.put(i); } } public static void main(String[] args) { /*返回计算机最精确的时间,单位微妙*/ long start = System.nanoTime(); if (bloomFilter.mightContain(key)) { System.out.println("成功过滤到" + key); } long end = System.nanoTime(); System.out.println("布隆过滤器消耗时间:" + (end - start)); int sum = 0; for (int i = capacity + 20000; i < capacity + 30000; i++) { if (bloomFilter.mightContain(i)) { sum = sum + 1; } } System.out.println("错判率为:" + sum); } }
成功过滤到999998 布隆过滤器消耗时间:215518 错判率为:318
可以看到,100w个数据中只消耗了约0.2毫秒就匹配到了key,速度足够快。然后模拟了1w个不存在于布隆过滤器中的key,匹配错误率为318/10000,也就是说,出错率大概为3%,跟踪下BloomFilter的源码发现默认的容错率就是0.03:
public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions /* n */) { return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions }
我们可调用BloomFilter的这个方法显式的指定误判率:
private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), capacity,0.01);
我们断点跟踪下,误判率为0.02和默认的0.03时候的区别:
对比两个出错率可以发现,误判率为0.02时数组大小为8142363,0.03时为7298440,误判率降低了0.01,BloomFilter维护的数组大小也减少了843923,可见BloomFilter默认的误判率0.03是设计者权衡系统性能后得出的值。要注意的是,布隆过滤器不支持删除操作。用在这边解决缓存穿透问题就是:
public String getByKey(String key) { // 通过key获取value String value = redisService.get(key); if (StringUtil.isEmpty(value)) { if (bloomFilter.mightContain(key)) { value = userService.getById(key); redisService.set(key, value); return value; } else { return null; } } return value; }
(三)缓存雪崩问题
现象:大量key同一时间点失效,同时又有大量请求打进来,导致流量直接打在DB上,造成DB不可用。
解决方案:
- 设置key永不失效(热点数据);
- 设置key缓存失效时候尽可能错开;
- 使用多级缓存机制,比如同时使用redsi和memcache缓存,请求->redis->memcache->db;
- 购买第三方可靠性高的Redis云服务器;
引申阅读: 使用quartz实现高级定制化定时任务(包含管理界面)
推荐阅读:elastic search搜索引擎实战demo:https://github.com/simonsfan/springboot-quartz-demo,分支:feature_es
-
清除微信内置浏览器缓存
2018-08-22 21:19:44在做微信开发的时候(主要是微信内网页或者比较大型的手机网站)的时候,更改了页面代码,但是微信内置浏览器有缓存,还是之前的效果,影响调试,而且还死活清除不掉!!!!!怎么办? 我的第一想法是关闭手机的... -
springboot整合redis做缓存
2018-09-13 13:39:33之前的项目中,用到过redis,主要是使用redis做缓存,redis在web开发中使用的场景很多,其中缓存是其中一个很重要的使用场景,之所以用作缓存,得益于redis的读写数据,尤其是在读取数据的时候是直接走内存的,这样... -
缓存穿透,缓存击穿,缓存雪崩解决方案分析
2017-01-06 11:12:50设计一个缓存系统,不得不要考虑的问题就是:缓存穿透、缓存击穿与失效时的雪崩效应。 缓存穿透 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则... -
缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题
2018-03-12 20:09:10》,今天给大家整理一篇关于Redis经常被问到的问题:缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等概念的入门及简单解决方案。 一、缓存雪崩 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未... -
VUE 缓存 设置缓存 使用缓存
2019-08-06 18:58:38VUE.JS 使用缓存我建议用good-storage ,简单方便好用,下面来看看怎么使用它 good-storage 是一个插件,需要安装 localStorage 临时缓存(主动清除缓存才会销毁) sessionStorage 长期缓存(关闭浏览器自动销毁... -
mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache
2015-07-26 16:52:111查询缓存 1.1什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。 mybaits提供一级缓存,和二级缓存。 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中... -
Redis11_缓存穿透和雪崩
2020-09-09 16:01:10Redis11_缓存穿透和雪崩 缓存穿透 用户查询某个数据时,会先在redis缓存中查询,如果缓存没有命中,会去持久层数据库MySQL中查询,如果此时依然没有命中,将返回null,不会写入缓存。 当同时有大量的查询请求在... -
-
Redis缓存穿透、缓存击穿、缓存雪崩的原理和解决办法
2020-09-17 18:59:53希望:在大数据时代,由于网络请求的并发,导致的数据库I/O开销巨大,所以为了缓解数据库的压力,缓存技术必不可少,而这其中redis基本是服务器的缓存服务之一,虽然缓存技术很好用,但是也会出现各种各样的问题,... -
Caffeine 缓存
2017-12-13 17:07:05缓存和 Map 之间的一个根本区别在于缓存可以回收存储的 item。 回收策略为在指定时间删除哪些对象。此策略直接影响缓存的命中率 — 缓存库的一个重要特征。 Caffeine 因使用 Window TinyLfu 回收策略,提供了一个... -
缓存穿透,缓存击穿,缓存雪崩
2019-02-28 13:33:45文章目录缓存穿透,缓存击穿,缓存雪崩1、什么是缓存穿透2、如何解决缓存穿透方案一方案二3、什么是缓存击穿4、缓存击穿与缓存雪崩的区别5、如何解决缓存击穿方案一方案二方案三方案四6、什么是缓存雪崩7、如何避免... -
缓存穿透、缓存雪崩、缓存击穿及其解决方案
2020-09-02 11:24:15缓存在系统中的位置 因为大型系统,其数据库资源比较紧俏,并且数据库的访问速度并发量远不如目前的各种内存缓存系统。所以缓存的主要意义是减少数据库压力,增加访问速度。其位置是建立在数据库层和业务逻辑层之间... -
Redis: 缓存过期、缓存雪崩、缓存穿透、缓存击穿(热点)、缓存并发(热点)、多级缓存、布隆过滤器
2019-08-18 16:34:241.缓存过期 缓存过期:在使用缓存时,可以通过TTL(Time To Live)设置失效时间,当TTL为0时,缓存失效。 为什么要设置缓存的过期时间呢? 一、为了节省内存 例如,在缓存中存放了近3年的10亿条博文数据,但是经常被... -
你不知道的redis二-缓存穿透和缓存雪崩问题及解决方案
2020-08-12 09:29:39一、缓存使用方式 1、客户端请求业务系统 2、业务系统首先判断redis是否存在数据 3、如果数据存在redis则返回给业务系统 4、业务系统返回给客户端 5、如果redis不存在数据,则业务服务区数据库中查询数据 ... -
mysql手册11_查询缓存优化和内存管理优化、并发参数调整
2020-08-19 15:51:42mysql手册11_查询缓存优化 当开启查询缓存,执行了相同sql查询操作时,服务器会直接从查询缓存中读取结果,当数据被修改后,缓存失效 修改频繁的表不适合设置查询缓存。 查询缓存参数的配置: 注:Mysql8.0已经不再... -
22-Mybatis缓存相关设置对一级缓存和二级缓存的影响
2020-11-14 07:06:26缓存相关的设置 1. <setting name="cacheEnabled" value="false"/> 关闭二级缓存,一级缓存可正常使用 2. <select useCache="false"> 关闭二级缓存,一级缓存可正常使用 3. <select flushCache=... -
Nginx缓存
2019-09-22 21:52:44缓存文件放在哪儿? 如何指定哪些请求被缓存? 缓存的有效期是多久? 如何指定哪些请求不被缓存? 1 缓存文件放在哪儿? 配置 $ vim $NGINX_HOME/conf/nginx.conf worker_processes auto; events { use epoll; ... -
缓存过期与一致性,缓存雪崩,缓存穿透
2019-08-15 09:53:06缓存使用带来的一致性问题 ---- 数据同步,有四类方式 (1)要求高的场景下,使用实时更新策略----- 即数据有变化时,更新的线程直接同步缓存数据 (2)如果允许,可以单独架设第三方方案,来同步缓存数据,常见的... -
MyBatis缓存
2019-09-25 10:57:35MyBatis提供查询缓存,用于减轻数据库压力,提高性能。MyBatis提供了一级缓存和二级缓存。 一级缓存是SqlSession级别的缓存,每个SqlSession对象都有一个哈希表用于缓存数据,不同SqlSession对象之间缓存不共享。同... -
快速了解缓存穿透与缓存雪崩
2019-07-26 08:00:00缓存穿透 缓存系统,一般流程都是按照key去查询缓存,如果不存在对应的value,就去后端系统(例如:持久层数据库)查找。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的... -
spring boot 缓存@EnableCaching
2017-08-02 22:51:29很多时候系统的瓶颈都在一些比较复杂的IO操作,例如读取数据库,如果一些比较稳定的数据,一般的解决方案就是用缓存。spring boot提供了比较简单的缓存方案。只要使用 @EnableCaching即可完成简单的缓存功能。缓存的... -
http缓存策略之强缓存与协商缓存
2020-04-11 16:45:25因此通过浏览器的缓存机制,协同服务器让浏览器缓存那些不需要频繁变动的资源就可以有效地降低流量消耗和响应时间。 一、什么是http缓存 http缓存指的是:当客户端向服务器请求资源时,会先查... -
mybatis缓存
2021-01-24 16:43:42将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。 2、为什么使用缓存? 减少和数据库的交互...
-
Rockchip平台以太网配置手册.rar
-
02 预定义类(LocalDate,).md
-
类的实例化顺序专题
-
五子棋终结者.rar
-
深入浅出matplotlib(87):误差条的数量控制
-
MySQL 主从复制 Replication 详解(Linux 和 W
-
nestjs-events-sample-源码
-
双向冒泡排序算法-Java实现
-
冥想第四天
-
【硬核】一线Python程序员实战经验分享(1)
-
2021 年该学的 CSS 框架 Tailwind CSS 实战视频
-
axios拦截器
-
朱老师C++课程第3部分-3.6智能指针与STL查漏补缺
-
MySQL 事务和锁
-
轻巧建模之需求篇(三)
-
【爱码农】C#制作MDI文本编辑器
-
2021-02-27
-
ImageMagic.7z
-
零基础极简以太坊智能合约开发环境搭建并开发部署
-
MySQL NDB Cluster 负载均衡和高可用集群