缓存是什么
1)许多人认为,“缓存”是内存的一部分。许多技术文章都是这样教授的,但是还是有很多人不知道缓存在什么地方,缓存是做什么用的?其实,缓存是CPU的一部分,它存在于CPU中。
2)CPU存取数据的速度非常的快,一秒钟能够存取、处理十亿条指令和数据。而内存就慢很多,快的内存能够达到几十兆就不错了,可见两者的速度差异是多么的大。
3)CPU高速缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。在缓存中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的,当CPU调用大量数据时,就可先缓存中调用,从而加快读取速度。
4)当CPU需要读取数据并进行计算时,首先需要将CPU缓存中查到所需的数据,并在最短的时间下交付给CPU。如果没有查到所需的数据,CPU就会提出“要求”经过缓存从内存中读取,再原路返回至CPU进行计算。而同时,把这个数据所在的数据也调入缓存,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。
缓存在不同场景的分类
客户端缓存
浏览器的缓存可以将之前渲染的页面保存为文件,当用户再次访问时可以避开网络连接,从而减少负载。如何把客户端缓存对于业务组件透明和客户端缓存数据及时更新,是客户端缓存能否成功应用的关键。客户端可以将内同缓存在内存、文件或本地数据库中。
网页浏览器启用缓存策略后,访问静态图片文件时客户端与服务器交互如下:
If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中;如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。
web代理
web代理的作用跟浏览器的内置缓存类似,位于浏览器和互联网之间,网络请求通过代理来中继。对于企业而言,既可以节省成本,又能提高性能。
常用的web代理有Varnish,Ngnix,Squid,它们都是反向代理 。反向代理一般缓存静态资源,动态资源转发到应用服务器处理。以Squid为例,Squid反向代理一般只缓存静态资源,动态程序默认不缓存。根据从WEB服务器返回的HTTP头标记来缓冲静态页面。有四个最重要HTTP 头标记:
- Last-Modified: 告诉反向代理页面什么时间被修改
- Expires: 告诉反向代理页面什么时间应该从缓冲区中删除
- Cache-Control: 告诉反向代理页面是否应该被缓冲
- Pragma: 用来包含实现特定的指令,最常用的是Pragma:no-cache
Squid 反向代理加速网站实例:
- 通过DNS的轮询技术,将客户端的请求分发给其中一台Squid 反向代理服务器处理;
- 如果这台 Squid 缓存了用户的请求资源,则将请求的资源直接返回给用户;
- 否则这台 Squid 将没有缓存的请求根据配置的规则发送给邻居Squid 和后台的WEB 服务器处理;
- 这样既减轻后台 WEB 服务器的负载,又提高整个网站的性能和安全性。
边缘缓存
边缘缓存位于应用服务器的前面,可以处理来自不同用户的请求,主要用于向用户提供静态的内容,以减少应用服务器的接入。边缘缓存的商业化服务就是CDN了。
CDN的全称是Content Delivery Network,即内容分发网络。CDN将网站的内容发布到最接近用户的网络 " 边缘 " ,使用户可以就近取得所需的内容,降低网络拥塞,提高用户访问响应速度和命中率。
CDN本质就是加速用户获取资源的系统。这些资源可以是静态资源,也可以是动态资源,取决于我们的推送策略。不过还是建议使用CDN加速网站的静态部分。现在大部分的视频加速完全取决于CDN。视频资源都是放到CDN上,用来加速用户获取数据的速度,用户一般通过运营商,比如接入电信、长城这些运营商。用户想上网的时候通过这些运营商的接口,去访问离它最近的城域网的地址,再通过城域网跳到主干网,主干网再通过IP来找到对应的访问资源所在的服务器。当然很大一部分内容已经在上层的节点上CDN已经找到了对应的内容,他也就不用再往后查找直接返回对应的资源。
CDN和反向代理的基本原理都是缓存,区别在于CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据;而反向代理则部署在应用服务器机房,当用户请求到达中心机房后,首先访问的服务器反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户。
CDN=更智能的镜像+缓存+流量导流。镜像指的是把网站上的静态内容下载到各地服务器上。
平台缓存
平台缓存是用来写应用的框架,或者缓存的专用库。Java语言中,缓存框架很多,例如EHcache、JBoss Cache等等。简单来说,就平台级缓存而言,只需要在框架侧配置一下属性即可,不需要调用特定的方法或函数。
应用缓存
应用及缓存,需要自己通过代码来实现缓存。这里是NoSQL的胜场,不论是Redis还是MongoDB,都可以作为应用缓存的工具。一个典型的方式是,每分钟或一段时间后统一生成某类页面存储在缓存中,也可以在热数据变化时更新缓存。
数据库缓存
数据库缓存是一类特殊的缓存。大多数数据库不需要配置就可以快速运行,但并没有为特定的需求进行优化。在数据库调优的时候,缓存优化是一项很重要的工作。
MySQL为例,MySQL中使用了查询缓冲机制,将Select语句和查询结果存放在缓冲区中,以后对于同样的Select语句,将直接从缓冲区中读取结果,以节省查询时间,提高SQL查询的效率。
缓存更新问题
方案1:需要操作人员去操作,或者定时调度
-
主动
:后台点击更新缓存按钮,从DB查找最新数据集合,删除原缓存数据,存储新数据到缓存; -
问题
:更新过程中删除掉缓存后刚好有业务在查询,那么这个时候返回的数据会是空,会影响用户体验。
方案2:由用户触发更新
-
被动
:前台获取数据时发现没有缓存数据就会去数据库同步数据到缓存; -
问题
:当并发请求获取缓存数据不存在的时候,就会产生并发的查询数据的操作(大量用户同时去数据库查询数据)。
方案3:提前加载好数据
-
主动
:后台点击更新缓存按钮,从DB查找最新数据集合,这里不删除缓存,通过遍历数据覆盖和删除掉无效的数据; -
问题
:逻辑相对麻烦,而且更新机制无法通用。
关于一级缓存和二级缓存
为了分清这两个概念,我们先了解一下RAM。RAM和ROM相对的,RAM是掉电以后,其中的信息就消失那一种,ROM在掉电以后信息也不会消失那一种。
RAM又分两种,一种是静态RAM,SRAM;一种是动态RAM,DRAM。前者的存储速度要比后者快很多,我们现在使用的内存一般都是动态RAM。
缓存通常都是静态RAM,速度是非常的快,但是静态RAM集成度低(存储相同的数据,静态RAM的体积是动态RAM的6倍),价格高(同容量的静态RAM是动态RAM的四倍)。
由此可见,扩大静态RAM作为缓存是一个非常愚蠢的行为,这样就有了一个折中的办法,不扩大原来的静态RAM缓存,而是增加一些高速动态RAM作为缓存。这些高速动态RAM速度要比常规动态RAM快,但比原来的静态RAM缓存慢,我们把原来的静态RAM缓存叫做一级缓存,而把后来增加的动态RAM叫二级缓存。
一级缓存和二级缓存中的内容都是内存中访问频率高的数据的复制品(映射),它们的存在都是为了减少高速CPU对慢速内存的访问。通常CPU找数据或指令的顺序是:先到一级缓存中找,找不到再到二级缓存中找,找不到再到内存中找,再找不到就要到硬盘中去找了。