关于PHP的缓存
2011年05月12日
[b]关于PHP的缓存[/b][b]0. 为什么要缓存[/b]为什么需要缓存,缓存的目的就是加速页面的载入,因此使用缓存之后,你的请求将会直接去获取html文件,传统的动态页面从数据库中获取数据,然后用程序 将数据显示出来的这个过程就被绕过去了,而这个过程是最消耗系统资源的过程,静态页面传送过程中,系统I/O所占用的资源相比之下就可以忽略了。当然,更 传统的其实还是静态页面,因为它出现在动态页面之前。有人说用缓存更新不及时,不够快,所以很不方便,这也是很有道理的,但是仅仅是因为这样就放弃使用缓存,或许不太划算,特别是在你服务器压力比较大的情况下。
[b]1. 什么是缓存[/b]顾名思义,缓存是一块设定了缓冲功能的内存区域,用于提供数据的高速缓冲。无论是针对硬件的CPU的缓存,硬盘的缓存。都是起到减少不比要的I/O访问,提高数据访问速度的目的。
[b]2. 缓存的形式[/b]字面上,缓存就应该是内存的一个部分。但是,也有其他形式的缓存。
CPU上的缓存可以有2到3级RAM,是现在CPU设计中一个重要的组成部分。同样,硬盘上的Flash RAM芯片,承担了缓存的作用。
而针对应用软件系统,例如:Memcached这样的软件,从物理内存中划去了一部分空间,为各种应用程序提供缓存服务。
针对特殊的Web + DB的这种B/S业务系统,还有类似的生成静态页,减少数据库存取I/O操作的缓存方式。
[b]3. PHP缓存的具体方法[/b]针对PHP这种具体的B/S架构的脚本语言,有几种常见的缓存形式。
[b]文件缓存:[/b]文件缓存是PHP缓存的十分常见的一种形式。其主要目的是将页面中不经常变更的数据保存在文件中,当有用户请求访问的时候,直接将数据调出,避免了再次对数据库的请求的I/O操作,减少了数据库的负载压力。
[b]一般情况下,PHP的文件缓存分为两种方法:[/b]
第一种,把需要缓存的数据进行处理,形成PHP可以直接执行的文件。在需要缓存数据的时候,通过include方式引入,并使用。
第二种,把需要的数据通过serialize函数序列化后直接保存到文件。在需要使用缓存数据的时候,通过反序列化读入文件内容并复制给需要的变量,然后使用。当然,这里说到的serialize函数是PHP自带的serialize()函数。针对该函数的改进问题,后续的章节将会提及。
通过测试发现,第二种也就是serialize缓存数据的方式更加高效。
[b]
分析原因:[/b]
include方式读取缓存的时候,PHP需要执行几个过程
1.读取文件
2.解析所Include的文件
3.执行,给变量赋值
而serialize序列化方式读取缓存的时候:
1.读取数据
2.反序列化数据内容
3.给变量赋值
从以上内容对比的话,可能是由于解析PHP文件内的数组需要的时间超过unserialize反序列化数组的时间。
[b]测试代码:[/b]
[b]CacheTest_IncludeFile.php[/b]
view source
print?01 0,
04 'values' =>
05 array (
06 0 =>
07 array (
08 'id' => '3',
09 'title' => 'Title NO.3',
10 'dateline' => '1191244506',
11 ),
12 1 =>
13 array (
14 'id' => '2',
15 'title' => 'Title NO.2',
16 'dateline' => '1191244505',
17 ),
18 2 =>
19 array (
20 'id' => '1',
21 'title' => 'Title NO.1',
22 'dateline' => '1191244504',
23 ),
24 ),
25 'multipage' => NULL,
26 );
[b]CacheTest_SerializeFile.php[/b]
view source
print?01内存缓存之后,第一种通过include读取缓存的方式速度会高于第二种serialize序列化缓存的方式。
本部分参考: http://www.ccvita.com/311.html
[b]Sqlite缓存:[/b]Sqlite是嵌入式SQL数据库引擎SQLite(SQLite Embeddable SQL Database Engine)的一个扩展。SQLite是一个实现嵌入式SQL数据库引擎小型C语言库(C library),实现了独立的,可嵌入的,零配置的SQL数据库引擎。特性包括:事务操作是原子,一致,孤立,并且持久的,即使在系统崩溃和电源故障之后。零配置――不需要安装和管理。实现了绝大多数SQL92标准。整个数据库存储在一个单一的文件中。数据库文件可以在不同字节序的机器之间自由地共享。支持 最大可达2T的数据库。字符串和BLOB类型的大小只受限于可用内存。完整配置的少于250KB,忽略一些可选特性的少于150KB。在大多数常见操作上 比流行的客户/服务器数据库引擎更快。简单易于使用的API。内建TCL绑定。另外提供可用于许多其他语言的绑定。具有良好注释的源代码,代码95%有较好的注释。独立:没有外部依赖。源代码位于公共域,可用于任何用途。用 SQLite连接的程序可以使用SQL数据库,但不需要运行一个单独的关系型数据库管理系统进程(separate RDBMS process)。SQLite不是一个用于连接到大型数据库服务器(big database server)的客户端库(client library),而是非常适合桌面程序和小型网站的数据库服务器。SQLite直接读写(reads and writes directly)在硬盘上的数据库文件。著名的浏览器Firefox的数据库就采用的Sqlite。Firefox所记录的配置,书签,历史记录,Cookie和Password等信息,均存储在Sqlite中。
在缓存方案中,选择采用Sqlite作为方案,主要是看中了它轻量,简单,快速的特点。并且,PHP5以上版本就内部支持了Sqlite的操作,使用起来简单,方便。因此,作为PHP和MySQL中间的一个有效的缓冲机制,Sqlite无意是一个很好的选择。由于Sqlite的缓存方案不是本文探讨的重点。因此,这里就做上述的简单介绍。
[b]Apc缓存:[/b]APC,严格的意义上讲应该成为加速器,全称Alternative PHP Cache,是 PHP 的一个免费公开的优化代码缓存。它用来提供免费,公开并且强健的架构来缓存和优化 PHP 的中间代码。对应的还有eAccelerator 和 Zend Optimizer两个加速器方案。
APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache。我们这里主要控讨php-apc的配置。
[b]安装PHP APC:[/b]
作为测试环境,我们这里使用的是CentOS5.4(2.6.18-194.3.1.el5) + Apache2.2.3 + php5.2.10.我们可以去pecl apc下载APC-3.0.19.tgz
view source
print?1# tar -xzvf APC-3.0.19.tgz
2#cd APC-3.0.19
3# /usr/bin/phpize
4# ./configure --enable-apc --enable-mmap --enable-apc-spinlocks --disable-apc-pthreadmutex
5#make
6#make install
注意:我们这里支持mmap,同时采用spinlocks自旋锁。Spinlocks是Facebook推荐使用,同时也是APC开发者推荐使用的锁机制。
[b]APC PHP.ini配置选项详解[/b]
view source
print?001[APC]
002; Alternative PHP Cache 用于缓存和优化PHP中间代码
003
004apc.cache_by_default = On
005;SYS
006; 是否默认对所有文件启用缓冲。
007; 若设为Off并与以加号开头的apc.filters指令一起用,则文件仅在匹配过滤器时才被缓存。
008
009apc.enable_cli = Off
010;SYS
011; 是否为CLI版本启用APC功能,仅用于测试和调试目的才打开此指令。
012
013apc.enabled = On
014; 是否启用APC,如果APC被静态编译进PHP又想禁用它,这是唯一的办法。
015
016apc.file_update_protection = 2
017;SYS
018; 当你在一个运行中的服务器上修改文件时,你应当执行原子操作。
019; 也就是先写进一个临时文件,然后将该文件重命名(mv)到最终的名字。
020; 文本编辑器以及 cp, tar 等程序却并不是这样操作的,从而导致有可能缓冲了残缺的文件。
021; 默认值 2 表示在访问文件时如果发现修改时间距离访问时间小于 2 秒则不做缓冲。
022; 那个不幸的访问者可能得到残缺的内容,但是这种坏影响却不会通过缓存扩大化。
023; 如果你能确保所有的更新操作都是原子操作,那么可以用 0 关闭此特性。
024; 如果你的系统由于大量的IO操作导致更新缓慢,你就需要增大此值。
025
026apc.filters =
027;SYS
028; 一个以逗号分隔的POSIX扩展正则表达式列表。
029; 如果源文件名与任意一个模式匹配,则该文件不被缓存。
030; 注意,用来匹配的文件名是传递给include/require的文件名,而不是绝对路径。
031; 如果正则表达式的第一个字符是"+"则意味着任何匹配表达式的文件会被缓存,
032; 如果第一个字符是"-"则任何匹配项都不会被缓存。"-"是默认值,可以省略掉。
033
034apc.ttl = 0
035;SYS
036; 缓存条目在缓冲区中允许逗留的秒数。0 表示永不超时。建议值为7200~36000。
037; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。
038
039apc.user_ttl = 0
040;SYS
041; 类似于apc.ttl,只是针对每个用户而言,建议值为7200~36000。
042; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。
043
044apc.gc_ttl = 3600
045;SYS
046; 缓存条目在垃圾回收表中能够存在的秒数。
047; 此值提供了一个安全措施,即使一个服务器进程在执行缓存的源文件时崩溃,
048; 而且该源文件已经被修改,为旧版本分配的内存也不会被回收,直到达到此TTL值为止。
049; 设为零将禁用此特性。
050
051apc.include_once_override = Off
052;SYS
053; 关于该指令目前尚无说明文档,参见:http://pecl.php.net/bugs/bug.php?id=8754
054; 请保持为Off,否则可能导致意想不到的结果。
055
056apc.max_file_size = 1M
057;SYS
058; 禁止大于此尺寸的文件被缓存。
059
060apc.mmap_file_mask =
061;SYS
062; 如果使用
2011年05月12日
[b]关于PHP的缓存[/b][b]0. 为什么要缓存[/b]为什么需要缓存,缓存的目的就是加速页面的载入,因此使用缓存之后,你的请求将会直接去获取html文件,传统的动态页面从数据库中获取数据,然后用程序 将数据显示出来的这个过程就被绕过去了,而这个过程是最消耗系统资源的过程,静态页面传送过程中,系统I/O所占用的资源相比之下就可以忽略了。当然,更 传统的其实还是静态页面,因为它出现在动态页面之前。有人说用缓存更新不及时,不够快,所以很不方便,这也是很有道理的,但是仅仅是因为这样就放弃使用缓存,或许不太划算,特别是在你服务器压力比较大的情况下。
[b]1. 什么是缓存[/b]顾名思义,缓存是一块设定了缓冲功能的内存区域,用于提供数据的高速缓冲。无论是针对硬件的CPU的缓存,硬盘的缓存。都是起到减少不比要的I/O访问,提高数据访问速度的目的。
[b]2. 缓存的形式[/b]字面上,缓存就应该是内存的一个部分。但是,也有其他形式的缓存。
CPU上的缓存可以有2到3级RAM,是现在CPU设计中一个重要的组成部分。同样,硬盘上的Flash RAM芯片,承担了缓存的作用。
而针对应用软件系统,例如:Memcached这样的软件,从物理内存中划去了一部分空间,为各种应用程序提供缓存服务。
针对特殊的Web + DB的这种B/S业务系统,还有类似的生成静态页,减少数据库存取I/O操作的缓存方式。
[b]3. PHP缓存的具体方法[/b]针对PHP这种具体的B/S架构的脚本语言,有几种常见的缓存形式。
[b]文件缓存:[/b]文件缓存是PHP缓存的十分常见的一种形式。其主要目的是将页面中不经常变更的数据保存在文件中,当有用户请求访问的时候,直接将数据调出,避免了再次对数据库的请求的I/O操作,减少了数据库的负载压力。
[b]一般情况下,PHP的文件缓存分为两种方法:[/b]
第一种,把需要缓存的数据进行处理,形成PHP可以直接执行的文件。在需要缓存数据的时候,通过include方式引入,并使用。
第二种,把需要的数据通过serialize函数序列化后直接保存到文件。在需要使用缓存数据的时候,通过反序列化读入文件内容并复制给需要的变量,然后使用。当然,这里说到的serialize函数是PHP自带的serialize()函数。针对该函数的改进问题,后续的章节将会提及。
通过测试发现,第二种也就是serialize缓存数据的方式更加高效。
[b]
分析原因:[/b]
include方式读取缓存的时候,PHP需要执行几个过程
1.读取文件
2.解析所Include的文件
3.执行,给变量赋值
而serialize序列化方式读取缓存的时候:
1.读取数据
2.反序列化数据内容
3.给变量赋值
从以上内容对比的话,可能是由于解析PHP文件内的数组需要的时间超过unserialize反序列化数组的时间。
[b]测试代码:[/b]
[b]CacheTest_IncludeFile.php[/b]
view source
print?01 0,
04 'values' =>
05 array (
06 0 =>
07 array (
08 'id' => '3',
09 'title' => 'Title NO.3',
10 'dateline' => '1191244506',
11 ),
12 1 =>
13 array (
14 'id' => '2',
15 'title' => 'Title NO.2',
16 'dateline' => '1191244505',
17 ),
18 2 =>
19 array (
20 'id' => '1',
21 'title' => 'Title NO.1',
22 'dateline' => '1191244504',
23 ),
24 ),
25 'multipage' => NULL,
26 );
[b]CacheTest_SerializeFile.php[/b]
view source
print?01内存缓存之后,第一种通过include读取缓存的方式速度会高于第二种serialize序列化缓存的方式。
本部分参考: http://www.ccvita.com/311.html
[b]Sqlite缓存:[/b]Sqlite是嵌入式SQL数据库引擎SQLite(SQLite Embeddable SQL Database Engine)的一个扩展。SQLite是一个实现嵌入式SQL数据库引擎小型C语言库(C library),实现了独立的,可嵌入的,零配置的SQL数据库引擎。特性包括:事务操作是原子,一致,孤立,并且持久的,即使在系统崩溃和电源故障之后。零配置――不需要安装和管理。实现了绝大多数SQL92标准。整个数据库存储在一个单一的文件中。数据库文件可以在不同字节序的机器之间自由地共享。支持 最大可达2T的数据库。字符串和BLOB类型的大小只受限于可用内存。完整配置的少于250KB,忽略一些可选特性的少于150KB。在大多数常见操作上 比流行的客户/服务器数据库引擎更快。简单易于使用的API。内建TCL绑定。另外提供可用于许多其他语言的绑定。具有良好注释的源代码,代码95%有较好的注释。独立:没有外部依赖。源代码位于公共域,可用于任何用途。用 SQLite连接的程序可以使用SQL数据库,但不需要运行一个单独的关系型数据库管理系统进程(separate RDBMS process)。SQLite不是一个用于连接到大型数据库服务器(big database server)的客户端库(client library),而是非常适合桌面程序和小型网站的数据库服务器。SQLite直接读写(reads and writes directly)在硬盘上的数据库文件。著名的浏览器Firefox的数据库就采用的Sqlite。Firefox所记录的配置,书签,历史记录,Cookie和Password等信息,均存储在Sqlite中。
在缓存方案中,选择采用Sqlite作为方案,主要是看中了它轻量,简单,快速的特点。并且,PHP5以上版本就内部支持了Sqlite的操作,使用起来简单,方便。因此,作为PHP和MySQL中间的一个有效的缓冲机制,Sqlite无意是一个很好的选择。由于Sqlite的缓存方案不是本文探讨的重点。因此,这里就做上述的简单介绍。
[b]Apc缓存:[/b]APC,严格的意义上讲应该成为加速器,全称Alternative PHP Cache,是 PHP 的一个免费公开的优化代码缓存。它用来提供免费,公开并且强健的架构来缓存和优化 PHP 的中间代码。对应的还有eAccelerator 和 Zend Optimizer两个加速器方案。
APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache。我们这里主要控讨php-apc的配置。
[b]安装PHP APC:[/b]
作为测试环境,我们这里使用的是CentOS5.4(2.6.18-194.3.1.el5) + Apache2.2.3 + php5.2.10.我们可以去pecl apc下载APC-3.0.19.tgz
view source
print?1# tar -xzvf APC-3.0.19.tgz
2#cd APC-3.0.19
3# /usr/bin/phpize
4# ./configure --enable-apc --enable-mmap --enable-apc-spinlocks --disable-apc-pthreadmutex
5#make
6#make install
注意:我们这里支持mmap,同时采用spinlocks自旋锁。Spinlocks是Facebook推荐使用,同时也是APC开发者推荐使用的锁机制。
[b]APC PHP.ini配置选项详解[/b]
view source
print?001[APC]
002; Alternative PHP Cache 用于缓存和优化PHP中间代码
003
004apc.cache_by_default = On
005;SYS
006; 是否默认对所有文件启用缓冲。
007; 若设为Off并与以加号开头的apc.filters指令一起用,则文件仅在匹配过滤器时才被缓存。
008
009apc.enable_cli = Off
010;SYS
011; 是否为CLI版本启用APC功能,仅用于测试和调试目的才打开此指令。
012
013apc.enabled = On
014; 是否启用APC,如果APC被静态编译进PHP又想禁用它,这是唯一的办法。
015
016apc.file_update_protection = 2
017;SYS
018; 当你在一个运行中的服务器上修改文件时,你应当执行原子操作。
019; 也就是先写进一个临时文件,然后将该文件重命名(mv)到最终的名字。
020; 文本编辑器以及 cp, tar 等程序却并不是这样操作的,从而导致有可能缓冲了残缺的文件。
021; 默认值 2 表示在访问文件时如果发现修改时间距离访问时间小于 2 秒则不做缓冲。
022; 那个不幸的访问者可能得到残缺的内容,但是这种坏影响却不会通过缓存扩大化。
023; 如果你能确保所有的更新操作都是原子操作,那么可以用 0 关闭此特性。
024; 如果你的系统由于大量的IO操作导致更新缓慢,你就需要增大此值。
025
026apc.filters =
027;SYS
028; 一个以逗号分隔的POSIX扩展正则表达式列表。
029; 如果源文件名与任意一个模式匹配,则该文件不被缓存。
030; 注意,用来匹配的文件名是传递给include/require的文件名,而不是绝对路径。
031; 如果正则表达式的第一个字符是"+"则意味着任何匹配表达式的文件会被缓存,
032; 如果第一个字符是"-"则任何匹配项都不会被缓存。"-"是默认值,可以省略掉。
033
034apc.ttl = 0
035;SYS
036; 缓存条目在缓冲区中允许逗留的秒数。0 表示永不超时。建议值为7200~36000。
037; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。
038
039apc.user_ttl = 0
040;SYS
041; 类似于apc.ttl,只是针对每个用户而言,建议值为7200~36000。
042; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。
043
044apc.gc_ttl = 3600
045;SYS
046; 缓存条目在垃圾回收表中能够存在的秒数。
047; 此值提供了一个安全措施,即使一个服务器进程在执行缓存的源文件时崩溃,
048; 而且该源文件已经被修改,为旧版本分配的内存也不会被回收,直到达到此TTL值为止。
049; 设为零将禁用此特性。
050
051apc.include_once_override = Off
052;SYS
053; 关于该指令目前尚无说明文档,参见:http://pecl.php.net/bugs/bug.php?id=8754
054; 请保持为Off,否则可能导致意想不到的结果。
055
056apc.max_file_size = 1M
057;SYS
058; 禁止大于此尺寸的文件被缓存。
059
060apc.mmap_file_mask =
061;SYS
062; 如果使用