今天抛开编译(opcode缓存)缓存、CDN缓存、web服务器(如nginx)缓存不说,只谈程序能控制实现的缓存方式:
一、本地缓存:
先问个问题,我要发货到辽宁,最牛逼的物流是什么?大货车?高铁?飞机?时光隧道?机器猫?我晕,你还让不让我写下去了。做过物流的应该知道,最厉害的物流不是物联调度系统响应有多快(服务器处理能力),运输工具有多快(传输速度),也不是你同时能发多少趟车(带宽),那你说是啥?对了,在当地建仓库,仓库建到他家去。
缓存也是这个道理,最牛B的缓存就是把最后要呈现于浏览器的信息内容存到浏览器本地。
用户在向服务器获取内容时因为头部带有If-Modified-Since,服务器判断本地的信息是否过期,没有过期就返回304让浏览器到本地拿货;过期了就重新生成内容,并构造缓存的头部信息,其中包含很重要的max-ag,Expires,Last-modified信息(能让请求头带上If-Modified-Since)。
public function set_cache_header($last_modified, $expiration)
{
$max_age = $expiration - $_SERVER['REQUEST_TIME'];
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
{
$this->set_status_header(304);
exit;
}
else
{
header('Pragma: public');
header('Cache-Control: max-age='.$max_age.', public');
header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
}
}
怎么让浏览器不缓存静态资源?
设置头信息Cache-Control: no-cache header,这样就不会缓存静态资源了,每次都去服务器上重新获取。
对firefox的浏览器要在header中加一个Cache-Control: no-cache, no-store
二、服务端/应用层缓存
这个级别的缓存,重点是在缓存介质的使用上。介质可以是File,Nosql 。主要是减少Cpu运算,磁盘这种慢的I/O读写和内在占用。
CI框架的做法是根据用户请求的URL作为唯一的KEY值进行缓存,那么value就是该地址向浏览器输出的内容。当然我们也可以有别的用法,不去缓存整个页面,而是缓存片段,比如省、市、区三级联动数据,比如栏目类别数据。不过对于需要身份验证和判断的页面,或者适时性很强的页面,就不适合作缓存了,反而需要强制不缓存。
怎么设置过期呢?CI框架是这样做的,将过期时间$expire放在缓存的内容前面,并用一个特殊字符串"ENDCI--->"隔开。
在读取缓存时,先取出前端的过期时间$expire,与当前请求时间$_SERVER['REQUEST_TIME']比对,如果小的话就说明过期了,然后无情删除,如果大的话,就说明还是有效缓存。
当某个终端用户第一次请求该url,会在服务器上生成一个缓存,同时按照“本地缓存”中的实现方法
三、数据库缓存
数据库缓存重点同样是在缓存介质的使用上。CI的实现方式是将查询类的语句的结果对像序列化并保存到文本中,对于缓存的key实现方法,各种框架都有不同,有的把查询语句md5生成唯一key。CI的做法是,根据调用的控制器名和方法名生成一个目录,然后将方法中的查询缓存文件保存到子目录中。