转-架构高性能网站秘笈(二)——动态内容缓存
转自CSDN博客,u010425776,http://m.blog.csdn.net/u010425776/article/details/51089204
什么是动态内容缓存?
浏览器向服务器发送请求后,服务器会根据浏览器的要求做相应的处理(如:数据库操作),然后将处理后的结果注入JSP页面生成HTML,最后将生成的HTML返回给浏览器显示。我们知道,数据库读取操作是非常耗时的,如果能将每次请求中的数据库处理时间去掉,那服务器的相应速度将会大幅提升。要实现这一点,我们就需要将常用的HTML页面事先生成好,当用户发出请求时,服务器只需从缓存中取出即可,无需再做数据库处理操作。
综上所述:事先生成HTML页面的技术称为动态内容缓存。
什么是“缓存命中率”?
缓存命中率 = 访问缓存的请求数/请求总数
缓存命中率是衡量缓存是否有效的重要指标。如果将所有需要访问的数据均缓存起来,那么缓存命中率是100%。但一半情况下,为了节约存储空间,只将访问频率较高的数据缓存起来,那么这样就会造成有一些请求能够通过缓存访问数据,而有一些请求需要查询数据库访问数据。
我们没有办法确保缓存的命中率100%,但我们需要使用一些算法确保缓冲命中率较高。也只有当缓冲命中率较高的情况下,缓冲才能发挥它真正的价值。
PS:缓存与缓冲的区别?
这里顺便提一下“缓存”和“缓冲”的区别。
-
缓冲:缓冲是一块临时的存储空间,为了解决不同存储设备之间读写速率不匹配而产生的。
比如:内存的读写速度远远大于硬盘的读写速度。当内存中的数据向硬盘中写入时,内存会先将数据写入内存缓冲区,再由内存缓冲区向硬盘写入数据。这样内存快速腾空之后就可以做其他事了,提高了效率。 -
缓存:缓存是在一些为了避免重复计算,而被暂时性存储的数据。
综上所述:缓冲=缓冲区,它是指内存中的一片区域;而缓存指的是数据,一些味了避免重复计算而被临时性存储的数据。
它们都是为了提高处理效率而存在的,都采用了“牺牲空间换取时间”的思想。
缓存的三种存储方式
缓存可以存储在三种不同的地方:
- 存储在内存
- 存储在IO设备
- 存储在内存和IO设备上
- 存储在缓存服务器上
对于小型网站,缓存首选的存储位置就是内存。内存相对于IO设备有较快的访问速度,能大大缩短缓存的读取时间。但内存资源比较宝贵,如果没钱买大内存的服务器的话,那就只好考虑第二种办法,将缓存存在IO设备中。
对于一些小型网站,如果需要存储的缓存数据量比较大,而且买不起大内存的服务器的话,那存储在IO设备是不错的选择。但IO设备相对于内存来说有个致命的缺陷,那就是慢!因此,对于资金不充裕的小型网站来说,第三种方式最为合适。
如果既想获得内存的读写速度,又想拥有IO设备的巨大存储空间,那就可以选择两者结合的方式。
内存中开辟一块固定大小的缓冲区,用于存储使用频率较高的缓存数据,而将使用频率较低的缓存数据存储至IO设备。当缓冲区存满时,你需要使用LRU算法将最近最旧未使用的缓存从缓冲区中扔出去,而将最近一段时间IO设备中访问频率最高的缓存放进来,从而保证了当前缓冲区中数据的命中可能性是最大的。
最后,对于大型网站来说,可以使用专门的缓存服务器来存储缓存。这主要有两点好处:
- 节约服务器的内存资源,让服务器的内存作更多数据处理的工作,而把数据存储的工作交给缓存服务器;
- 缓存服务器具有更好的可扩展性。如果网站需要定期举办一些营销活动,为了应付急剧增加的并发量,缓存服务器是不二之选。
但是,由于Web服务器与缓存服务器采用TCP通信,而建立和释放TCP连接时间开销比较大,因此对于小型网站来说,直接将缓存存在内存无疑是种首选办法。
如何实现缓存?
这里就简单地介绍下基于内存的缓存机制,近期我会单独写一篇“基于内存+IO+LRU算法的缓存机制”的博客,敬请关注。
服务器在接收客户端发来的请求后,首先根据请求的URL判断内存中是否有对应的缓存;若有的话先判断该缓存是否过期,若没过期就直接返回缓存数据;若过期了,或者内存中根本就没有该请求的缓存的话,就调用业务逻辑层的相关函数,处理客户端发来的请求,生成客户端需要的数据。然后给生成的数据设置一个有效期,并存入缓存,供下次使用,最后将数据返回给用户。
静态化页面
之前我们介绍的缓存机制仍然需要服务器程序去判断存储空间中是否有缓存,而服务器程序判断的过程也需要时间,如果缓存很多的话,服务器程序需要找半天。那么我们能否把静态页面事先都生成好,让浏览器直接访问静态页面,而无需再通过服务器程序访问缓存。
要知道,浏览器直接访问静态页面的速度比通过服务器程序访问静态页面的速度要快很多很多很多!
要实现这样的想法,我们可以这么做:
- 服务器程序启动的时候将生成所有需要访问的HTML页面,存储至服务器外设中;
- 浏览器所有a标签中的href都填写这些静态HTML页面URL;
- 在服务器中开启一条定时线程,每隔一段时间检查动态数据发生修改的HTML页面,并生成新的HTML页面;
- 当数据库发生修改时,立即更新与该数据相关的HTML页面。