一聚教程网:一个值得你收藏的教程网站

热门教程

ThinkPHP 5.1 利用 APCu 缓存热点数据降低 DB 压力扩展

时间:2026-07-27 08:05:47 编辑:袖梨 来源:一聚教程网

APCu是ThinkPHP 5.1单机部署下缓存用户配置、地区字典等低频数据的最优方案,需安装扩展、配置store、封装两级读取逻辑,并同步清理两级缓存以保证一致性。

ThinkPHP 5.1 应用中频繁读取用户配置、站点开关、地区字典等不变或低频变更数据时,每次请求都查数据库会迅速拖慢响应、耗尽 MySQL 连接数;APCu 作为进程内内存缓存,能直接拦截这些重复读取,0 网络开销、微秒级返回,是单机部署下最轻量高效的热点数据缓存方案。

启用 APCu 扩展并验证加载状态

执行 sudo apt install php-apcu(Ubuntu/Debian)或 sudo yum install php-apcu(CentOS),安装后重启 PHP-FPM 服务: sudo systemctl restart php-fpm

运行 php -m | grep apcu,若输出 apcu 则说明扩展已启用;若无输出,检查 /etc/php/*/mods-available/apcu.ini 是否存在且未被注释,确认其中包含 extension=apcu.so

【必须关闭 apcu.enable_cli=0】 否则命令行环境(如 artisan 命令、crontab 脚本)会误用 APCu 导致缓存不可见,而 Web 请求正常——这种不一致极易引发调试困惑。

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

在 cache.php 中配置 APCu 驱动

打开 config/cache.php,在 'stores' 数组内新增 'apcu' 配置项:

'apcu' => [
  'type' => 'apcu',
  'prefix' => 'tp5_apcu_',
  'expire' => 3600,
],

注意:不要修改 'default' 键值,保留其为 'file''redis';APCu 仅作为辅助驱动按需调用,避免全局切换导致标签等功能失效。

配置中的 prefix 必须显式指定,否则不同模块缓存键可能冲突——例如 get('status') 在用户模块和系统模块中会被写入同一 key。

封装两级缓存读取逻辑

第一步:定义统一读取函数,优先查 APCu,未命中再查 Redis,最后 fallback 至数据库:

function getHotConfig($key, $ttl = 3600) {
  $value = thinkCache::store('apcu')->get($key);
  if ($value !== false) return $value;
  $value = thinkCache::store('redis')->get($key);
  if ($value !== false) {
    thinkCache::store('apcu')->set($key, $value, $ttl);
    return $value;
  }
  $value = db('sys_config')->where('k', $key)->value('v');
  if ($value !== null) {
    thinkCache::store('redis')->set($key, $value, $ttl);
    thinkCache::store('apcu')->set($key, $value, $ttl);
  }
  return $value;
}

第二步:在控制器中调用 getHotConfig('site_open') 即可,无需关心底层哪一层命中。

第三步:对更新操作,必须同步清理两级缓存——先 thinkCache::store('apcu')->rm('site_open'),再 thinkCache::store('redis')->set('site_open', $newVal, 3600)。只清 Redis 不清 APCu,下次请求仍会从本地内存返回旧值。

规避 APCu 缓存穿透与空值陷阱

方法一:对数据库查无结果的 key,不存 null,改存占位符字符串 '__APCU_EMPTY__' 并设短 TTL(如 60 秒):

if ($dbResult === null) {
  thinkCache::store('apcu')->set($key, '__APCU_EMPTY__', 60);
  return false;
}

方法二:读取时显式判断 if ($val === '__APCU_EMPTY__') return false;,避免业务层把字符串当有效数据处理。

APCu 不支持缓存标签(tag),Cache::tag('config')->clear() 对 APCu 驱动完全无效——该操作只会清空 file 或 redis 驱动下的对应标签,APCu 层仍残留旧数据,务必手动逐 key 清理或全量 apcu_clear_cache()(慎用,影响全站)。

热门栏目