缓存,顾名思义,就是临时存储信息以提高访问性能。PHP的缓存技术大体可分为三大类:
1. 缓存内容(Caching content)
2. 内存缓存(Memory Cache)
3. 数据库缓存(Database Cache)
1. 缓存内容
将某个脚本的最终输出作为静态文件存放在文件系统中,比如👤信息,商品显示页,当数据库内容被修改或文件过期时,重新执行原始脚本以更新缓存内容。简单示例如下:
内容缓存是最为常见的,比如输出缓存ob_start,页面部分缓存ob_get_contents,甚至数据库某些查询结果的缓存。
2. 内存缓存
顾名思义,通过内存进行缓存,显然会比缓存在文件系统中快出许多,常见的技术如下:
Opcode Cache
简要介绍下PHP的运行机制:a)子进程解释器解析php脚本,比如Zend Complier; b)zend_language_scanner会首先对代码进行扫描,将PHP代码进行词法分析,转化为一系列的token array;c)zend_language_parse将上一步产生的一系列token处理空格等无用的代码后转化成一系列表达式;d)这些表达式经过complier阶段生成opcode【即Operation code,是一个四元组(opcode,op1,op2,result)】并返回zend_op_array指针;e)zend_vm_execute根据传入的zend_op_array指针,执行opcode并将结果返回输出;
对opcode进行缓存的软件很多,比如apc,eAcclerator,Xcache,Zend Platform,这里主要介绍下apc;
APC提供了两种缓存功能:缓存Opcode(目标文件),即apc_complier_cache,缓存用户数据即apc_user_cache. 下图为使用了apc_complier_cache后的php解析过程:
由于apc并未内置到PHP解释器内核中,你需要单独安装并在php.ini中添加apc配置:
apc的使用是比较简单的,主要比较常用的有三个方法:
apc_add/apc_store– store a variable in the cache. The only difference betweenapc_addandapc_storeis thatapc_storeoverwrites the data if it already exists andapc_adddoes not。
apc_fetch– fetch a variable from the cache
apc_delete– delete a variable from the cache.
http://www.360doc.com/content/16/0204/17/22355405_532718314.shtml
据说apc使用了spinlocks(自旋)锁机制,能够达到最佳性能,但这也可能会死锁,进而影响到php-fpm进程(https://yq.aliyun.com/articles/1699);
一方面apc_store对于系统设置等PHP变量的缓存是比较好的选择,但apc不合适通过apc_store频繁变更用户数据,会出现一些奇异现象;
Memcache
分布式对象缓存系统,通过在内存中以键值对的形式缓存数据和对象以减少读取数据库的次数,进而提高驱动网站的速度。它可以应对任意多个连接,使用非阻塞的网络IO。
Memcache与memcached区别:Memcache是项目名称,而memcached是项目在服务器段的主程序文件名;
所谓的分布式对象缓存体现,单个服务器就算了,比如现memcache客户端要添加“shanghai”,客户端根据查询算法(比如Consistent hashing)根据“键”来决定保存数据的memcached服务器。至于memcache服务器端,它会在内存中开辟一块空间,然后建立一个HashTable, 并复制管理维护。“shanghai”到了选定的服务器后,将“shanghai”维护到HashTable,并在内存中保存其值。
同样在获取保存的数据时,比如键值“hangzhou”,memcache客户端会通过相同的方式,根据键值选择服务器,然后发送get命令取得value,当然若不幸该键值尚不存在或已失效,那就从元数据取之并reset。这样键值对通过HashTable存储到不同的服务器上,就实现了memcached的分布式。
注意:查询算法因节点分布不均而造成的数据倾斜问题,memcache服务器增多是否会影响键值的重新分布以及增减服务器是否会导致缓存的大范围丢失。
Memcache区分为memcache服务器端的安装和memcache客户端安装,默认端口号11211。简单示例如下:
既然是缓存,定是有过期时间的,比如上述图片中set('things',$things,false,86400),对memcache而言,它不会在过期监视上耗费CPU时间,当某个值过期后,其内存并没有被删除,而是当再次在get时查看记录的时间戳,检查记录是否过期,如果已过期,则返回空并且清空,这种技术被称为lazy(惰性)expiration。
另外,memcache会优先使用已超时记录的空间,但即使如此,也会发生追加新纪录时空间不足的情况,此时就要使用Least Recently Used(LRU)机制来分配空间【即使某个key设置的是永久有效期】。
对于分布式的对象缓存系统memcache,其须以root权限运行,且访问是无用户状态的,考虑到安全性,一般通过放在内网,并通过防火墙限制外网访问memcache端口达到安全。
数据库缓存
上述的缓存技术都是在应用层讨论的,database server本身也可以cache,典型的就是SQL第一次查询时解析,后续查询则直接从database server cache中获取结果。简单config MySQL my.cnf如下:
query_cache_type =1
query_cache_limit = 1M
query_cache_size =16M