🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
APCU的前身是APC,APC的主要用途有两项: 1. 将PHP代码编译之后所产生的bytecode暂存在共享内存内供重复使用,以提升应用的运行效率。(Opcode Cache) 2. 提供用户数据缓存功能。(User Data Cache) 其中第一点是其主要功能,因为PHP的运行机制——每次接受一个请求时都要初始化所有的资源(将源代码转换成Opcode(即001011机器操作吗),……),执行代码,然后释放资源;所以启用Opcache Cache后,在第一次请求时将编译后的机器操作码暂存在共享内存内供重复使用,这样就可以在初始化资源阶段减少CPU和内存的消耗。 但是PHP从PHP 5.5开始,使用ZendOptimizerPlus(更名为Opcache)作为内置的Opcode Cache实现。所以现在APCU的主要功能便不再有意义了,而且其官方也随后表示不再维护APC了。 虽然apc可以通过关闭Opcache Cache而只使用用户数据缓存功能但是APC的User Data Cache使用的存储机制是和Opcode Cache一样的, 这样的场景要求数据严格正确, 所以锁会比较多,因此APCU作为缓存用户数据的扩展被启用。 他的作用和redis和memcached重合,测试表明, APC的User Data Cache的效率和本地memcached几乎相当(在单机性能上,APCu通常比Memcached更高。memcached本身的设计就是为了分布式应用,大规模内存缓存,集群,易扩展等,如果只有一台服务器且内存足够缓存用户数据时推荐apcu) APCU缓存和memcahce/redis不一样的地方。你通过memcache/redis存储一个数据,在缓存有效期内,同一机器上的不同的PHP进程(FPM+CLI)都是能够取到这份数据的。 对的,注意关键字 “同一机器上的不同的PHP进程”,对于APCU而言,PHP-FPM(PHP5.3.3+)模式下所有的php-fpm进程(即使是不同的pool)属于同一个父进程,所以是可以共享缓存数据的;但是cli(命令行)模式每次都是单独一个全新进程,因而和php-fpm模式的进程是不能共享缓存数据的。所以如果你的业务场景需要在cli和php-fpm两种模式下共享数据一定要小心了,可能memcache或者redis才是你更好的选择 **APCu 配置选项** | 名字 | 默认 | 可修改范围 | 说明| | --- | --- | --- | --- | | apc.enabled | "1" | PHP\_INI\_SYSTEM | 启用缓存扩展  | | apc.shm_segments | "1" | PHP\_INI\_SYSTEM | 分配**共享内存块**的数量(建议值为1)  | | apc.shm_size | "32M" | PHP\_INI\_SYSTEM |  设置每个**共享内存块**的大小(以MB为单位,建议值为128~256) | | apc.entries_hint | "4096" | PHP\_INI\_SYSTEM |  关于可能存储的不同变量的数量“提示”。如果不确定,设置为零或省略 | | apc.ttl | "0" | PHP\_INI\_SYSTEM |  设置缓存超时时间,单位是秒。0表示永不超时。建议值为7200~36000。 | | apc.gc_ttl | "3600" | PHP_INI_SYSTEM |  缓存条目在垃圾回收表中能够存在的秒数,此值提供了一个安全措施,即使一个服务器进程在执行缓存的源文件时崩溃,而且该源文件已经被修改,为旧版本分配的内存也不会被回收,直到达到此ttl值为止,设置为0禁用此功能 | | apc.mmap_file_mask | NULL | PHP_INI_SYSTEM | 如果在安装模块时使用–enable-mmap(默认启用)为apc编译了mmap(映射)支持,<br>这里的值就是传递给mmap模块的mktemp风格的文件掩码(建议值为"/tmp/apc.xxxxxx"),以确定内存映射区域是文件支持的还是共享内存支持的。<br>对于直接文件支持的内存映射,将它设置为/tmp/apc。XXXXXX(正好6x)。<br>要使用posix风格的shm_open/mmap就需要设置成"/apc.shm.xxxxxx"的样子。例如/ apc.shm。<br>您还可以将它设置为/dev/zero,以使用内核的/dev/zero接口来访问匿名映射的内存。<br>不定义它将强制生成一个匿名的mmap(映射)。<br>它将只使用一个内存段,这与使用多个内存段的SHM (SysV共享内存)支持构建APCu不同。MMAP不像/proc/sys/kernel/ shmmaxde那样有最大限制。一般来说,MMAP支持是被推荐的,因为它将在重新启动web服务器时更快地回收内存,并且总而言之,在启动时减少了内存分配的影响。 | | apc.slam_defense | "1" | PHP_INI_SYSTEM |  在非常繁忙的服务器上,无论是启动服务还是修改文件,都可能由于多个进程企图同时缓存一个文件而导致竞争条件。这个指令用于设置进程在处理未被缓存的文件时跳过缓存步骤的百分率。比如设为75表示在遇到未被缓存的文件时有75%的概率不进行缓存,从而减少碰撞几率。设为 0 禁用这个特性。 | | apc.enable_cli | "0" | PHP_INI_SYSTEM | 主要用于测试和调试,通过设置此选项,可以为cli版本的php启用apc功能。在正常情况下,在每个CLI请求上创建、填充和销毁APC缓存并不理想,但是对于各种测试场景,能够轻松地为CLI版本的PHP启用APC是很有用的  | | apc.use_request_time | "1" | PHP_INI_ALL | 为生存时间TTL使用SAPI请求启动时间  | | apc.serializer | "default" | PHP_INI_SYSTEM |  用于配置APC以使用第三方序列化程序 | | apc.coredump_unmap | "0" | PHP_INI_SYSTEM |  启用APC的信号句柄,例如SIGSEGV信号,当信号写入核心文件。当这些信号被接收,APC将试图取消映射的共享内存段,从核心文件中排除它。此设置可以提高系统的稳定性,当接受到致命的信号或者采用APC的大型共享内存段配置方式<br>此功能是潜在的危险。如果发生致命错误取消映射一个共享内存段致命的信号句柄, 可能会导致不可预知的结果 <br>虽然有些内核可能会提供了便利,忽略各类共享内存时生成核心转储文件,这些实现可能也忽略了重要的共享内存段,比如 Apache scoreboard| | apc.preload_path | NULL | PHP_INI_SYSTEM | 可选地,设置APC将在启动时加载缓存数据的目录的路径  | 如果APCu在工作,那么缓存的全计数号(在左边)将显示缓存达到最大容量的次数,并且必须强制清除上一个apc中没有访问的任何条目 ``` //修改php.ini加入如下内容[请根据环境自行调整]: extension= "apcu.so" ; ;开启功能 apc.enabled= 1 ;为编译器缓冲区分配的共享内存块数量(建议值为1)。 apc.shm_segments= 1 ;每个共享内存块的大小(以MB为单位,建议值为128~256)。 apc.shm_size= 128M ;优化级别(建议值为0 );正整数值表示启用优化器,值越高则使用越激进的优化。 apc.optimization= 0 ;Web服务器上可能被包含或被请求的不同源文件的大致数量(建议值为1024~4096)。如果不能确定,则设为0。 apc.num_files_hint= 0 ;缓冲区中超时时间,单位是秒。0表示永不超时。建议值为7200~36000。 apc.ttl= 0 ;缓存条目在垃圾回收表中超时秒数。 apc.gc_ttl= 3600 //配置变更后,需重启httpd或者php-fpm服务。 ``` ## **函数:** **增** `apcu_add( string $key , mixed $var [, int $ttl = 0 ] ) bool -在数据存储中缓存一个新变量,变量以存在则不会被设置` ``` $bar = 'BAR'; apcu_add('foo', $bar); var_dump(apcu_fetch('foo')); //BAR $bar = 'NEVER GETS SET'; apcu_add('foo', $bar,0); var_dump(apcu_fetch('foo'));//BAR ``` `apcu_add( array $values [, mixed $unused = NULL [, int $ttl = 0 ]] ) : array -在数据存储中缓存多个新变量,变量以存在则不会被设置` ``` apcu_add(['foo'=>'BAR','tool'=>'BBT']); apcu_add(['foo'=>'BAR','tool'=>'BBT'],null,0); ``` `apcu_store -在数据存储中缓存一个变量 用法同apcu_add,区别就是他会覆盖存在的缓存变量` ***** **查** `apcu_fetch( mixed $key [, bool &$success ] ) : mixed - 从缓存中获取已存储的变量` ``` $bar = 'BAR'; apcu_store('foo', $bar); var_dump(apcu_fetch('foo'));//BAR ``` ***** **改** `apcu_cas( string $key , int $old , int $new ) : bool - 用新值更新旧值` ``` apcu_store('foobar', 2); apcu_cas('foobar', 2, 1) ``` `apcu_dec( string $key [, int $step = 1 [, bool &$success [, int $ttl = 0 ]]] ) -减少存储的值(递减,必须数值型)` ``` apcu_store('anumber', 42); echo apcu_dec('anumber'), PHP_EOL; echo apcu_dec('anumber', 10), PHP_EOL; echo apcu_dec('anumber', 10, $success), PHP_EOL; ``` `apcu_inc增加存储的值(递增,必须数值型)` ``` apcu_store('anumber', 42); echo apcu_inc('anumber'), PHP_EOL; echo apcu_inc('anumber', 10), PHP_EOL; echo apcu_inc('anumber', 10, $success), PHP_EOL; ``` ***** **删** `apcu_delete( mixed $key ) : mixed -删除存储变量从缓存` ``` $bar = 'BAR'; apcu_store('foo', $bar); apcu_delete('foo'); //删除多个 apcu_delete(['foo', 'bar', 'baz']); ``` `apcu_clear_cache() -清除APCu缓存 成功返回true` `apcu_enabled() — APCu在当前环境中是否可用 返回bool` `apcu_exists( mixed $keys ) : mixed -检查某个变量是否被缓存` ``` $fruit = 'apple'; apcu_store('foo', $fruit); if (apcu_exists('foo')) { echo "Foo exists: "; echo apcu_fetch('foo'); } else { echo "Foo does not exist"; } ``` `apcu_entry( string $key , callable $generator [, int $ttl = 0 ] ) : mixed -自动读取或生成一个缓存条目` ``` $config = apcu_entry("config", function($key) { return [ "fruit" => apcu_entry("config.fruit", function($key){ return [ "apples", "pears" ]; }), "people" => apcu_entry("config.people", function($key){ return [ "bob", "joe", "niki" ]; }) ]; }); var_dump($config); //以上例程会输出: array(2) { ["fruit"]=> array(2) { [0]=> string(6) "apples" [1]=> string(5) "pears" } ["people"]=> array(3) { [0]=> string(3) "bob" [1]=> string(3) "joe" [2]=> string(4) "niki" } } ``` `apcu_sma_info([ bool $limited = FALSE ] ) : array -检索APCu共享内存分配信息` ``` print_r(apcu_sma_info()); //以上例程的输出类似于: Array ( [num_seg] => 1 [seg_size] => 31457280 [avail_mem] => 31448408 [block_lists] => Array ( [0] => Array ( [0] => Array ( [size] => 31448408 [offset] => 8864 ) ) ) ) ``` `apcu_cache_info([ bool $limited = FALSE ] ) -从APC的数据存储中检索缓存的信息和元数据  ` 如果limited为真,则返回值将排除缓存项的单个列表。这在尝试优化统计信息收集调用时非常有用 ``` print_r(apcu_cache_info()); 结果: Array ( [num_slots] => 2000 [ttl] => 0 [num_hits] => 9 [num_misses] => 3 [start_time] => 1123958803 [cache_list] => Array ( [0] => Array ( [filename] => /path/to/apcu_test.php [device] => 29954 [inode] => 1130511 [type] => file [num_hits] => 1 [mtime] => 1123960686 [creation_time] => 1123960696 [deletion_time] => 0 [access_time] => 1123962864 [ref_count] => 1 [mem_size] => 677 ) [1] => Array (...iterates for each cached file) ) ``` 注意:php-cli模式运行不能保存到下次运行(即命令行执行时,缓存无效) 在FastCGI模式下重启后将会清除缓存 ## **APCUIterator类** ``` APCUIterator implements Iterator { public __construct ([ mixed $search = NULL [, int $format = APC_ITER_ALL [, int $chunk_size = 100 [, int $list = APC_LIST_ACTIVE ]]]] ) public current ( void ) : mixed - 得到当前项 public getTotalCount ( void ) : int - 得到总数 public getTotalHits ( void ) : int - 获取缓存总命中数 public getTotalSize ( void ) : int - 获取总缓存大小 public key ( void ) : string - 得到迭代器关键字 public next ( void ) : bool - 移动指针到下一项 public rewind ( void ) : void - 复原指针到初始位置 public valid ( void ) : bool - 检查当前位置是否有效 } ```