PHP缓存策略有哪些

wen PHP项目 2

本文目录导读:

PHP缓存策略有哪些

  1. 第一类:PHP 代码层面(字节码缓存)
  2. 第二类:应用数据缓存(业务逻辑层)
  3. 第三类:HTTP 客户端缓存(浏览器层)
  4. 第四类:页面级缓存(全页/片段缓存)
  5. 第五类:数据库级缓存(底层优化)
  6. 实际项目中的综合策略(最佳实践)
  7. 核心代码示例(Redis + 防击穿)
  8. 总结与建议

PHP 缓存策略是一个非常广泛的话题,涵盖了从代码层面应用层面,再到服务器/数据库层面的多个维度。

根据缓存的数据位置和作用域,我将其分为五大类,并附上具体的实现建议:


第一类:PHP 代码层面(字节码缓存)

这是最基础、见效最快的缓存,主要用于解决 PHP 脚本每次请求都需要重新编译的问题。

  • OPcache(推荐)
    • 原理:PHP 是解释型语言,每次请求都需要将 .php 文件编译成字节码再执行,OPcache 将编译后的字节码存储在共享内存中,下次请求直接读取,省去编译时间。
    • 配置建议opcache.enable=1opcache.memory_consumption=128opcache.max_accelerated_files=10000
    • 说明:这是 PHP 7+ 后的标配,必须开启

第二类:应用数据缓存(业务逻辑层)

这是开发中最常接触的,用于缓存数据库查询结果、API 调用结果或复杂计算的结果。

文件缓存(File Cache)

  • 实现:将数据序列化后写入 .php.txt 文件,读取时通过 file_get_contentsunserialize 获取。
  • 优点:无需安装额外扩展,部署简单。
  • 缺点:I/O 开销大,不适合高并发分布式环境。
  • 适用:单机小项目,或存储配置信息(如 Laravel 的配置缓存 config:cache)。

内存缓存(Memcached / Redis)

这是当前主流的高性能方案。

  • Memcached
    • 特点:纯内存、简单、速度快(但数据类型单一,仅支持字符串)。
    • 适用:用于 Session 共享、简单的数据对象缓存。
  • Redis(推荐)
    • 特点:支持丰富的数据结构(String、Hash、List、Set、Sorted Set),支持数据持久化(RDB/AOF),支持分布式锁发布订阅
    • 适用:复杂业务缓存、排行榜、计数器、队列。
  • 框架集成:Laravel、Symfony 等框架都内置了 Cache 门面,可以快速切换驱动。

第三类:HTTP 客户端缓存(浏览器层)

这是为了减少服务器压力,加快用户端加载速度。

  • HTTP 头信息控制
    • 通过 Cache-ControlExpires 设置浏览器缓存静态资源(图片、CSS、JS)。
    • ETag / Last-Modified:用于条件请求(If-None-Match),如果资源未修改,服务器返回 304 Not Modified,不传输响应体。
  • CDN 缓存:将静态资源分发到边缘节点,用户就近获取。
  • PHP 中的应用
    • 对于动态生成的页面,如果数据变化不频繁,可以设置 Cache-Control: max-age=3600,让浏览器或 CDN 缓存页面。

第四类:页面级缓存(全页/片段缓存)

如果页面不是实时交互的,可以考虑整体缓存输出。

  • 全页静态化(输出缓冲)
    • 使用 PHP 的 ob_start() 将页面内容缓冲,然后写入 .html 文件,下次请求直接读取 HTML 文件,跳过 PHP 执行。
    • 示例
      if (file_exists($cache_file) && (time() - filemtime($cache_file) < 3600)) {
          include $cache_file; // 直接输出静态文件
          exit;
      }
      ob_start();
      // ... PHP 业务逻辑 ...
      $html = ob_get_contents();
      file_put_contents($cache_file, $html);
      ob_end_flush();
  • Edge Side Includes(ESI)或片段缓存
    • 如 Laravel 的 Blade 模板引擎支持 @cache 指令,将模板中的部分区块(如侧边栏)缓存,而核心内容动态更新。

第五类:数据库级缓存(底层优化)

虽然不属于 PHP 直接操作,但对 PHP 性能影响巨大。

  • MySQL 查询缓存

    注意:MySQL 8.0 已移除该功能,不推荐依赖。

  • SQL 语句预处理与索引

    这是最根本的缓存逻辑,减少昂贵的 Join 查询。

  • 慢查询日志与缓存联动
    • 将复杂查询的结果存入 Redis,$hot_data = Redis::get('complex_query_key') ?: DB::select(...)

实际项目中的综合策略(最佳实践)

以一个高并发 API 项目为例,推荐的“缓存金字塔”策略是:

  1. 第一层(最快):OPcache —— 确保 PHP 代码本身执行快。
  2. 第二层(业务):Redis —— 针对热点数据,设置 TTL(过期时间) 防止缓存雪崩。
    • 缓存穿透:查询空值也缓存,或使用布隆过滤器。
    • 缓存击穿:使用互斥锁(SETNX)重构缓存。
    • 缓存雪崩:给 TTL 加随机值,防止同一时段大面积失效。
  3. 第三层(网络):CDN —— 对于静态资源,直接由 CDN 拦截,根本不算 PHP 进程。
  4. 第四层(协议):HTTP 缓存 —— 强制浏览器复用缓存,减少请求数。

核心代码示例(Redis + 防击穿)

function getProductInfo($id) {
    $cacheKey = "product:{$id}";
    // 1. 尝试从 Redis 获取
    $data = Redis::get($cacheKey);
    if ($data !== false) {
        return unserialize($data);
    }
    // 2. 缓存不存在,尝试获取锁(防止缓存击穿)
    $lockKey = "lock:" . $cacheKey;
    if (Redis::set($lockKey, 1, ['nx', 'ex' => 10])) {
        try {
            // 3. 查数据库
            $product = DB::table('products')->where('id', $id)->first();
            if ($product) {
                // 4. 写缓存,设置过期时间
                Redis::setex($cacheKey, 3600, serialize($product));
            } else {
                // 5. 空值缓存,防止穿透(设置较短过期时间)
                Redis::setex($cacheKey, 60, serialize(null));
            }
            return $product;
        } finally {
            // 6. 释放锁
            Redis::del($lockKey);
        }
    } else {
        // 其他请求等待或递归重试
        usleep(50000); // 等待 50ms
        return getProductInfo($id); // 递归重试
    }
}

总结与建议

策略类型 技术方案 效率 复杂度 适用场景
代码缓存 OPcache ⭐⭐⭐⭐⭐ 低(配置即可) 所有生产环境必开
数据缓存 Redis / Memcached ⭐⭐⭐⭐ 热点数据、Session、接口加速
页面缓存 ob_start / 静态化 ⭐⭐⭐⭐⭐ 首页、活动页、不常变化的页面
HTTP缓存 Cache-Control / CDN ⭐⭐⭐⭐⭐ 静态资源(CSS/JS/图片)
数据库缓存 MySQL Query Cache(旧) 一般 已过时,推荐交给中间件处理

最核心的三大原则:

  1. 能开OPcache就开(基本零成本)。
  2. 优先用Redis做业务层缓存(灵活可控)。
  3. 不要存“永久”,一定要设 TTL(长期运行时不至于内存爆炸)。

抱歉,评论功能暂时关闭!