PHP怎样用APCu缓存进程内数据_APCu进程缓存法【轻量】

12次阅读

apcu 是 php 进程内用户数据缓存扩展,不跨进程、不持久、不支持集群;它是 apc 的精简版,仅保留用户缓存功能,移除字节码缓存(由 opcache 承担),php 7+ 需单独安装并启用,常因配置遗漏或进程隔离导致缓存不生效。

PHP 怎样用 APCu 缓存进程内数据_APCu 进程缓存法【轻量】

APCu 是 PHP 进程内缓存的轻量级首选,但它不跨进程、不持久、不支持集群——用对场景才能真正“轻量”。

APCu 和 APC、OPcache 到底什么关系?

APCu 是 APC 的“缓存模块精简版”:只保留 apcu_store() / apcu_fetch() 等用户数据缓存功能,移除了已由 OPcache 承担的字节码缓存部分。PHP 7+ 不再内置 APC,apcu 扩展需单独安装(如 apt install php-apcu),且必须启用 extension=apcu.so;OPcache 默认开启,但和 APCu 互不干扰。

常见错误现象:Call to undefined function apcu_fetch() —— 检查是否漏装扩展,或 CLI 和 FPM 的 php.ini 配置不一致(尤其 Docker 或多版本共存环境)。

怎么安全地写入和读取 APCu 缓存?

APCu 的 key 是字符串,值支持大多数 PHP 类型(含数组、对象),但序列化 / 反序列化由扩展自动处理,无需手动调用 serialize()

立即学习 PHP 免费学习笔记(深入)”;

  • apcu_store($key, $value, $ttl):$ttl 单位为秒,0 表示永不过期(但受内存限制,实际可能被 LRU 清理)
  • apcu_fetch($key) 返回 false 表示未命中(注意不是 null),建议用 !== false 判断
  • 并发写入无原子锁,若需“先读后写”,应改用 apcu_add()(仅当 key 不存在时写入)或加应用层锁

示例:

if (($data = apcu_fetch('user_123')) === false) {$data = getUserFromDb(123); // 实际查询     apcu_store('user_123', $data, 300); // 缓存 5 分钟 }

为什么本地开发能用,上线后缓存总不生效?

核心原因:APCu 数据 ** 不跨 PHP 进程 **。FPM 下每个 worker 是独立进程,CLI 脚本也完全隔离。这意味着:

  • Web 请求写入的缓存,另一个请求可能读不到(如果落在不同 worker)——这不是 bug,是设计如此
  • CLI 命令(如 cron)无法共享 Web 请求的缓存,反之亦然
  • 重启 PHP-FPM 或 Apache/Nginx 后,所有 APCu 数据清空

典型误用场景:用 APCu 存“全局开关”或“计数器”,结果各进程各自为政。这类需求应换 Redis 或数据库。

怎么调优 APCu 内存和清理行为?

默认 32MB(apc.shm_size=32M)通常够用,但需根据缓存对象大小和数量调整。关键配置项:

  • apc.enabled=1:必须开启(CLI 下默认关闭,需显式设为 1)
  • apc.shm_size:建议按预估总量 × 1.5 设置,避免频繁 LRU 驱逐
  • apc.ttlapc.user_ttl:控制默认过期时间,但建议代码中显式传 $ttl 更可控
  • apc.slam_defense=0:禁用“雪崩防御”(旧版有,新版默认关),避免高并发下批量失效

监控命令:apcu_cache_info() 查当前使用量、命中率;apcu_clear_cache('user') 仅清用户缓存(慎用,会清空全部)。

容易被忽略的一点:APCu 的 LRU 清理不保证及时性——内存满时才触发,且只清理过期项或最久未用项。如果缓存大量长 TTL 数据,又突然写入大批新数据,旧数据可能意外残留很久。

text=ZqhQzanResources