PHP APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache。我们这里主要控讨php-apc的配置。

安装PHP APC

作为测试环境,我们这里使用的是CentOS5.3(2.6.18-128.el5PAE) + Apache2.0(prefork) + php5.2。我们可以去pecl apc下载APC-3.0.19.tgz

# tar -xzvf APC-3.0.19.tgz
#cd  APC-3.0.19
# /usr/bin/phpize
# ./configure --enable-apc --enable-mmap --enable-apc-spinlocks --disable-apc-pthreadmutex
#make
#make install

注意:我们这里支持mmap,同时采用spinlocks自旋锁。Spinlocks是Facebook推荐使用,同时也是APC开发者推荐使用的锁机制。

PHP APC 配置参数

如果你使用的系统环境跟我的测试环境是一样的话,可以在/etc/php.d目录下创建文件apc.ini,并且相关配置写入/etc/php.d/apc.ini文件。这里,我们挑了一些常用到的配置,并进行探讨。把相关的配置放在一起解释。

apc.enabled=1
apc.enabled默认值是1,你可设成0禁用APC。如果你设置为0的时候,同样把extension=apc.so也注释掉(这样可以节约内存资源)。一旦启用了APC功能,则会缓存Opcodes到共享内存。

apc.shm_segments = 1
apc.shm_size = 30
APC既然把数据缓存在内存里面,我们就有必要对它进行内存资源限定。通过这二个配置可以限定APC可以使用的内存空间大小。 apc.shm_segments指定了使用共享内存块数,而apc.shm_size则指定了一块共享内存空间大小,单位是M。所以,允许APC使用的 内存大小应该是 apc.shm_segments * apc.shm_size = 30M。你可以调整一块共享内存的大小空间。当然,一块共享内存最大值是受操作系统限制的,即不能超过/proc/sys/kernel/shmmax大 小。否则APC创建共享内存的时候,会失败。在apc.shm_size达到了上限的时候,你可以通过设置apc.shm_segments来允许APC 使用更多的内存空间。我们推荐,如果调用APC使用内存空间的话,先考滤apc.shm_size,后考滤apc.shm_segments。具体数值, 可以根据apc.php监控情况进行规划与调整。值得注意的是,每一次调整需要重启httpd守护进程,这样可以重新加载apc.so模块。跟随着 httpd守护进程启动,apc.so模块就会加载。apc.so加载初始化的时候,通过mmap请求分配内存指定大小的内存,即 apc.shm_size * apc.shm_segments。而且,这里使用的是匿名内存映射方式,通过映射一个特殊设备/dev/zero,提供一个“大型”的,填满了零的内存 供APC管理。
为了验证以上陈述,我们注释掉apc.ini配置,并且写了以下php脚本观察apc.so模块初始化的分配的内存空间。

<?php
//@file: apc_load.php
if (!extension_loaded('apc')) {dl('apc.so');        #加载apc.so模块
  echo posix_getpid();  #//输出当前进程的pid,我这里这里输出的是14735
  ob_flush();flush();sleep(3600);       #让进程进入休眠状态.这样,我们可以观察内存分配情况
 }
?>

#strace -p `cat /var/run/httpd.pid`
open("/var/www/html/apc_load.php", O_RDONLY) = 13
...
mmap2(NULL, 31457280, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0xb5ce7000
...
nanosleep({3600, 0},

红色部分,我们可以看出。通过mmap系统内核调用分配了30M(31457280/1024/1024)内存空间。 PROT_READ|PROT_WRITE表示该内存空间可供读取与写入。MAP_SHARED表示该内存空间与其它进程是共享的,即其它进程也可以进行 读取与写入,我们可以通过apc.php进行管理该块内存空间亦是受益于此设定。MAP_ANONYMOUS则表示匿名映射。其中fd=-1表示忽略,因 为这里映射的特殊设备/dev/zero。最后的0表示无偏移量。我们还可以通过进程映像文件查看该块内存的具体情况
#cat /proc/14735/smaps

b5ce7000-b7ae7000 rw-s 00000000 00:08 633695     /dev/zero (deleted)
Size:       30720 kB
Rss:        44 kB
Shared_Clean:   0 kB
Shared_Dirty:   0 kB
Private_Clean:  0 kB
Private_Dirty:  44 kB

可以很容易地发现起始地址0xb5ce7000与上面mmap系统内核调用返回的地址一样。该块内存是可读写rw,并与其它进程共享s。而/dev /zero则是映射文件,该文件节点是633695。其中,size表示进程可以使用的内存空间,而rss则表示实际分配的内存空间,且由 Private_Dirty可以看出,实际分配的44kb内存是由当前进程自己分配的。

apc.num_files_hint = 1000
apc.user_entries_hint = 4096
这二配置指定apc可以有多少个缓存条目。apc.num_files_hint说明你估计可能会有多少个文件相应的opcodes需要被缓成,即大约可 以有多少个apc_compiler_cache条目。另外apc.user_entries_hint则说明你估计可能会有多少个 apc_userdata_cache条目需要被缓存。如果项目中不使用apc_store()缓存用户数据的话,该值可以设定得更小。也就是说 apc.num_files_hint与apc.user_entries_hint之和决定了APC允许最大缓存对象条目的数量。准确地设置这二个值可 以得到最佳查询性能。当然,如果你不清楚要进行多少缓存(缓存对象实例)的情况下,你可以不必修改这二项配置。
其中apc.user_entries_hint要根据项目实际开发使用了apc_store()条目估计其值大小。相较而 言,apc.num_files_hint可以通过find命令,更容易地估计其大小。比如我们的web根目是/var/vhosts,则使用下面的 find命令可以大致地统计当前apc.num_files_hint数目.
#find /var/vhosts \( -name “*.php” -or -name “*.inc” \) -type f -print |wc -l
1442

apc.stat = 1
apc.stat_ctime = 0
这二个参数,只跟apc_compiler_cache缓存相关,并不影响apc_user_cache。我们前面提到过 apc_complier_cache,它缓存的对象是php源文件一一对应的opcodes(目标文件)。PHP源文件存放在磁盘设备上,与之相对应的 Opcodes目标文件位置内存空间(共享内存),那么当php源文件被修改以后,怎么通知更新内存空间的opcodes呢?每次接收到请求后,APC都 会去检查打开的php源文件的最后修改时间,如果文件的最后修改时间与相应的内存空间缓存对象记录的最后修改时间不一致的话,APC则会认为存放在内存空 间的Opcode目标文件(缓存对象)已经过期了,acp会将缓存对象清除并且保存新解析得到的Opcode。我们关心的是,即便没有更新任何php源文 件,每次接受到http请求后,APC都会请求系统内核调用stat()来获取php源文件最后修改时。我们可以通过将apc.stat设置为0,要求 APC不去检查Opcodes相对应的php源文件是否更新了。这样可以获得最佳的性能,我们也推荐这么做。不过,这样做有一点不好的就是,一旦有PHP 源文件更新了之后,需要重启httpd守护进程或者调用apc_cache_clear()函数清空APC缓存来保证php源文件与缓存在内存空间的 Opcodes相一致。

<?php
define('ROOTP', dirname(__FILE__) . '/');
include(ROOTP . 'i1.php');
require(ROOTP . 'i2.php');
include_once(ROOTP . 'i3.php');
require_once(ROOTP . 'i4.php');
require(ROOTP . 'i5.php');
include(ROOTP . 'i6.php');
?>

# strace -e trace=file -p `cat /var/run/httpd.pid`
getcwd("/var/www/html", 4096)           = 14
stat64("/var/www/html/i1.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
stat64("/var/www/html/i2.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html/i3.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
open("/var/www/html/i3.php", O_RDONLY)  = 12
stat64("/var/www/html/i3.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/var/www/html/i4.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
open("/var/www/html/i4.php", O_RDONLY)  = 12
stat64("/var/www/html/i4.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
stat64("/var/www/html/i5.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
stat64("/var/www/html/i6.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0
chdir("/tmp")                           = 0# strace -e trace=file -p `cat /var/run/httpd.pid`
getcwd("/var/www/html", 4096)           = 14
open("/var/www/html/i3.php", O_RDONLY)  = 12
open("/var/www/html/i4.php", O_RDONLY)  = 12
chdir("/tmp")                           = 0

对比可见,当apc.stat=0时,省了很多系统内核调用,我们没有看到系统内核调用stat64了。其中,i3.php和i4.php分别是 php的include_once和require_once函数调用,它要交给fstat()系统内核调用来检查文件是否打开过。单从性能角度出发的 话,require比require_once性能更佳。

设置apc.stat_ctime的意义并是很大。如果apc.stat_ctime值为1时,仅当php源文件的创建时间(ctime)大于 php源文件的最后修改时间(mtime)时,缓存对象的mtime时间会被php源文件的ctime所代替,否则缓存对象的mtime依然记录为php 源文件的mtime。这样做是防止通过cvs, svn或者rsync等工具刷新php源文件的mtime,这样会导致APC通过比对php源文件的创建时间ctime来决定缓存对象有没有过期。我们推 荐该保持默认值,即apc.stat_ctime = 0

apc.ttl=0
apc.user_ttl=0
缓存对象的生命周期。其中ttl表示Time To Live,意味着指定时间后缓存对象会被清除。其中0表示永不过期。我们前面提过,APC能缓存的条目是受限定的,如果你把ttl设置永不过期的话,当缓存条目已满或者缓存空间不够,之后的缓存都将失败。
其中apc.ttl作用于apc_compiler_cache。当apc.ttl大于0时,每次请求都会对比这次的请求时间与上一次请求时间之差是不是大于apc.ttl,如果大于apc.ttl,则会被认缓存条目过期了,会被清理。
比较有意思的是apc.user_ttl,它主要作用于apc_user_cache缓存。我们知道,这种类型的缓存是通过 apc_store($key, $var, $ttl = 0)创建的缓存对象。函数apc_store()中指定的$ttl与php.ini中设定的apc.user_ttl有什么异同,是我们比较关心的。因为 它们同样作用于apc_userdata_cache缓存。经过分析,我们知道:判断apc_user_cache缓存过期的依据是,当 apc.user_ttl大于0,且这次http请求时间与上一次http请求时间之差大于apc.user_ttl,则认为相应的缓存条目已过期;或 者,user.data.ttl(php函数apc_store()中指定的$ttl)大于0,且这次http请求时间与缓存对象创建时间ctime之差 大于user.data.ttl,则同样认为缓存条目已过期,会被清除。
我们推荐,如果你的项目较为稳定,并且apc.stat设置为0。同时apc.shm_size、apc.num_files_hint设置合理的 话,apc.ttl建议设置为0。即apc_compiler_cache永不回收,直到重启httpd守护进程或者调用函数 apc_cache_clear()清缓存。至于apc.user_ttl,建议设置为0,由开发人员调用apc_store()函数的时候,设 置$ttl来指定该缓存对象的生命周期。

apc.slam_defense=0
apc.write_lock=1
apc.file_update_protection=2
之所以把这三个配置放在一起解释,是因为他们的意义很相近。其中apc.file_update_protection最好理解,它的单位是时间单位秒。 如果当前http请求时间与php源文件最好修改时间mtime之差小于apc.file_update_protection时间,APC则不会缓存该 php源文件与之对应的Opcodes,直到接下来的某次访问,并且访问时间与php源文件的最后修改时间大于 apc.file_update_protection时间,相之相应的Opcodes才会被缓存到共享内存空间。这样做的好处是,不容易被用户访问到你 正在修改的源文件。我们推荐在开发环境,该值可以设置得更大一点,但在运营环境,我们推荐保留默认值即可。
当你的网站并发量很大的时候,可能出现由http守护进程fork的多个子进程同时缓存同一份Opcodes的情况。通过 apc.slam_defense则可以减少这种事情的发生机率。比如,apc.slam_defense值设置为60的时候,当遇到未缓存的 Opcodes,每100次有60次是不缓存的。对于并发量不大的网站,我们推荐该值设定为0,对于并发量高的网站我们可以根据统计适当地调整该值。而 apc.write_lock是一个布尔值,当该值设置为1的时候,当多个进程同时缓存同一份Opcodes时,仅当最先那个进程缓存有效,其它的无效。 通过apc.write_lock设置,有效地避免了缓存写竞争的出现。

apc.max_file_size=1M
apc.filters = NULL
apc.cache_by_default=1
这三个配置放在一起,是因为他们都用于限制缓存。其中apc.max_file_size表示如果php源文件超过了1M,则与之对应的opcodes不 被缓存。而apc.filters指定一个文件过滤列表,以逗号(,)隔开。当apc.cache_by_default等于1时,与 apc.filters列表中指定的文件名相匹配的文件不会被缓存。相反,apc.cache_by_default等于0时,仅缓存与 acp.filters列表中指定的文件相匹配的文件。

总结

1,使用Spinlocks锁机制,能够达到最佳性能。
2,APC提供了apc.php,用于监控与管理APC缓存。不要忘记修改管理员名和密码
3,APC默认通过mmap匿名映射创建共享内存,缓存对象都存放在这块”大型”的内存空间。由APC自行管理该共享内存
4,我们需要通过统计调整apc.shm_size、apc.num_files_hints、apc.user_entries_hint的值。直到最佳
5,好吧,我承认apc.stat = 0 可以获得更佳的性能。要我做什么都可以接受.
6,PHP预定义常量,可以使用apc_define_constants()函数。不过据APC开发者介绍说pecl hidef性能更佳,抛异define吧,它是低效的。
7,函数apc_store(),对于系统设置等PHP变量,生命周期是整个应用(从httpd守护进程直到httpd守护进程关闭),使用APC比Memcached会更好。必竟不要经过网络传输协议tcp。
8,APC不适于通过函数apc_store()缓存频繁变更的用户数据,会出现一些奇异现象。

转载于:https://www.cnblogs.com/lchb/articles/3270763.html

php加速 PHP APC 浅析相关推荐

  1. Nature子刊:厌氧消化链球菌促进结直肠癌发生及调节肿瘤免疫

    英文题目: Peptostreptococcus anaerobius promotes colorectal carcinogenesis and modulates tumour immunity ...

  2. nginx0.8 + php-5.3.4 + memcached

    nginx0.8 + php-5.3.4 + memcached#-- 编码转换库 Unicode和其他的传统编码之间转换的需求 --#wget http://mozbuildtools.google ...

  3. Linux+php+memcache+APC加速PHP网站

    一.前言     对于一个站长而言不仅要做好网站内容外,还需要对网站做优化,如果速度访问很慢的,没有人下次再访问你的站点,目前国内使用php的网站不计其数,这里用我的博客为例:http://china ...

  4. GPU加速原理浅析及代码实现

    GPU加速原理浅析及代码实现 一.CUDA简介 二.GPU架构特点 三.CUDA线程模型 四.CUDA内存模型 五.CUDA编程规范 **第一个要掌握的编程要点**:**我们怎么写一个能在GPU跑的程 ...

  5. php编译优化,浅析使用Turck-mmcache编译来加速、优化PHP代码

    php_screw确实很不错,但是只能起到加密的作用,并没有加速和优化的作用. 下面我们来看看:Turck MMCache它的作用是通过对php代码的编译来加速.优化php代码,我们如果发布的php代 ...

  6. php加速缓存器opcache,apc,xcache,eAccelerator

    一.opcache opcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销. PHP 5.5. ...

  7. Android HWUI硬件加速模块浅析

    原址 什么是硬件加速(What) 传统软件的UI绘制是依靠CPU来完成的,硬件加速就是将绘制任务交由GPU来执行.Android系统负责硬件加速的模块主要是HWUI,如下图所示: 为什么要硬件加速(W ...

  8. 网络加速技术浅析(二)

    上一篇我们看了一些网络加速的技术,它们致力于减少处理每个网络数据包所需要的CPU时间,要么是把一些网络协议的运算卸载(offload)到网卡,要么是减少数据拷贝对CPU资源的消耗.在上一篇我们说过,网 ...

  9. Android ART dex2oat 加载加速浅析

    前言 手机淘宝插件化框架Atlas在ART上首次启动的时候,会通过禁用dex2oat来达到插件迅速启动的目的.之后后台进行dex2oat,下次启动如果dex2oat完成了则启用dex2oat,如果没有 ...

  10. 浅析门户网站体育赛事CDN加速解决方案

    经过近些年来的高速发展,互联网已经成为现今媒体传播的主要力量.这一点在大型体育赛事的报道与转播上,体现的尤为明显.更及时的信息内容.更多样的报道形式.更齐全的资料组成.更方便的阅读查询.更具互动性的报 ...

最新文章

  1. python进程执行带有参数的任务(args、kwargs)
  2. 表格td超出部分隐藏,显示...
  3. putty 保存密码 自动登陆 四种方法
  4. centos7设置密码策略_Linux系统设置复杂密码策略方法总结
  5. C - Log Calculator FZU - 2036
  6. 机器人搏击大赛冠军_机器人的江湖 谁主沉浮——2017格斗机器人大赛侧记
  7. JVM 运行机制及基本原理
  8. 升级后开机就提示“android.process.acore”停止执行 --分析 解决方式
  9. 大规模知识图谱的构建及应用
  10. Lucene查询结果高亮
  11. 烈火如歌手游找回服务器,《烈火如歌》05月02日新服公告:侠肝义胆
  12. GULP 案例 1 代码解释:声子色散曲线和态密度的计算
  13. 港股美股打新截然不同!教你玩转美股打新
  14. dell emc isilon环境 Windows共享文件下生成.snapshot无法删除
  15. js引用本地json文件
  16. Unity游戏动画 从入门到住院 1
  17. WuThreat身份安全云-TVD每日漏洞情报-2022-12-26
  18. linux cups工作原理,Linux打印系统CUPS原理分析
  19. 程序员的中年危机好可怕
  20. 2023 年值得推荐的 Vue 库

热门文章

  1. mysql修改主键为unique_mysql 如何修改、添加、删除表主键及unique约束
  2. android灰度发布平台,移动APP灰度发布策略
  3. javascript 字符串与数组之间的相互转换(join、split)与splice介绍
  4. 二、常量、变量和基本数据类型
  5. PHP JAVA BASE64 encode decode
  6. Apache JMeter web 应用测试工具使用快速入门
  7. mysql 初始化_MySQL安装与初始化
  8. BZOJ4318: OSU!
  9. 如何使用Transact-SQL进行事务处理[示例]
  10. 阶段3 2.Spring_03.Spring的 IOC 和 DI_3 spring基于XML的IOC环境搭建和入门