一 认识缓存
1 为什么使用?
(1)当服务器资源有限,数据库能接受的请求次数也受限时,可以利用缓存尽可能的提高吞吐量,它可以减少计算量,缩短请求流程
下图列举了我们能够用到的缓存
(2)命中率:
通常通过命中率来衡量缓存机制的好坏,它是指 请求缓存的次数 与 缓存正确返回的次数 的比率
以MySQL的Query cache为例,Query cache缓存客户端提交给mysql的select语句以及该语句的结果集,就是讲select语句
和查询结果做hash关系映射后保存在一定的内存区域
MySQL提供了一系列的Global Status记录Query Cache的当前状态:
Qcache_free_blocks:目前处于空闲状态的Query Cache中内存block的数目
Qcache_free_memory:目前处于空闲状态的Query Cache中内存总量
Qcache_hits : Qcache名中次数
Qcache_inserts : 向Query cache中插入新的query cache的次数,也就是未命中的次数
Qcache_lowmem_prunes:Querycache内存不足时需要删除旧的query cache,给新的query cache对象使用次数
Qcache_not_cached:未被cache的SQL数,包括没办法被Cache的SQL和由于Query_cache_type设置而不会被cache的SQL
Qcache_queries_in_cache:目前在Query cache中的SQL数量
Qcache_total_blocks:Qcache中总的block数
可以使用show global status来查看全局状态
命中率 = Qcache_queries_in_cache/Com_select 注意sQL cache只有select语句会被缓存,insert update delete不会,show命令和存储过程也不会
(3)缓存更新策略:
Mysql 的Query cache策略:在Mysql中,设置query cache所使用的总内存,MySQL会把默认进行缓存的SQL语句结果集缓存,
内存塞满后就会剔除旧的query cache对象,为了保持一致性,表数据变化时,会使缓存失效
常见的缓存更新策略:
FIFO(First in First Out):最先进入缓存的最先删除
LFU(Less Frequenrly Used):最少使用的元素被清除
LRU(Less Recently Used):最近最少使用的会被清除
MySQL采用的策略,猜测来说应该是FIFO,即队列清除
(4)缓存最大量数据
缓存最大量数据是指在缓存中能处理的元素最大个数或者所能使用的最大存储空间,通常都会有限制,如MySQL的是有query_cache_size来限制,
并且可以修改,而基于内存的memcache缓存最大量可由操作系统觉得,默认64M每次可申请的最大内存2M
超过缓存机制时的处理:
a 停止缓存服务,清除所有缓存数据
b 拒绝写入,不再更新缓存数据
c 根据缓存策略清除旧数据
d 在c的基础上淘汰旧数据,腾出新的空间
2 文件缓存,它是把数据缓存到硬盘,与内存相比,存取相对较慢,但是
a 硬盘容量大
b 比内存相对稳定性更可靠,断电后数据不易丢失,存储也简单可靠
c 固态硬盘如SSD的出现使硬盘的读写速度得到提高
d 比较容易扩展,可以使用磁盘阵列,分布式处理等进行大规模的存储和管理
基于以上几点,文件缓存还是很必要的
(1)文件缓存机制
a 根据配置文件判断是否需要缓存,不需要则直接include PHP文件,需要缓存转到b
b 判断对应缓存文件是否存在,不存在则‘编译’,并缓存,否则转到c
c 判断缓存文件是否过期,过期则重新编译
虽然文件缓存受磁盘IO的影响,但在web中类似模板编译后静态存储可以减少与web服务器及数据库的交互,及php解释引擎对脚步解释的消耗
(2)开源文件缓存产品Secache
a 纯php实现
b LRU策略
c key-value二进制数据库
d 使用slab形式存储数据
e 使用hash定位,迅速读取
f 最大支持1G缓存
(3)opcache缓存
php的缓存机制:
优点:有效避免内存泄漏,垃圾回收机制更简单,避免因为一个程序的问题而连累整个服务器
缺点:无法复用数据,每个PHP请求都得重复执行请求-翻译-执行的过程
a opcache缓存就是虚拟机把php编译成一种中间码的结果缓存起来,下次php运行时,直接执行,省去了Flex语法器进行语法编译和检查,一定程度上提高了php运行速度
b 也可以使用apc,eAccelerator工具,达到所谓的常驻内存的作用,它支持win和Linux,关于它的配置文章很多,不再详述
c 如何查看opcache
首先要安装VLD扩展,Vulcan Logic Disassembler,用来检测php脚本的执行情况,但是,这个扩展需要自己源码编译,Linux下的安装如下:
wget http://pecl.PHP.net/get/vld
tar zxvf vld-0.9.1
phpize
./configure
make && make install
d 编辑php的配置文件,激活扩展
extension = vld.so
测试代码:
<?php
echo "hello,world" ;
$data['first'] = 'hello' ;
$data['first']['second'] = 'world';
echo $data['first'] ;
命令行下执行:
php -dvld.active = 1 ~/www/test.php (文件代码的路径) 得到汇编代码
上边提到的eAccelerator就是缓存opcode,同时提供一组API来操作缓存数据,变相实现了类似Java的共享变量的功能,PHP本身在请求结束后就销毁变量,没办法实现变量共 享,无法在另一个进程中得到其数据,借助eAccelerator可以实现类似的效果,主要有
eaccelerator_put($key,$value,$ttl=0) : 将value存储在共享内存中,ttl秒
eaccelerator_get($key) : 从共享内存中得到key的值,如果不存在或者已过期,返回null
这两组API来实现
3 客户端(web)缓存
如图片,文件,HTML页面缓存都称为web缓存,很多时候,图片是被浏览器缓存到本地,根据一定的规则去更新的,当然,这个规则可以人为指定
a 客户端缓存规则:
如果响应头信息告诉缓存器不要缓存, 它就不会缓存
请求信息需要验证时,也不会缓存
在回应消息中不存在校验器(ETag或者Last-modified头),缓存服务器就不会缓存相应的内容,缓存服务器认为缺乏直接的更新度信息
含有完整的过期时间,会被缓存
浏览器已经使用过缓存副本,并且在一个会话中已经检验过内容的新鲜度
缓存未过期时,直接读取缓存,而不会像原服务器发送请求
缓存过期会像原服务器发送校验请求
b http协议中缓存的应用:
expires
cache-control
ETag
注意:加了缓存之后三种情况下才会更新 1 缓存到期 2 缓存被清除 3 强制刷新页面 加下边的代码:
header("Cache-Control:no-cache,must-revalidate");//http1.1
header("Pragma:no-cache");//http1.0
可以禁用浏览器缓存,在前台页面使用缓存,减少http请求,在后台页面压缩数据,减小数据的传输量,对服务器开启压缩,客户端可以在浏览器进行解压
4 html5中的Application Cache 这是h5新增的功能,用来处理离线应用中的问题,会有3个方面的优势
a 离线缓存:用户不用联网,即可浏览整个网站
b 高速:缓存资源是放在本地的,加载速度更快
c 更小的服务器负载:浏览器只需要下载变更的资源,相同的资源不必重复下载
使用Application Cache只需要指定一个Manifest文件配置文件缓存即可、
5 web服务器缓存 a Apache缓存,Apache的Expires和Cache-Control模块包含控制缓存的信息,这些模块需要和Apache一起编译,
虽然包含在默认,但默认是关闭的,找到httpd程序并运行httpd -l会列出所有可用模块儿,要用的是mod_expires和mod_headers,
Apache一旦启用了响应模块儿,就可以在.htaccess文件或者服务器的acess.conf文件,通过mod_expires副本过期时间了,
包括设置控制应答时的expires头内容个Cache-Control头的max-age指令 ExpiresActive on 设置expires后,系统会自动输出Cache-Control的
max-age信息,关于Expires的详细内容可以看apache的官方文档
6 Nginx缓存 配置缓存的代码如下:
proxy_cache_path /path/to/cache_levels=1:2 keys_zone=NAME:10m inactive=5m max_size=2m clean_time=1m
注意:这个配置是在server标签之外,
levels是指缓存空间的hash目录有2层,第一层有1个字母,第二层2个,类似/path/to/cache/c/29/......key_zone为这个空间起个名字,
10m是指空间大小为10M,inactive的5m指默认缓存时长为5分钟,max_size指单个文件的大小超过2M就不缓存clean_time指1分钟清理一次
location / {
proxy_pass http://www.baidu.com;
proxy_cache NAME;//使用name这个
key_zone proxy_cache_valid 200 302 1h;#200 302状态码保持一小时
proxy_cache_valid any 1m; #其它保持一分钟
}