http的缓存分为2种,一种是本地缓存,一种是协商缓存.
本地缓存,当用户第一次想服务器发送请求的时候,如果该资源允许缓存,那么将会把资源存在本地的一个临时文件夹,并标识过期时间.在过期时间前,用户再次请求这个资源,浏览器将不会发器http请求,直接使用缓存在本地的文件.本地缓存是最节约资源的一个缓存,因为他不会发起任何http请求,对服务器,对网络等资源都没有造成任何压力.
协商缓存,当用户在本地缓存找到一个资源,但是他已经过期或者不确定该资源是否和服务器上的资源一致的情况下,就会发起一个http请求,这个请求同时会带这个本地资源的一些信息,如果这个资源和服务器的资源一致(没有任何更改),那么就返回304,只是浏览器继续使用本地的资源.如果资源不一致,那么服务器就会返回200,同时把新的资源返回到浏览器.
协商缓存在提供服务器性能上起到很大的作用, 如果没有协商缓存,那么每一个资源都需要到服务器上读取,这样会很耗磁盘的IO,同时也会延迟服务器处理改请求的时间(因为保持到资源发送完毕).如果协商缓存起了作用,那么该请求在apache层就已经处理完毕,而且只需要发送一个304的http头,完全不涉及磁盘操作,响应时间也非常短.由此提高了服务器的性能.
更详细的内容在我另外一篇blog上,请移步:浅谈HTTP缓存机制!
静态页面缓存
说到静态页面缓存,我们就不得不说一下APACHE处理PHP程序和html页面的流程.
html页面,当apache接受到一个请求,判断这个请求是指向一个html页面的时候,就到磁盘上找到这个文件,然后读取这个文件的内容并返回到浏览器
php程序,apache开启的时候,会加载php5_module这个模块,当服务器接受到一个php请求的时候,他就会到磁盘中找到这个php文件,然后把文件通过php模块去解释并执行,而在等待PHP执行完毕之后,把数据返回到apache,然后apache在把内容返回到浏览器上.
而在等待php返回的这段时间,apache的这一个子线程是一直在等待的,而且执行PHP也是需要用到其他资源的,比如CPU资源,连接数据库等资源.
相比较之下,PHP程序耗的资源远多于html页面所需要的资源.
现在我们碰到这样一个问题,我们有一个产品的展示页面,这个产品的更改率是非常小的,也就是1个月也不改那么1次.而现在都是通过PHP来显示页面,也就是每次想访问这个产品信息的时候,就把产品ID通过参数传递到PHP,然后PHP从数据库中获取信息,然后返回到apache,再返回到浏览器.这样是非常耗资源的.既然这个产品是很少改动的,那我们能不能通过缓存的方法来减少服务器的开销呢?这个时候就需要用到静态页面缓存.
当第一次访问某个产品的信息时,执行PHP并返回产品信息到浏览器.同时把要返回的数据以html形式保存到服务器本地,第二次访问这个产品的时候,就可以直接返回html页面,而不需要执行php程序.
这个解决方案需要rewrite模块的配合
例如,http://www.keepmyway.com/12.html
通过rewrite模块判断是否存在12.html这个文件,如果不存在,需要重写url,把请求转到php处理.
简单而言,静态化缓存就是把PHP执行后的内容以html形式保存,以便下次反问的时候不需要调用PHP程序,因而提高了服务器的性能
opcode缓存
opcode缓存是针对php代码本身的一种缓存.需要用到某些工具来实现这些功能,其代表产品就是apc和xcache.
那什么是opcode?他有什么用?为什么对他进行缓存就可以提高php执行效率?这些问题我们都要从php的自身的执行过程说起.
在你执行一个php程序的时候,首先就是调用一个php解释器,把PHP代码进行编译并解释,解释之后的PHP会形成一种类似汇编形式的代码,这种代码称之为”opcode”, 然后再把opcode代码放进zend引擎里面进行解释并执行.
上面简单的处理流程已经说明,在PHP代码到真正通过ZEND引擎处理的这中间,是存在一个opcode代码的.zend引擎处理的并不是你编写的php代码,而是这段php代码经过处理之后的opcode.
同一个PHP文件,执行3次,每一次都要解释成opcode,再放到zend引擎处理, 这是浪费了一定的资源的.为什么不把opcode缓存起来,然后下次执行同一个文件的时候,直接把opcode传递给zend引擎,这就节约了把php代码解释成opcode这段时间浪费的资源了.
这个就是针对php代码自身的缓存
mysql查询缓存
web开发,最容易碰到的瓶颈就是数据库压力过大.因为数据库的文件存在磁盘中,无论是增删该查都设计到磁盘操作,但是磁盘的IO是固定的, 而且磁盘在众多计算机硬件中处理速度是最慢的.mysql为了提高性能,自身就做了各种优化,这里我们只简单地说一下mysql自身的查询缓存.
假设现在某站点上的一个展品非常吸引人,他的id为10,如果没有缓存,那么每打开一次这个页面,调用一次数据查询语句,就要从磁盘上找到这个记录,然后读出来,在返回到程序上.这是一个效率非常低的处理方式.
mysql自身的缓存做了这样的优化处理,当第一次执行某条查询的时候,会把查询的记录集缓存到内存中,如果下一次再执行同样的操作(必须是同样的语句,无论是条件还是大小写,都必须一致),那么就不用到磁盘中查找,直接把缓存中的数据返回.这样就可以提高了自身性能.
mysql的缓存是一个很复杂的配置,要考虑到很多的问题,例如是否无论多大的结果他都缓存?是否会无限大的缓存?如果无限制得缓存,那不是把内存都占满了?如果不是无限制地缓存,那缓存的数据什么时候失效果?如果缓存的数据所在的表做了改动,那缓存的数据是否失效?这些问题都不是三言两语可以说清楚,由于边幅太长,这里就不详细叙述了.
memcache缓存
其实把这个小标题写成memcache并不合理,可是想不到一个合适的名字,而且现在做这种缓存的大多都是用memcache(现在用redis的也很多了),姑且就叫做memcache缓存吧.
memcache是什么东西这里就不详细去说明了,如果有不知道的同学可以去google一下.这里讨论一下memcache最大的功效—-减少数据库压力.
数据库压力过大,最容易碰到的瓶颈.这话在上面已经说过,就算mysql自身有缓存机制,很多时候也抗不住高访问量,因为数据库自身的缓存也是有局限的.而且,就算有了mysql的缓存,但我们每发送一次查询的请求,mysql都要通过开启一个线程来接受请求,然后到自身的缓存中去查询想要的结果集是否存在等等操作,这些都是要消耗CPU资源的.而且mysql的qps(response per second)也是有上限的.
那什么办法可以减少数据库的压力么?因而,memcache应运而生.
memcache主要以key => value的形式把数据存在内存中,因为是放在内存中,所以点服务器断电等意外发生,那么数据将去丢失,因此memcache只适合做缓存,而不适合做持久化保存数据的工具.
当我们用php去取数据的时候,先到memcache中查找,如果找不到对应的数据,再到mysql里面查找,当在mysql找到数据之后,php不但把数据返回到浏览器,同时也把这分数据存放到memcache上,第二次查询同样的数据十,就用到mysql查找,而是直接在memcache内获取.因为memcache是把数据放在内存中,所以存取效率会非常块.提高了程序执行效率的同时,也减少了mysql的压力.从而提高了整体的性能.
web服务器缓存
服务器缓存和页面静态化有点相似,不过页面静态化是需要通过PHP生成了一个html页面.而服务器的缓存则是在服务器接受到PHP返回的数据后,把数据返回到浏览器的同时,把文件以html的形式存放到某个文件夹,当下次访问这个php程序的时候,服务器并不去调用php程序,而是直接返回已保存的html页面.
在nginx上有一个fastcgi-cache的配置项,就是实现这个功能的.apache没有相应的功能,不过可以使用squid配合apache使用,实现该功能.但是如果使用squid,则在维护apache的同时,要多维护一个squid系统.感觉还是用ngnix比较简单.