APCu 是 PHP 版的内存键值存储。 键是 string 类型且值可以为 PHP 任何变量。 APCu 仅支持用户空间(userland)级别的变量缓存。
在PHP5版本用的是APC,PHP7之后就是APCU.它俩是同一东西.在php.ini的配置项中都以apc开头.
APCu 是去除了操作码缓存的 APC。(也就是去掉了opcode缓存,保留了key/value的用户级缓存)
第一个 APCu 代码库版本是 v4.0.0,是在那时从 APC master 分支中 fork 出来的。 APCu v5.0.0 起提供 PHP 7 支持。自 APCu v5.1.19 起提供 PHP 8 支持。
扩展下载地址: http://pecl.php.net/package/APCu
APCu 的安装就和普通的 PHP 扩展一样,非常简单,最主要的是这个扩展还非常的小。不管下载还是安装都是秒级可以完成的。所以说能够非常方便的应用于小规模的项目,而且是 PHP 原生支持的,不需要额外的端口之类的配置。
不过只支持FastCGI模式.PHP-CLI下会达不到预期的效果.需要注意!(如果是常驻内存的PHP程序,比如swoole另有一套自带组件 高性能共享内存 Table)
apcu是基于共享内存技术建设的,多个cgi之间访问apcu中的cache可以完全等同于访问自己进程的一块内存一样,不需要发任何的网络请求。而不管是redis、mysql或者其他的独立服务的cache都需要发网络请求,即使存储和服务部署在同一机器上也仍然需要采用本地sock进行网络请求,何况在虚拟化的趋势下,这些存储服务一定是独立运行的。按照计算机存储器层次结构的理论,访问内存的速度大概在纳秒级别 ,网络请求的速度在毫秒级别,同机架或者同机房的机器可能在1/10ms左右,还不考虑服务稳定性的情况下。
但是APCu在实际的使用中还是存在一定的局限性:
- 以扩展的方式接入,跟php这门语言有很强的耦合,而redis作为独立服务存在,使用协议接入
- apcu受限于单机内存的限制,扩展受阻,而目前的redis集群模式已经可以做到动态扩容,理论上无容量风险
- apcu数据存于单机内存,多机器之间的数据无法共享,这是他使用场景有限的最大阻碍
所以,我再使用场景中一般用apcu来缓存数据量小、但是读取量大或者瞬间读取量大的场景。
缓存系统一般都会有的增加、删除、查询、自增等功能都在 APCu 扩展中有对应的实现。具体的内容大家可以查看PHP官方手册。
- apcu_add — 创建一个新的缓存
- apcu_cache_info — 查看 APCu 的全部缓存信息
- apcu_cas — 更新一个缓存的值为新值
- apcu_clear_cache — 清除全部的缓存
- apcu_dec — 自减缓存值
- apcu_delete — 删除一个缓存的内容
- apcu_enabled — 当前环境下是否启用 APCu 缓存
- apcu_entry — 原子地生成一个缓存实体
- apcu_exists — 检查缓存是否存在
- apcu_fetch — 查询缓存
- apcu_inc — 自增缓存值
- apcu_sma_info — 查询缓存的共享内存信息
- apcu_store — 保存一个缓存
正常的使用都是比较简单的,我们添加各种类型的数据都可以正常存入缓存。不过需要注意的是,我们可以直接保存对象进入 APCu 缓存中,不需要将它序列化或者JSON成字符串,系统会自动帮我们序列化。
apcu_add(string \key , mixedkey,mixedvar [, int ttl = 0 ]) 方法就是普通的添加一个缓存,ttl=0])方法就是普通的添加一个缓存,ttl 可以设置过期时间,也是以秒为单位,如果不设置就是长期有效的。注意,APCu 的缓存时限在一次 CLI 中有效,再调用一次 CLI 取不到上次 CLI 中设置的缓存内容。而在 PHP-FPM 中,重启 PHP-FPM 或 FastCGI 之后缓存会失效。
apcu_cas(string $key , int $old , int $new) 是将一个 $old 值修改为 $new 值,它只能修改数字类型的内容,如果是字符串的修改会报错。这个函数有什么优势呢?它最大的优势是原子性的,也就是不受高并发的影响。与之类似的是 apcu_store(string $key , mixed $var [, int $ttl = 0 ]) 方法,不过这个方法只是简单的修改一个缓存的内容,如果这个缓存的键不存在的话,就新建一个,它不受类型的限制,当然也不具有原子性。
apcu_entry(string $key , callable $generator [, int $ttl = 0 ]) 这个函数的作用是如果 $key 这个缓存不存在,则执行 $generator 这个匿名函数,并将 $key 做为键值传递进去,然后生成也就是 return 一个内容做为这个缓存的值。
当缓存中的数据非常多时,它还提供了一个 APCUIterator 迭代器方便我们进行缓存信息的循环查询及相关统计。总之,这一套系统是非常方便的一套小规模的缓存系统,在日常开发中完全可以尝试用到一些小功能上。