转载(https://www.kancloud.cn/thinkphp/php-best-practices/40866)

使用 APC

在一个标准的 PHP 环境中,每次访问PHP脚本时,脚本都会被编译然后执行。 一次又一次地花费时间编译相同的脚本对于大型站点会造成性能问题。

解决方案是采用一个 opcode 缓存。 opcode 缓存是一个能够记下每个脚本经过编译的版本,这样服务器就不需要浪费时间一次又一次地编译了。 通常这些 opcode 缓存系统也能智能地检测到一个脚本是否发生改变,因此当你升级 PHP 源码时,并不需要手动清空缓存。

PHP 5.5 内建了一个缓存 OPcache。PHP 5.2 - 5.4 下可以作为PECL扩展安装。

此外还有几个PHP opcode 缓存值得关注 eaccelerator, xcache,以及APC。 APC 是 PHP 项目官方支持的,最为活跃,也最容易安装。 它也提供一个可选的类 memcached 的持久化键-值对存储,因此你应使用它。

安装 APC

在 Ubuntu 12.04 上你可以通过在终端中执行以下命令来安装 APC:

user@localhost: sudo apt-get install php-apc

除此之外,不需要进一步的配置。

将 APC 作为一个持久化键-值存储系统来使用

APC 也提供了对于你的脚本透明的类似于 memcached 的功能。 与使用 memcached 相比一个大的优势是 APC 是集成到 PHP 核心的,因此你不需要在服务器上维护另一个运行的部件, 并且 PHP 开发者在 APC 上的工作很活跃。 但从另一方面来说,APC 并不是一个分布式缓存,如果你需要这个特性,你就必须使用 memcached 了。

示例

<?php
// Store some values in the APC cache. We can optionally pass a time-to-live,
// but in this example the values will live forever until they're garbage-collected by APC.
apc_store('username-1532', 'Frodo Baggins');
apc_store('username-958', 'Aragorn');
apc_store('username-6389', 'Gandalf'); // After storing these values, any PHP script can access them, no matter when it's run!
$value = apc_fetch('username-958', $success);
if($success === true)
print($value); // Aragorn $value = apc_fetch('username-1', $success); // $success will be set to boolean false, because this key doesn't exist.
if($success !== true) // Note the !==, this checks for true boolean false, not "falsey" values like 0 or empty string.
print('Key not found'); apc_delete('username-958'); // This key will no longer be available.
?>

陷阱

  • 如果你使用的不是 PHP-FPM(例如你在使用 mod_php 或 mod_fastcgi), 那么每个 PHP 进程都会有自己独有的 APC 实例,包括键-值存储。 若你不注意,这可能会在你的应用代码中造成同步问题。

相关文章(https://www.cnblogs.com/vania/p/4745029.html)

APC的介绍

The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. Its goal is to provide a free, open, and robust framework for caching and optimizing PHP intermediate code.

APC官方网站:http://www.php.net/manual/en/book.apc.php

WIN下最新版本的下载地址:http://downloads.php.net/pierre/

下载连接:http://downloads.php.net/pierre/php_apc-3.1.4-5.3-VC6-x86.zip  根据自己的PHP编译版本使用相对应的DLL

1、APC缓存简介

APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”。它为我们提供了缓存和优化PHP的中间代码的框架。 APC的缓存分两部分:系统缓存和用户数据缓存。

系统缓存

它是指APC把PHP文件源码的编译结果缓存起来,然后在每次调用时先对比时间标记。如果未过期,则使用缓存的中间代码运行。默认缓存 3600s(一小时)。但是这样仍会浪费大量CPU时间。因此可以在php.ini中设置system缓存为永不过期(apc.ttl=0)。不过如果这样设置,改运php代码后需要重启WEB服务器。目前使用较多的是指此类缓存。

用户数据缓存

缓存由用户在编写PHP代码时用apc_store和apc_fetch函数操作读取、写入的。如果数据量不大的话,可以一试。如果数据量大,使用类似memcache此类的更加专著的内存缓存方案会更好

缓存key生成规则

APC的缓存中的每个slot都会有一个key,key是 apc_cache_key_t结构体类型,除了key相关的属性,关键是h字段的生成。 h字段决定了此元素落于slots数组的哪一个位置。对于用户缓存和系统缓存,其生成规则不同。 用户缓存通过apc_cache_make_user_key函数生成key。通过用户传递进来的key字符串,依赖PHP内核中的hash函数(PHP的hashtable所使用的hash函数:zend_inline_hash_func),生成h值。
系统缓存通过apc_cache_make_file_key函数生成key。通过APC的配置项apc.stat的开关来区别对待不同的方案。在打开的情况下,即 apc.stat= On 时,如果被更新则自动重新编译和缓存编译后的内容。此时的h值是文件的device和inode相加所得的值。在关闭的情况下,即apc.stat=off时,当文件被修改后,如果要使更新的内容生效,则必须重启Web服务器。此时h值是根据文件的路径地址生成,并且这里的路径是绝对路径。即使你是使用的相对路径,也会查找PG(include_path)定位文件,以取得绝对路径,所以使用绝对路径会跳过检查,可以提高代码的效率。

常用APC设置

apc.cache_by_default默认启用缓存。1表示“启用”,0表示“禁用”
apc.filters根据逗号分隔的POSIX正则表达式判断文件需要缓存还是不需要缓存。以a+开头的正则
表达式将强制APC不缓存与此正则表达式匹配的任何文件。以a-开头的正则表达式将强制
APC缓存与此正则表达式匹配的任何文件
apc.stat 启用或禁用APC对于所有请求PHP脚本是否有更改的检查。每次调用脚本时均会执行此
过程。如果禁用该设置,在对PHP脚本进行任意更改后均需要重新启动WEB服务器以
清除缓存并更改脚本内容。0=禁用,1=启用,默认1
apc.enabled启用或禁用APC缓存。0=禁用,1=启用,默认1
apc.shm_size 设置APC允许使用的共享内存大小,此值以兆字节为单位
apc.shm_segments 设置可用的共享内存段总数
apc.include_once_override启用或禁用include_once和require_once的优化。启用该设置时,可减少PHP内部函数进行的额外系统调用。0=禁用,1=启用,默认0
apc.optimization 设置优化级别。0=禁用优化功能
apc.num_files_hint设置你认为需要缓存的文件数。默认值1000,如果不确定文件数,可以设置0
apc.ttl 设置文件存储在缓存中的过期时间,以秒为单位。
apc.write_lock 开启该设置将强制单个进程缓存特定的脚步。适用于必须缓存多个文件的大流量WEB服务器或应用程序

添加缓存过程

以用户缓存为例,apc_add函数用于给APC缓存中添加内容。如果key参数为字符串中,APC会根据此字符串生成key,如果key参数为数组,APC会遍历整个数组,生成key。根据这些key,APC会调用_apc_store将值存储到缓存中。由于这是用户缓存,当前使用的缓存为apc_user_cache。执行写入操作的是apc_cache_make_user_entry函数,其最终调用apc_cache_user_insert执行遍历查询和写入操作。与此对应,系统缓存使用apc_cache_insert执行写入操作,其最终都会调用_apc_cache_insert。

不管是用户缓存还是系统缓存,大体的执行过程类似,步骤如下:

  1. 通过求余操作,定位当前key的在slots数组中的位置: cache->slots[key.h % cache->num_slots];
  2. 在定位到slots数组中的位置后,遍历当前key对应的slot链表,如果存在slot的key和要写入的key匹配或slot过期,清除当前slot。
  3. 在最后一个slot的后面插入新的slot。

2、APC模块安装

WINDOWS

第一步:下载php_apc.dll 在http://pecl.php.net/package/apc 要与php版本对应 将php_apc.dll放入你的ext目录

第二步:让php.ini支持apc扩展模块。 然后打开php.ini 加入:

extension=php_apc.dll

apc.rfc1867 = on

apc.max_file_size = 100M

upload_max_filesize = 100M

post_max_size = 100M

//以上参数可自己定义

第三步:检查是否支持PHP APC apc_store apc_fetch PHP APC 配置参数 把相关的配置放在一起解释。

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

apc.shm_segments = 1

总结 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()缓存频繁变更的用户数据,会出现一些奇异现象。

LIUNX

wget http://pecl.php.net/get/APC-3.1.8.tgz

tar -zxvf APC-3.1.8.tgz cd APC-3.1.8

/usr/local/php/bin/phpize

./configure --enable-apc --enable-mmap --enable-apc-spinlocks
--disable-apc-pthreadmutex
--with-php-config=/usr/local/php/bin/php-config

make

sudo make install

在/usr/local/php/etc/php.ini 加入

extension = "apc.so" ;

;APC setting

apc.enabled = 1

apc.shm_segments = 1

apc.shm_size = 64M

apc.optimization = 1

apc.num_files_hint = 0

apc.ttl = 0

apc.gc_ttl = 3600

apc.cache_by_default = on

重启apache 或者 /usr/local/php/sbin/php-fpm restart

查看phpinfo apc

下面引用www.initphp.com 框架的APC缓存类

initphp框架之APC缓存类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php 
if (!defined('IS_INITPHP')) exit('Access Denied!'); 
/*********************************************************************************
 * InitPHP 2.0 国产PHP开发框架  Dao-APC缓存 不适合频繁写入的缓存数据
 *-------------------------------------------------------------------------------
 * 版权所有: CopyRight By initphp.com
 * 您可以自由使用该源码,但是在使用过程中,请保留作者信息。尊重他人劳动成果就是尊重自己
 *-------------------------------------------------------------------------------
 * $Author:zhuli
 * $Dtime:2011-10-09 
***********************************************************************************/ 
class apcInit { 
       
    /**
     * Apc缓存-设置缓存
     * 设置缓存key,value和缓存时间
     * @param  string $key   KEY值
     * @param  string $value 值
     * @param  string $time  缓存时间
     */ 
    public function set_cache($key, $value, $time = 0) {  
        if ($time == 0) $time = null; //null情况下永久缓存 
        return apc_store($key, $value, $time);; 
    
       
       
    /**
     * Apc缓存-获取缓存
     * 通过KEY获取缓存数据
     * @param  string $key   KEY值
     */ 
    public function get_cache($key) { 
        return apc_fetch($key); 
    
       
    /**
     * Apc缓存-清除一个缓存
     * 从memcache中删除一条缓存
     * @param  string $key   KEY值
     */ 
    public function clear($key) { 
        return apc_delete($key); 
    
       
    /**
     * Apc缓存-清空所有缓存
     * 不建议使用该功能
     * @return
     */ 
    public function clear_all() { 
        apc_clear_cache('user'); //清除用户缓存 
        return apc_clear_cache(); //清楚缓存 
    
       
    /**
     * 检查APC缓存是否存在
     * @param  string $key   KEY值
     */ 
    public function exists($key) { 
        return apc_exists($key); 
    
       
    /**
     * 字段自增-用于记数
     * @param string $key  KEY值
     * @param int    $step 新增的step值
     */ 
    public function inc($key, $step) { 
        return apc_inc($key, (int) $step); 
    
       
    /**
     * 字段自减-用于记数
     * @param string $key  KEY值
     * @param int    $step 新增的step值
     */ 
    public function dec($key, $step) { 
        return apc_dec($key, (int) $step); 
    
       
    /**
     * 返回APC缓存信息
     */ 
    public function info() { 
        return apc_cache_info(); 
    
05-11 14:42