APP中缓存、加载与刷新机制设计【转载】
1、为什么要加缓存?
场景一:【等待】,在向服务器请求新的数据时。我们让用户看到什么?第一种是漂亮的等待加载页面;第二种是缓存的内容。对于第二种,用户可以对页面进行操作,等待新数据时可以查看旧数据,更具有“可操作性”与“可用性”,从而减轻了从服务器获取数据这一动作的大小和时间长短,增强了用户体验。另一方面,如果内容更新的间隔较长或者用户刷新的间隔较短,在没有缓存的情况下,很多数据我们会多次重复的向服务器获取,增加了成本。
场景二:【结果】没有联网,或者在地铁上网络太差无法加载数据时,如果留给用户一个空白页面,实在是感觉有点不负责任啊。并且很多功能在没有联网的情况下也有使用的可能性,比如:APP中的通讯录,查看一些聊天记录,通知信息,文章列表等。因为用户打开APP不一定是要看新信息,说不定是回顾老信息(或许老信息里也有用户之前没看的),所以恰当的缓存可以满足更多的用户场景。
场景三:【金钱】有一天,一个用户发现自己装了某个APP后流量用的特别快,Ta可能永远将这个APP打入冷宫了,而增加缓存正是节省流量的一个方法。虽然节省的不多或者用户也察觉不到,但是作为一个有态度的产品经理,应该多做一些思考。
2、什么是缓存?
缓存可分为如下几类:
(1)app缓存。
(2)固定缓存。
(3)可手动清理的缓存。
(4)不可手动清理的缓存。
(5)临时缓存。
其中,临时缓存常用于一个功能页面内,保存各栏目的缓存。同一个功能里会把子功能分为多个栏目进行划分,每个标签栏目下的内容在本次使用中都可保存为临时缓存,在该功能里切换栏目,不需要重新加载数据,使用缓存显示。
对于用户来说,使用时达到了无缝切换浏览,对于服务器来说,在短时间内数据很少会有更新,所以在一般情况下能满足用户的正常需求,并达到体验优秀。
临时缓存的清理机制是:退出该功能模块就清除之前的缓存。也就是说下次进入该功能模块,需要重新获取一次数据。
很多时候我们都会用到临时缓存,因为那些信息真的不是那么重要,而且不需要经常反复查看,那对于那些我们经常使用而且经常需要反复查看的信息,马海祥建议采取固定缓存,保存在本地,方便下次翻阅时不需要再一次向服务器请求数据了。
对于固定缓存又会细分为可手动清理的缓存和不可手动清理的缓存。
第一种是我们最常见的缓存,几乎所有产品都采用这种缓存方式。平时用户浏览文章、图集加载的数据就以这种形式缓存在本地,下次看回这篇文章、图集时就不需要加载了。用户也可以手动把这些缓存清理了,释放空间。
而对于某些特殊场景,例如一些相对固定的数据,我们不愿意一开始就打包进App里,这样会占太大容量,造成产品包很大,也不愿意每次进入页面都向服务器加载这些信息,那怎么办?建议的解决方法就是我们可以只加载一次就永远存在本地了,这样安装包也不会大,以后也不用加载了。
3、如何清理缓存?
一般App都会在“设置”里提供一个清理缓存的功能,一键把空间释放。除此之外,App最好要设计自动清理机制,可以通过两个维度来设计这个机制。
(1)、时间
通过设定一个固定的时间,或者根据用户使用周期灵活设定时间来清理缓存。每个产品的场景不一,用户使用频率不一,设定这个机制的时候就需要结合实际情况考虑了。
(2)、容量
一般是设定一个容量上限,采用堆栈的设计原理进行缓存清理,溢出堆栈的旧数据将自动清除。
1、页面加载
方案1:单页面整体加载
这种加载比较简单,一般运用在页面内容比较单一的情况下,所以直接一次性加载完所有数据后再显示内容。其单页面加载失败的状态相对来说也比较好处理。
方案2:单页面分块加载
这种方案的特点是,能让用户逐步看到内容,在这个渐进的过程中降低用户的焦虑心理。
其中又可以分为,模块间有关联性的,先加载父内容,再加载子内容。如优酷,先把栏目加载出来,再加载各栏目的内容。
模块间没有绝对关联性的,可独自加载各自模块内容,根据请求的速度不同分别显示。这样处理有一定几率让用户在没完全刷出数据的情况下就能找到自己需要的功能,如大众点评、淘宝客户端等。
框架固定,内容更新的,可先把框架显示出来,再把各模块的数据各自加载显示,如各种iOS自带应用。
这种分模块加载的需要特别注意加载失败的状态,毕竟每个模块都提示加载失败,点击重试是很挫的一件事,可以根据信息的优先级来决定哪些数据失败了采用默认状态,哪些数据采用失败提示。
方案3:跨页面加载
父页面&子页面 or 同一app内,页面间字段可以复用的,在加载子页面时不需要重新加载新数据。
方案4:预加载
这种加载方式的特点是,在加载一个页面内容的同时,预测用户的下一步行为,并为他下一步需要使用的页面加载内容,使得他在下一步的操作中能立刻获取信息而不需要加载等待。
预加载提供给用户无缝的产品使用体验,使得用户在使用产品的过程中更直接流畅,没有被打断的感觉。
具体的例子有:
在浏览图集的时候,当看到第一张的图片时,就自动后台加载第二第三第四张图片,用户浏览完第一张图片切换到第二张时就不会有加载等待的过程。
在浏览新闻列表时,就把每篇新闻的内容在后台进行预加载,用户选择看某篇新闻时,能立刻阅读到内容。
但是这种方案也需要面临很多的问题,马海祥觉得最直接的就是流量问题,因为会自动跑掉很多用户可能根本用不上的数据流量,所以,一般情况下马海祥建议可以设定在wifi环境才采用这种加载模式。又或者设定加载规则,只把主要内容预加载,而部分次要内容可以在用户真的用到的时候才加载,例如预加载新闻正文的情况,可以只加载文本信息,图片信息等到用户进入内页才加载。这种预加载与分块加载结合的方式也普遍运用在各个场景。
另外,预加载也需要时间的,他只是不在客户端显示给用户,默默在后台运作而已,需要特殊考虑未加载完用户就使用到那些信息的情况,所以在做预加载设计时需要同时考虑另一种适合该情况的普通加载方式。
预加载需要根据具体的场景来进行设计,设定好信息优先级,综合考虑各种类型信息的具体大小流量,整体考虑预加载的方式,这些都是需要经过精心分析思考的。
随着网络环境的发展,预加载将成为以后产品普遍的加载方式,他提供给用户的无缝使用体验**地提升了产品的可用性。
2、操作加载
除了页面的信息需要加载,页面内的操作也是需要通过给服务器发送请求记录的。
方案1:加载层
进行一个操作后,弹出模态的提示层,告知用户正在加载。采用模态的提示主要是防止用户在该过程中进行其他操作,导致当前加载出错。由于采用模态的提示,并且有可能因为网络原因导致长时间处于加载状态,建议提供一个“关闭”的操作,中止本次加载,恢复App可用状态。加载失败时可在当前浮层变换为失败提示。模态提示层是最稳妥的方式,但他会使用户在使用过程中有打断的感觉。
方案2:控件自身加载状态
这种方式是把操作加载的状态与控件的样式结合起来了,对某个控件进行操作后,控件变换为加载状态,此时控件不能重复操作。由于这种加载方式是控件的自身状态,不影响其他操作,所以用户也可以对页面进行其他操作,可能会导致同时有多个请求的情况,增加了加载失败的风险,这也算是这种方式的弊端,不过这种极端情况很少出现。请求失败后,可配合Toast提示告知用户失败的原因。
方案3:后台加载
用户在操作后,客户端立刻反馈操作成功,然后把请求放到后台与服务器交互,这一过程用户不需要了解,不需要等待,在正常情况**验是非常棒的。
但是在极端情况下会出现一些莫名其妙的状况,由于是后台记录请求并与服务器交互,所以实际请求是否成功客户端是不说明的,全部以操作成功来显示,这就会导致用户误以为操作成功了,但实际上下次来看发现没有成功。
所以,这种加载方式是需要根据具体使用场景来权衡使用的,对于一些重要的操作,建议还是使用模态的方式加载,对于一些小操作,如点赞、订阅、关注,可采用后台加载的方式。
3、下一页加载还是当前也加载
用户进入首页,正式迈出体验的第一步,接下来迎接的就是基于用户目标的界面间跳转。完成界面的跳转,会有各种加载策略,但无论形式如何,我们都可以将其归为两大类:“下一页加载”、“当前页加载”。
(1)“下一页加载”满足了用户提前窥视的需求
我们把页面看成“点”,页面流是连接这些点的“线”,我们以“用户想买一条牛仔裤”这一场景作为案例做了简单的眼动研究,从应用启动到商品浏览再到商品确定最后进入下单页,用户所呈现的瞳孔梯次增大,即E>D>C>B>A,为了解释这一现象,通过与被试交流,我们发现相比于各种浏览,用户更期待看到他们想看到的东西。因此此时的”下一页加载“正好,满足了用户提前窥视的需求。
(2) Wait!I Need Think Think
我们以同样的方式又对“使用支付宝对手机充值”这一场景做了研究,从开始支付到二次确认支付,用户所呈现的瞳孔都比较大,即A与B近似相等,通过访谈,我们发现与“递增体验流”不同的是,当用户遇到判断逻辑的界面时,用户并非急于想看下一页面到底包含怎样的内容,而是非0即1的验证心态,即我的操作效成功了吗?因此在判断逻辑界面中,用户的内容窥视需求并不强,当然也没什么内容,要么仅是一个小小的Toast,再大一点就是一个简单的信息反馈界面(意味着“下一页加载”在这里就是个鸡肋),用户反而对非0即1的验证需求较为强烈,其中还伴随着等待结果过程中的紧张感、激动感,因此界面通过 当前页加载 表明系统正在努力地处理用户交代的指令**了用户的紧张感、激动感,直到结果显现——“处理成功”,完成了非0即1验证的满足感。
4、先加载还是先展示
当需加载的是功能时,可以先展示再加载,当需加载的是内容时,则反过来。
淘宝
打开APP的第一个页面是功能,所以先展示再加载的:
随便点击一个模块(不要点菜单),下面要展示的将要是内容(商品),所以是先加载再展示的,没有加载完都不展示:
京东
同样的,功能模块先展示后加载:
内容先加载,没加载完不展示:
两种方式各有利弊:
先展示,后加载:
优点:给用户0等待的错觉
缺点:当前数据有可能是错的,而且得等用户操作到最后一步才会发现
先加载,后展示:
优点:保证数据的质量和准确
缺点:网络不好时,造成等待
显然,功能模块对于一个产品来说是既有固定的,在短时间内几乎不会更新,所以这种数据出现错误或与当前状态不同的几率小得多,因此,可以使用先展示后加载的方式。
另一方面,内容(特别是商品数据)是最容易产生变动的,为了保证每一个消费者看到的数据都是最真实,最准确的,所以务必要先加载再展示。
1、空白页面刷新失败有提示
现在的应用都标榜以内容为中心,所以都会极力避免空白页面的出现。对于大部分的应用,最好的方法就是使用缓存,进入页面之后,先显示之前的缓存,然后再进行内容的刷新。其次,消灭空白页面的第二种方法就是提供系统推荐项进行替代。但是对于一些页面,页面内容跟用户的使用状态关系密切,无法避免会出现空白页面,这时候会使用一些引导类的提示,使得页面变得更加丰富,同时可以促进用户产生内容。
但是一些资讯类应用,比如读读日报,打开默认是空白页面,然后再加载内容(我不是很明白这种设定)。其他一些应用,比如:豆瓣一刻和MONO,每天第一次进入应用的时候也会出现空白页面。我猜想第二类应用的展示方式的原因是这样的。他们的内容**都是严格以天为单位的,每天固定时段**精选内容。他们会希望你每天只看并且看完当天的东西,所以一旦到了第二天,昨天的内容就是累赘了。所以每天第一次进入应用的时候会出现空白页面,象征着每天都是从新开始。此时就会对应一个“空白刷新”逻辑。
空白刷新对应的场景是这样子的:用户想要刷新出内容,并且用户知道这里可以刷出新内容,但是没有刷新成功,这时候需要给用户一个交待。所以需要提示用户。同时,提示完用户之后需要给用户一个解决方法,这就是“点击后重试”。
2、缓存页面刷新失败无提示
常见的应用比如知乎、网易新闻、好奇心日报、微信朋友圈等,这些应用都会采用缓存的形式,打开之后显示的是缓存内容,然后系统会给服务器发送请求,如果有内容更新的话就会自动更新一次内容,更新之后的内容直接覆盖当前的内容。更新失败之后是没有提示的。但是有一些应用,比如有道词典、企鹅FM、网易云音乐等,他们更新失败之后是有提示的。
我觉得这两种应用的区分点在于
应用的使用频率;
内容的时间连续性;
界面之间的关系紧密度。
比如说网易新闻,作为一个打发时间的工具,每天使用频率就会比较高,所以用户进来之后是想看看有没有更新。其次,网易新闻的内容是连续不断更新的,所以用户会知道当前显示的内容是我看看过并且处理过的。最后,新闻列表页面显示的是摘要,用户可以通过摘要快速进行判断是否要进入详情页,摘要有助于帮助用户回忆上一次的使用场景。
所以这就对应着一个这样的场景:用户只是想看看有没有更新,所以他们已经做好了“没有新内容”的心理预期,所以即使是更新不了内容,用户也不会想太多。反倒是,如果进行了错误提示,用户可能会有一种挫败感。因为他知道现在有内容,只是因为网络的原因而没有更新,他要进行的任务受到了外界因素的阻碍,由此产生一种细微的挫败感。
3、缓存页面刷新失败有提示
另一类应用,使用频率没那么高,或者内容不具备时间连续性的,又或者说当前界面无法唤起用户上一次的使用场景。那么就有必要进行率先你失败提示了。
比如说企鹅FM,音频类的应用注定使用不会那么频繁,因为通过视觉接收的信息会比通过听觉接收的信息更快更多,同时音频类对环境的要求较高(比如用耳机时要求环境不那么嘈杂,外放时要求在私人场所)。其次,此类应用都是实时推荐的,不存在时间连续性的问题,用户无法通过时间来判断内容是否被阅读过。再者,标题也无法帮你快速做出判断,你还是要进去听过才知道内容是什么。最后如果不提醒,用户进入到详情页再收到提醒,就会觉得应用浪费了用户的时间。所以,对于此类内容,刷新失败是有必要进行提醒的。
一、全页面静态化缓存也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程。
此种方式,在CMS系统中比较常见,比如dedecms;一种比较常用的实现方式是用输出缓存:Ob_start()******要运行的代码*******$content=Ob_get_contents()****将缓存内容写入html文件*****Ob_end_clean()二、数据缓存顾名思义,就是缓存数据的一种方式;比如,商城中的某个商品信息,当用商品id去请求时,就会得出包括店铺信息、商品信息等数据,此时就可以将这些数据缓存到一个php文件中,文件名包含商品id来建一个唯一标示;下一次有人想查看这个商品时,首先就直接调这个文件里面的信息,而不用再去数据库查询;其实缓存文件中缓存的就是一个php数组之类;Ecmall商城系统里面就用了这种方式;三、查询缓存其实这跟数据缓存是一个思路,就是根据查询语句来缓存;将查询得到的数据缓存在一个文件中,下次遇到相同的查询时,就直接先从这个文件里面调数据,不会再去查数据库;但此处的缓存文件名可能就需要以查询语句为基点来建立唯一标示;按时间变更进行缓存就是对于缓存文件您需要设一个有效时间,在这个有效时间内,相同的访问才会先取缓存文件的内容,但是超过设定的缓存时间,就需要重新从数据库中获取数据,并生产最新的缓存文件;比如,我将我们商城的首页就是设置2个小时更新一次。
四、页面部分缓存该种方式,是将一个页面中不经常变的部分进行静态缓存,而经常变化的块不缓存,最后组装在一起显示;可以使用类似于ob_get_contents的方式实现,也可以利用类似ESI之类的页面片段缓存策略,使其用来做动态页面中相对静态的片段部分的缓存。
该种方式可以用于如商城中的商品页;五、Opcode缓存首先php代码被解析为Tokens,然后再编译为Opcode码,最后执行Opcode码,返回结果;所以,对于相同的php文件,第一次运行时可以缓存其Opcode码,下次再执行这个页面时,直接会去找到缓存下的opcode码,直接执行最后一步,而不再需要中间的步骤了。
比较知名的是XCache、TurckMMCache、PHPAccelerator等。
六、按内容变更进行缓存这个也并非独立的缓存技术,需结合着用;就是当数据库内容被修改时,即刻更新缓存文件;比如,一个人流量很大的商城,商品很多,商品表必然比较大,这表的压力也比较重;我们就可以对商品显示页进行页面缓存;当商家在后台修改这个商品的信息时,点击保存,我们同时就更新缓存文件;那么,买家访问这个商品信息时,实际问的是一个静态页面,而不需要再去访问数据库;试想,如果对商品页不缓存,那么每次访问一个商品就要去数据库查一次,如果有10万人在线浏览商品,那服务器压力就大了;七、内存式缓存提到这个,可能大家想到的首先就是Memcached;memcached是高性能的分布式内存缓存服务器。
一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。
它就是将需要缓存的信息,缓存到系统内存中,需要获取信息时,直接到内存中取;比较常用的方式就是key_>value方式;connect($memcachehost,$memcacheport)ordie("Couldnotconnect")$memcache->set('key','缓存的内容')$get=$memcache->get($key)//获取信息?>八、apache缓存模块apache安装完以后,是不允许被cache的。
厦门IT培训http://www.kmbdqn.cn/认为如果外接了cache或squid服务器要求进行web加速的话,就需要在htttpd.conf里进行设置,当然前提是在安装apache的时候要激活mod_cache的模块。
本文内容大多参考 《图解HTTP》一书
所以讲缓存为什么要先扯代理服务器?别急,让我们看一下一个请求的简单示意图。
我们看到客户端(用户)发送了一个请求并不是直接发给源服务器的而是经过了代理服务器,然后经由代理服务器再发送给源服务器,响应也同样遵循这个顺序。
那么代理服务器在这中间担任了什么角色?
缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。
缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因此客户端可就近从缓存服务器上获取资源,而源服务器也不必多次处理相同的请求了。
即便缓存服务器和客户端内有缓存,也不能每次都给我返回缓存吧,如果是这样,源服务器更新了我也不知道,因为我每次都是看缓存的资源。
为了解决这个问题,针对缓存设计了时效性的概念:
即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效,缓存服务器将会再次从源服务器上获取“新”资源。
缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以Internet Explorer 程序为例,把客户端缓存称为临时网络文件(Temporary Internet File)。
浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。
另外,和缓存服务器相同的一点是,当判定缓存过期后,会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。
Pragma 是HTTP/1.1 之前版本的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义。
规范定义的形式唯一,如下所示。
Pragma: no-cache
该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源。
通过指定首部字段Cache-Control 的指令,就能操作缓存的工作机制。
可用的指令按请求和响应分类如下所示:
public指令
Cache-Control: public
当指定使用public 指令时,则明确表明其他用户也可利用缓存。
private指令
no-store指令
Cache-Control: no-store
当使用no-store 指令时,暗示请求(和对应的响应)或响应中包含机密信息。
因此,该指令规定缓存不能在本地存储请求或响应的任一部分。
ps:从字面意思上很容易把no-cache误解成为不缓存,但事实上no-cache代表不缓存过期的资源,缓存会向源服务器进行有效期确认后处理资源,也许称为do-not-serve-from-cache-without-revalidation更合适。no-store 才是真正地不进行缓存,请读者注意区别理解。
s-maxage指令
Cache-Control: s-maxage=604800 //(单位:秒)
s-maxage 指令的功能和max-age 指令的功能相同, 它们的不同点是s-maxage 指令只适用于供多位用户使用的公共缓存服务器(这里指代理服务器)。也就是说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。
另外,当使用s-maxage 指令后,则直接忽略对Expires 首部字段及max-age 指令的处理。
max-age指令
cache-extension token
Cache-Control: private, community="UCI"
通过 cache-extension 标记(token),可以扩展Cache-Control 首部字段内的指令。
如上例,Cache-Control 首部字段本身没有community 这个指令。借助extension tokens 实现了该指令的添加。如果缓存服务器不能理community 这个新指令,就会直接忽略。因此,extension tokens 仅对能理解它的缓存服务器来说是有意义的。
If-Unmodified-Since: Thu, 03 Jul 2012 00:00:00 GMT
首部字段If-Unmodified-Since 和首部字段If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码412 Precondition Failed 作为响应返回。
ps:Last-Modified 存在一定问题,如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。
首部字段If-None-Match 属于附带条件之一。它和首部字段If-Match 作用相反。用于指定If-None-Match 字段值的实体标记(ETag)值与请求资源的ETag 不一致时,它就告知服务器处理该请求。
在GET 或HEAD 方法中使用首部字段If-None-Match 可获取最新的资源。因此,这与使用首部字段If-Modified-Since 时有些类似。
不与服务器确认,而是直接使用浏览器缓存的内容。其中响应内容和之前的响应内容一模一样,例如其中的Date时间是上一次响应的时间。
F5的作用和直接在URI输入栏中输入然后回车是不一样的,F5会让浏览器无论如何都发一个HTTP Request给Server,即使先前的响应中有Expires头部。
Ctrl+F5要的是彻底的从Server拿一份新的资源过来,所以不光要发送HTTP request给Server,而且这个请求里面连If-Modified-Since/If-None-Match都没有,这样就逼着Server不能返回304,而是把整个资源原原本本地返回一份,这样,Ctrl+F5引发的传输时间变长了,自然网页Refresh的也慢一些。
Cache-Control 是 HTTP1.1 才有的,不适用于 HTTP1.0,而 Expires 既适用于 HTTP1.0,也适用于 HTTP1.1,所以说在大多数情况下同时发送这两个头会是一个更好的选择,当客户端两种头都能解析的时候,会优先使用 Cache-Control。
二者都是通过某个标识值来请求资源, 如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed)状态码,内容为空,这样就节省了传输数据量。当资源变化后则返回新资源。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
其中Last-Modified使用文件最后修改作为文件标识值,它无法处理文件一秒内多次修改的情况,而且只要文件修改了哪怕文件实质内容没有修改,也会重新返回资源内容;ETag作为“被请求变量的实体值”,其完全可以解决Last-Modified头部的问题,但是其计算过程需要耗费服务器资源。
Expires和Cache-Control都有一个问题就是服务端的修改,如果还在缓存时效里,那么客户端是不会去请求服务端资源的(非刷新),这就存在一个资源版本不符的问题,而强制刷新一定会发起HTTP请求并返回资源内容,无论该内容在这段时间内是否修改过;而Last-Modified和Etag每次请求资源都会发起请求,哪怕是很久都不会有修改的资源,都至少有一次请求响应的消耗。
对于所有可缓存资源,指定一个Expires或Cache-Control max-age以及一个Last-Modified或ETag至关重要。同时使用前者和后者可以很好的相互适应。
前者不需要每次都发起一次请求来校验资源时效性,后者保证当资源未出现修改的时候不需要重新发送该资源。而在用户的不同刷新页面行为中,二者的结合也能很好的利用HTTP缓存控制特性,无论是在地址栏输入URI然后输入回车进行访问,还是点击刷新按钮,浏览器都能充分利用缓存内容,避免进行不必要的请求与数据传输。
做法很简单,就是把可能会更新的资源以版本形式发布,常用的方法是在文件名或参数带上一串md5或时间标记符:
可以看到上面的例子中有不同的做法,有的在URI后面加上了md5参数,有的将md5值作为文件名的一部分,有的将资源放在特性版本的目录中。
那么在文件没有变动的时候,浏览器不用发起请求直接可以使用缓存文件;而在文件有变化的时候,由于文件版本号的变更,导致文件名变化,请求的url变了,自然文件就更新了。这样能确保客户端能及时从服务器收取到新修改的文件。通过这样的处理,增长了静态资源,特别是图片资源的缓存时间,避免该资源很快过期,客户端频繁向服务端发起资源请求,服务器再返回304响应的情况(有Last-Modified/Etag)。
高速缓存分为一级缓存(即L1 Cache)和二级缓存(即L2Cache)。CPU在运行时首先从一级缓存读取数据,然后从二级缓存读取数据,然后从内存和虚拟内存读取数据,因此高速缓存的容量和速度直接影响到CPU的工作性能。一级缓存都内置在CPU内部并与CPU同速运行,可以有效的提高CPU的运行效率。一级缓存越大,CPU的运行效率越高,但受到CPU内部结构的限制,一级缓存的容量都很小。二级缓存对CPU运行效率的影响也很大,现在的二级缓存一般都集成在中,但有分为芯片内部和外部两种,集成在芯片内部的二级缓存与CPU同频率二级缓存(即全速二级缓存),而集成在芯片外部的二级缓存的运行频率 是CPU的运行频率的一半(即半速二级缓存),因此运行效率较低。但是一级缓存和二级缓存的大,它究竟有多少好处呢?你得告诉我们经销商,实际上你得用最普通的话跟他讲。所以我们给他们打个比方,说这个就好比你开汽车的时候,后备箱是整个的一级缓存,假如说扶手里面有一个小箱子,那是你的二级缓存。二级缓存大好在哪里呢?就是你随时开车的时候,随时在里面都可以取东西了。假如你二级缓存小的话,你还得把车停下来,到后备箱里取东西。
首先我们来简单了解一下一级缓存。目前所有主流处理器大都具有一级缓存和二级缓存,少数高端处理器还集成了三级缓存。其中,一级缓存可分为一级指令缓存和一级数据缓存。一级指令缓存用于暂时存储并向CPU递送各类运算指令;一级数据缓存用于暂时存储并向CPU递送运算所需数据,这就是一级缓存的作用(如果大家对上述文字理解困难的话,可参照下图所示)。
那么,二级缓存的作用又是什么呢?简单地说,二级缓存就是一级缓存的缓冲器:一级缓存制造成本很高因此它的容量有限,二级缓存的作用就是存储那些CPU处理时需要用到、一级缓存又无法存储的数据。同样道理,三级缓存和内存可以看作是二级缓存的缓冲器,它们的容量递增,但单位制造成本却递减。需要注意的是,无论是二级缓存、三级缓存还是内存都不能存储处理器操作的原始指令,这些指令只能存储在CPU的一级指令缓存中,而余下的二级缓存、三级缓存和内存仅用于存储CPU所需数据。
根据工作原理的不同,目前主流处理器所采用的一级数据缓存又可以分为实数据读写缓存和数据代码指令追踪缓存2种,它们分别被AMD和Intel所采用。不同的一级数据缓存设计对于二级缓存容量的需求也各不相同,下面让我们简单了解一下这两种一级数据缓存设计的不同之处。
一、AMD一级数据缓存设计
AMD采用的一级缓存设计属于传统的“实数据读写缓存”设计。基于该架构的一级数据缓存主要用于存储CPU最先读取的数据;而更多的读取数据则分别存储在二级缓存和系统内存当中。做个简单的假设,假如处理器需要读取“AMD ATHLON 64 3000+ IS GOOD”这一串数据(不记空格),那么首先要被读取的“AMDATHL”将被存储在一级数据缓存中,而余下的“ON643000+ISGOOD”则被分别存储在二级缓存和系统内存当中(如下图所示)。
需要注意的是,以上假设只是对AMD处理器一级数据缓存的一个抽象描述,一级数据缓存和二级缓存所能存储的数据长度完全由缓存容量的大小决定,而绝非以上假设中的几个字节。“实数据读写缓存”的优点是数据读取直接快速,但这也需要一级数据缓存具有一定的容量,增加了处理器的制造难度(一级数据缓存的单位制造成本较二级缓存高)。
二、Intel一级数据缓存设计
自P4时代开始,Intel开始采用全新的“数据代码指令追踪缓存”设计。基于这种架构的一级数据缓存不再存储实际的数据,而是存储这些数据在二级缓存中的指令代码(即数据在二级缓存中存储的起始地址)。假设处理器需要读取“INTEL P4 IS GOOD”这一串数据(不记空格),那么所有数据将被存储在二级缓存中,而一级数据代码指令追踪缓存需要存储的仅仅是上述数据的起始地址(如下图所示)。
由于一级数据缓存不再存储实际数据,因此“数据代码指令追踪缓存”设计能够极大地降CPU对一级数据缓存容量的要求,降低处理器的生产难度。但这种设计的弊端在于数据读取效率较“实数据读写缓存设计”低,而且对二级缓存容量的依赖性非常大。
在了解了一级缓存、二级缓存的大致作用及其分类以后,下面我们来回答以下硬件一菜鸟网友提出的问题。
从理论上讲,二级缓存越大处理器的性能越好,但这并不是说二级缓存容量加倍就能够处理器带来成倍的性能增长。目前CPU处理的绝大部分数据的大小都在0-256KB之间,小部分数据的大小在256KB-512KB之间,只有极少数数据的大小超过512KB。所以只要处理器可用的一级、二级缓存容量达到256KB以上,那就能够应付正常的应用;512KB容量的二级缓存已经足够满足绝大多数应用的需求。
这其中,对于采用“实数据读写缓存”设计的AMD Athlon 64、Sempron处理器而言,由于它们已经具备了64KB一级指令缓存和64KB一级数据缓存,只要处理器的二级缓存容量大于等于128KB就能够存储足够的数据和指令,因此它们对二级缓存的依赖性并不大。这就是为什么主频同为1.8GHz的Socket 754 Sempron 3000+(128KB二级缓存)、Sempron 3100+(256KB二级缓存)以及Athlon 64 2800+(512KB二级缓存)在大多数评测中性能非常接近的主要原因。所以对于普通用户而言754 Sempron 2600+是值得考虑的。
反观Intel目前主推的P4、赛扬系列处理器,它们都采用了“数据代码指令追踪缓存”架构,其中Prescott内核的一级缓存中只包含了12KB一级指令缓存和16KB一级数据缓存,而Northwood内核更是只有12KB一级指令缓存和8KB一级数据缓存。所以P4、赛扬系列处理器对二级缓存的依赖性是非常大的,赛扬D 320(256KB二级缓存)与赛扬 2.4GHz(128KB二级缓存)性能上的巨大差距就很好地证明了这一点;而赛扬D和P4 E处理器之间的性能差距同样十分明显。
最后,如果您是狂热的游戏发烧友或者从事多媒体制作的专业用户,那么具有1MB二级缓存的P4处理器和具有512KB/1MB二级缓存的Athlon 64处理器才是您理想的选择。因为在高负荷的运算下,CPU的一级缓存和二级缓存近乎“爆满”,在这个时候大容量的二级缓存能够为处理器带来5%-10% 左右的性能提升,这对于那些要求苛刻的用户来说是完全有必要的。
二级缓存
二级缓存又叫L2 CACHE,它是处理器内部的一些缓冲存储器,其作用跟内存一样。 它是怎么出现的呢?要上溯到上个世纪80年代,由于处理器的运行速度越来越快,慢慢地,处理器需要从内存中读取数据的速度需求就越来越高了。然而内存的速度提升速度却很缓慢,而能高速读写数据的内存价格又非常高昂,不能大量采用。从性能价格比的角度出发,英特尔等处理器设计生产公司想到一个办法,就是用少量的高速内存和大量的低速内存结合使用,共同为处理器提供数据。这样就兼顾了性能和使用成本的最优。而那些高速的内存因为是处于CPU和内存之间的位置,又是临时存放数据的地方,所以就叫做缓冲存储器了,简称“缓存”。它的作用就像仓库中临时堆放货物的地方一样,货物从运输车辆上放下时临时堆放在缓存区中,然后再搬到内部存储区中长时间存放。货物在这段区域中存放的时间很短,就是一个临时货场。最初缓存只有一级,后来处理器速度又提升了,一级缓存不够用了,于是就添加了二级缓存。二级缓存是比一级缓存速度更慢,容量更大的内存,主要就是做一级缓存和内存之间数据临时交换的地方用。现在,为了适应速度更快的处理器P4EE,已经出现了三级缓存了,它的容量更大,速度相对二级缓存也要慢一些,但是比内存可快多了。缓存的出现使得CPU处理器的运行效率得到了大幅度的提升,这个区域中存放的都是CPU频繁要使用的数据,所以缓存越大处理器效率就越高,同时由于缓存的物理结构比内存复杂很多,所以其成本也很高。
大量使用二级缓存带来的结果是处理器运行效率的提升和成本价格的大幅度不等比提升。举个例子,服务器上用的至强处理器和普通的P4处理器其内核基本上是一样的,就是二级缓存不同。至强的二级缓存是2MB~16MB,P4的二级缓存是512KB,于是最便宜的至强也比最贵的P4贵,原因就在二级缓存不同。
即L2 Cache。由于L1级高速缓存容量的限制,为了再次提高CPU的运算速度,在CPU外部放置一高速存储器,即二级缓存。工作主频比较灵活,可与CPU同频,也可不同。CPU在读取数据时,先在L1中寻找,再从L2寻找,然后是内存,在后是外存储器。所以L2对系统的影响也不容忽视。
CPU缓存(Cache Memory)位于CPU与内存之间的临时存储器,它的容量比内存小但交换速度快。在缓存中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的,当CPU调用大量数据时,就可避开内存直接从缓存中调用,从而加快读取速度。由此可见,在CPU中加入缓存是一种高效的解决方案,这样整个内存储器(缓存+内存)就变成了既有缓存的高速度,又有内存的大容量的存储系统了。缓存对CPU的性能影响很大,主要是因为CPU的数据交换顺序和CPU与缓存间的带宽引起的。
缓存的工作原理是当CPU要读取一个数据时,首先从缓存中查找,如果找到就立即读取并送给CPU处理;如果没有找到,就用相对慢的速度从内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。
正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右),也就是说CPU下一次要读取的数据90%都在缓存中,只有大约 10%需要从内存读取。这大大节省了CPU直接读取内存的时间,也使CPU读取数据时基本无需等待。总的来说,CPU读取数据的顺序是先缓存后内存。
最早先的CPU缓存是个整体的,而且容量很低,英特尔公司从Pentium时代开始把缓存进行了分类。当时集成在CPU内核中的缓存已不足以满足 CPU的需求,而制造工艺上的限制又不能大幅度提高缓存的容量。因此出现了集成在与CPU同一块电路板上或主板上的缓存,此时就把 CPU内核集成的缓存称为一级缓存,而外部的称为二级缓存。一级缓存中还分数据缓存(Data Cache,D-Cache)和指令缓存(Instruction Cache,I-Cache)。二者分别用来存放数据和执行这些数据的指令,而且两者可以同时被CPU访问,减少了争用Cache所造成的冲突,提高了处理器效能。英特尔公司在推出Pentium 4处理器时,用新增的一种一级追踪缓存替代指令缓存,容量为12KμOps,表示能存储12K条微指令。
随着CPU制造工艺的发展,二级缓存也能轻易的集成在CPU内核中,容量也在逐年提升。现在再用集成在CPU内部与否来定义一、二级缓存,已不确切。而且随着二级缓存被集成入CPU内核中,以往二级缓存与CPU大差距分频的情况也被改变,此时其以相同于主频的速度工作,可以为CPU提供更高的传输速度。
二级缓存是CPU性能表现的关键之一,在CPU核心不变化的情况下,增加二级缓存容量能使性能大幅度提高。而同一核心的CPU高低端之分往往也是在二级缓存上有差异,由此可见二级缓存对于CPU的重要性。
CPU在缓存中找到有用的数据被称为命中,当缓存中没有CPU所需的数据时(这时称为未命中),CPU才访问内存。从理论上讲,在一颗拥有二级缓存的CPU中,读取一级缓存的命中率为80%。也就是说CPU一级缓存中找到的有用数据占数据总量的80%,剩下的20%从二级缓存中读取。由于不能准确预测将要执行的数据,读取二级缓存的命中率也在80%左右(从二级缓存读到有用的数据占总数据的16%)。那么还有的数据就不得不从内存调用,但这已经是一个相当小的比例了。目前的较高端的CPU中,还会带有三级缓存,它是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5% 的数据需要从内存中调用,这进一步提高了CPU的效率。
为了保证CPU访问时有较高的命中率,缓存中的内容应该按一定的算法替换。一种较常用的算法是“最近最少使用算法”(LRU算法),它是将最近一段时间内最少被访问过的行淘汰出局。因此需要为每行设置一个计数器,LRU算法是把命中行的计数器清零,其他各行计数器加1。当需要替换时淘汰行计数器计数值最大的数据行出局。这是一种高效、科学的算法,其计数器清零过程可以把一些频繁调用后再不需要的数据淘汰出缓存,提高缓存的利用率。
CPU产品中,一级缓存的容量基本在4KB到64KB之间,二级缓存的容量则分为128KB、256KB、512KB、1MB、2MB等。一级缓存容量各产品之间相差不大,而二级缓存容量则是提高CPU性能的关键。二级缓存容量的提升是由CPU制造工艺所决定的,容量增大必然导致CPU内部晶体管数的增加,要在有限的CPU面积上集成更大的缓存,对制造工艺的要求也就越高
缓存(Cache)大小是CPU的重要指标之一,其结构与大小对CPU速度的影响非常大。简单地讲,缓存就是用来存储一些常用或即将用到的数据或指令,当需要这些数据或指令的时候直接从缓存中读取,这样比到内存甚至硬盘中读取要快得多,能够大幅度提升CPU的处理速度。
所谓处理器缓存,通常指的是二级高速缓存,或外部高速缓存。即高速缓冲存储器,是位于CPU和主存储器DRAM(Dynamic RAM)之间的规模较小的但速度很高的存储器,通常由SRAM(静态随机存储器)组成。用来存放那些被CPU频繁使用的数据,以便使CPU不必依赖于速度较慢的DRAM(动态随机存储器)。L2高速缓存一直都属于速度极快而价格也相当昂贵的一类内存,称为SRAM(静态RAM),SRAM(Static RAM)是静态存储器的英文缩写。由于SRAM采用了与制作CPU相同的半导体工艺,因此与动态存储器DRAM比较,SRAM的存取速度快,但体积较大,价格很高。
处理器缓存的基本思想是用少量的SRAM作为CPU与DRAM存储系统之间的缓冲区,即Cache系统。80486以及更高档微处理器的一个显著特点是处理器芯片内集成了SRAM作为Cache,由于这些Cache装在芯片内,因此称为片内Cache。486芯片内Cache的容量通常为8K。高档芯片如 Pentium为16KB,Power PC可达32KB。Pentium微处理器进一步改进片内Cache,采用数据和双通道Cache技术,相对而言,片内Cache的容量不大,但是非常灵活、方便,极大地提高了微处理器的性能。片内Cache也称为一级Cache。由于486,586等高档处理器的时钟频率很高,一旦出现一级Cache未命中的情况,性能将明显恶化。在这种情况下采用的办法是在处理器芯片之外再加Cache,称为二级Cache。二级Cache实际上是CPU和主存之间的真正缓冲。由于系统板上的响应时间远低于CPU的速度,如果没有二级Cache就不可能达到486,586等高档处理器的理想速度。二级Cache的容量通常应比一级Cache大一个数量级以上。在系统设置中,常要求用户确定二级Cache是否安装及尺寸大小等。二级Cache的大小一般为128KB、 256KB或512KB。在486以上档次的微机中,普遍采用256KB或512KB同步Cache。所谓同步是指Cache和CPU采用了相同的时钟周期,以相同的速度同步工作。相对于异步Cache,性能可提高30%以上。
目前,PC及其服务器系统的发展趋势之一是CPU主频越做越高,系统架构越做越先进,而主存DRAM的结构和存取时间改进较慢。因此,缓存(Cache)技术愈显重要,在PC系统中Cache越做越大。广大用户已把Cache做为评价和选购PC系统的一个重要指标。
1、OSCache
OSCache是个一个广泛采用的高性能的J2EE缓存框架,OSCache能用于任何java应用程序的普通的缓存解决方案。
OSCache有以下特点:
(1)缓存任何对象,你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。
永久缓存--缓存能随意的写入硬盘,因此答应昂贵的创建(eXPensive-to-create)数据来保持缓存,甚至能让应用重启。
(2)支持集群--集群缓存数据能被单个的进行参数配置,不需要修改代码。
缓存记录的过期--你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(假如默认性能不需要时)。
2、Java Caching System
JSC(Java Caching System)是一个用分布式的缓存系统,是基于服务器的java应用程序。它是通过提供治理各种动态缓存数据来加速动态web应用。
JCS和其他缓存系统一样,也是一个用于高速读取,低速写入的应用程序。
动态内容和报表系统能够获得更好的性能。
假如一个网站,有重复的网站结构,使用间歇性更新方式的数据库(而不是连续不断的更新数据库),被重复搜索出相同结果的,就能够通过执行缓存方式改进其性能和伸缩性。
3、EHCache
EHCache 是一个纯java的在进程中的缓存,它具有以下特性:快速,简单,为Hibernate2.1充当可插入的缓存,最小的依靠性,全面的文档和测试。
4、JCache
JCache是个开源程序,正在努力成为JSR-107开源规范,JSR-107规范已经很多年没改变了。这个版本仍然是构建在最初的功能定义上。
5、ShiftOne
ShiftOne Java Object Cache是一个执行一系列严格的对象缓存策略的Java lib,就像一个轻量级的配置缓存工作状态的框架。
6、SwarmCache
SwarmCache是一个简单且有效的分布式缓存,它使用ip multicast与同一个局域网的其他主机进
行通讯,是非凡为集群和数据驱动web应用程序而设计的。
SwarmCache能够让典型的读操作大大超过写操作的这类应用提供更好的性能支持。
SwarmCache使用JavaGroups来治理从属关系和分布式缓存的通讯。
扩展资料
Java中缓存存在的原因:
一 般情况下,一个网站,或者一个应用,它的一般形式是,浏览器请求应用服务器,应用服务器做一堆计算后再请求数据库,数据库收到请求后再作一堆计算后把数据 返回给应用服务器。
应用服务器再作一堆计算后把数据返回给浏览器,这个是一个标准流程。但是随着互连网的普及,上网的人越来越多,网上的信息量也越来越多。
数据库每秒中接受请求的次数也是有限的,如果利用有限的资源来提供尽可能大的吞吐量呢。一个办法:减少计算量,缩短请求流程(减少网络io或者硬盘io),这时候缓存就可以大展手脚了。
缓存的基本原理就是打破上图中所描绘的标准流程,在这个标准流程中,任何 一个环节都可以被切断.请求可以从缓存里取到数据直接返回。
大家好,一直以来我都本着 用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 「基础知识」 的铺垫
「大佬可以绕过 ~」
本节给大家讲讲 「Java的SpringBoot框架」 , 之前我们学习的都是java的基础知识和底层提供的一些能力,我们日常工作都是在写接口。在我们在产品开发中,一般我们都会选择比较稳定的框架来帮我们加速开发,不会自己去造轮子,而在java众多框架中,spring框架表现的非常好,大部分公司都会首选它作为开发框架,而至今,大部分企业都是以 springboot 来构建项目了,一个稳健的系统需要引入稳定的技术~
如果你是一路看过来的,很高兴你能够耐心看完。前几期都是带大家学习了 SpringBoot 的基础使用以及集成 mybatis 开发,这也是我们写业务的基础,如果你还不熟悉这些,请先看完它们。接下来的几期内容将会带大家进阶使用,会先讲解基础 中间件 的使用和一些场景的应用,或许这些技术你听说过,没看过也没关系,我会带大家一步一步的入门,耐心看完你一定会有 收获 ,本期将会给大家讲解最热门的缓存中间件技术 Redis ,同样的,我们集成到 Springboot 中。最近github可能会被墙,所以我把源码放到了国内gitee上,本节我们依然使用上期的代码
Redis 是由意大利人Salvatore Sanfilippo(网名:antirez)开发的一款内存高速缓存数据库。全称叫 Remote Dictionary Server(远程数据服务) 是由 C语言 编写的,Redis是一个 key-value 存储系统,它支持丰富的数据类型,如: string、list、set、zset(sorted set)、hash 。
它本质上是一种键值对数据库,我们之前学习的 mysql 它是持久层的关系型数据库,而 redis 它的存储主要存在 内存 中。我们都知道在 内存 中的数据读取是非常快的,就好比你把一个变量存到磁盘读取和直接放到代码中运行,肯定是在代码中拿到的速度快,因为运行时期,都是直接存到内存的。
给大家总结一下:
有了基本的概念之后,我们下面进行环境搭建,在学习阶段,安装 redis 很简单,生产环境一般我们也会选择云产品,一切为了服务保障,虽说它只是做缓存用,但也是系统的一把 保护伞
如果你是 mac 用户,你可以运行如下命令:
安装完成后会提示你运行命令,运行即可。
win 用户也很简单,直接下载 redis 软件,双击运行即可,运行之后它会有一个小方块的图案,和 locahost:6379 的log,说明运行成功了。初始阶段没有配置的 redis 默认 host 就是本地, port 就是 6379 , 而且是 没有密码 就可以访问的。
推荐一个客户端软件 Redis Desktop Manager ,它是 redis 的客户端界面软件,方便面我们学习的时候 清理缓存 使用,生产慎连。
我们不给大家讲它的基本命令使用,它也有语法,可以通过类似命令执行,如果想学习的小伙伴,可以自行搜索。本期重点内容是在 sprinboot 中的使用,我们平时开发不可能是去命令行里敲的,都是代码里执行,而目前市面上有很多封装好的库,我们可以直接调用它的方法,很方便的就可以操作它了,不用记一些繁琐的命令,下面我们就实际操作一下:
修改 pom.xml
修改 application.yml :
redis 默认是有 16 个库,不是 15 个啊,从 0 开始算的,我们随便连一个
通过代码很好理解, 首先需要引入 StringRedisTemplate ,然后需要设置一个 key ,那么思考一下,这个 key 允许重复吗
我们进客户端看一下,发现 key 还是只有一个,但是值变成了新的值了,所以可以得知 key 是唯一的,我们重新设置的时候相当于刷新了它。
在 redis 中删除缓存有两种方式,一种是自我消亡,也就是 过期 销毁,还有有一种是 主动 销毁,我们先看一下,过期时间如何设置
我们设置了 10s 后过期,过完10s后发现,这个```key data``消失了。我们在看看如何主动删除
我们可以利用 Redis 做一个计数器,实现自增功能,你可以用它做网站访问统计
通常做法,我们会把它封装一下,后续使用直接引入封装好的即可,把它直接交给 Springboot容器 管理
其实这个类,你还可以继续进一步封装,比如约束 key 的规范,约束过期时间,约束数据类型等等,这一切也都是为了规范和后期维护,防止滥用缓存
缓存的主要场景是用于解决热点数据问题,因为这些数据是访问频率比较高的,当大量的请求进来, mysql 可能压力很大,这样一来,数据查询效率就很慢,用户肯不高兴等了,这样用户体验很不好。所以我们一般做法,都是把这些热点数据放到缓存里,因为缓存读取速度很快。当有新数据的时候,我们再及时更新它,一般流程是先查询缓存,查到了直接返回缓存数据,查不到再走数据库,然后再刷回缓存。
但是并发足够大的时候,还是会暴露出很多问题,比如面试常问的一些高频问题 缓存雪崩、缓存穿透、缓存雪崩 ,这些问题后边会给大家专门讲,和如何去防范。所以总的来说,引入任何一门技术并不是万事大吉,还需我们不断的在实践中积累经验
本期到这里就结束了,总结一下,我们了解了什么是 redis ,以及在 springboot 中如何去使用它们,很简单,没什么复杂的东西。但这里想多说一点的是,缓存的设计却是很复杂的,因为工具是死的,人是活的,我们如何正确设计,需要我们在项目中不断的积累。
我们之前教大家查询列表数据,都是所有数据返回,还没有教大家如何去做分页,下期将带大家学习一下 mybatis 分页插件的使用 ,下期不见不散, 关注我,不迷路~
那么,二级缓存的作用又是什么呢?简单地说,二级缓存就是一级缓存的缓冲器:一级缓存制造成本很高因此它的容量有限,二级缓存的作用就是存储那些CPU处理时需要用到、一级缓存又无法存储的数据。同样道理,三级缓存和内存可以看作是二级缓存的缓冲器,它们的容量递增,但单位制造成本却递减。需要注意的是,无论是二级缓存、三级缓存还是内存都不能存储处理器操作的原始指令,这些指令只能存储在CPU的一级指令缓存中,而余下的二级缓存、三级缓存和内存仅用于存储CPU所需数据。
根据工作原理的不同,目前主流处理器所采用的一级数据缓存又可以分为实数据读写缓存和数据代码指令追踪缓存2种,它们分别被AMD和Intel所采用。不同的一级数据缓存设计对于二级缓存容量的需求也各不相同,下面让我们简单了解一下这两种一级数据缓存设计的不同之处。
级缓存Session级别缓存位于表示数据库SqlSession象称本缓存级缓存MyBatis内部实现特性用户能配置默认情况自支持缓存用户没定制权利(绝通发插件进行修改);
二级缓存Application应用级别缓存命周期跟Application声明周期说作用范围整Application应用
缓存功能的存在,让我们在浏览网页和访问防止的时候可以更快的加载我们需要的内容,而今天北大青鸟http://www.kmbdqn.cn/就通过案例分析来了解一下,浏览器的缓存功能在使用上都有哪些类型。
1.ServiceWorkerServiceWorker是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。
使用ServiceWorker的话,传输协议必须为HTTPS。
因为ServiceWorker中涉及到请求拦截,所以必须使用HTTPS协议来保障安全。
ServiceWorker的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
ServiceWorker实现缓存功能一般分为三个步骤:先需要先注册ServiceWorker,然后监听到install事件以后就可以缓存需要的文件,那么在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。
当ServiceWorker没有命中缓存的时候,我们需要去调用fetch函数获取数据。
也就是说,如果我们没有在ServiceWorker命中缓存的话,会根据缓存查找优先级去查找数据。
但是不管我们是从MemoryCache中还是从网络请求中获取的数据,浏览器都会显示我们是从ServiceWorker中获取的内容。
2.MemoryCacheMemoryCache也就是内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。
读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。
一旦我们关闭Tab页面,内存中的缓存也就被释放了。
那么既然内存缓存这么高效,我们是不是能让数据都存放在内存中呢?这是不可能的。
计算机中的内存一定比硬盘容量小得多,操作系统需要精打细算内存的使用,所以能让我们使用的内存必然不多。