本文目录导读:

- 第一类:PHP 代码层面(字节码缓存)
- 第二类:应用数据缓存(业务逻辑层)
- 第三类:HTTP 客户端缓存(浏览器层)
- 第四类:页面级缓存(全页/片段缓存)
- 第五类:数据库级缓存(底层优化)
- 实际项目中的综合策略(最佳实践)
- 核心代码示例(Redis + 防击穿)
- 总结与建议
PHP 缓存策略是一个非常广泛的话题,涵盖了从代码层面到应用层面,再到服务器/数据库层面的多个维度。
根据缓存的数据位置和作用域,我将其分为五大类,并附上具体的实现建议:
第一类:PHP 代码层面(字节码缓存)
这是最基础、见效最快的缓存,主要用于解决 PHP 脚本每次请求都需要重新编译的问题。
- OPcache(推荐):
- 原理:PHP 是解释型语言,每次请求都需要将
.php文件编译成字节码再执行,OPcache 将编译后的字节码存储在共享内存中,下次请求直接读取,省去编译时间。 - 配置建议:
opcache.enable=1,opcache.memory_consumption=128,opcache.max_accelerated_files=10000。 - 说明:这是 PHP 7+ 后的标配,必须开启。
- 原理:PHP 是解释型语言,每次请求都需要将
第二类:应用数据缓存(业务逻辑层)
这是开发中最常接触的,用于缓存数据库查询结果、API 调用结果或复杂计算的结果。
文件缓存(File Cache)
- 实现:将数据序列化后写入
.php或.txt文件,读取时通过file_get_contents和unserialize获取。 - 优点:无需安装额外扩展,部署简单。
- 缺点:I/O 开销大,不适合高并发分布式环境。
- 适用:单机小项目,或存储配置信息(如 Laravel 的配置缓存
config:cache)。
内存缓存(Memcached / Redis)
这是当前主流的高性能方案。
- Memcached:
- 特点:纯内存、简单、速度快(但数据类型单一,仅支持字符串)。
- 适用:用于 Session 共享、简单的数据对象缓存。
- Redis(推荐):
- 特点:支持丰富的数据结构(String、Hash、List、Set、Sorted Set),支持数据持久化(RDB/AOF),支持分布式锁和发布订阅。
- 适用:复杂业务缓存、排行榜、计数器、队列。
- 框架集成:Laravel、Symfony 等框架都内置了 Cache 门面,可以快速切换驱动。
第三类:HTTP 客户端缓存(浏览器层)
这是为了减少服务器压力,加快用户端加载速度。
- HTTP 头信息控制:
- 通过
Cache-Control和Expires设置浏览器缓存静态资源(图片、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();
- 使用 PHP 的
- Edge Side Includes(ESI)或片段缓存:
- 如 Laravel 的
Blade模板引擎支持@cache指令,将模板中的部分区块(如侧边栏)缓存,而核心内容动态更新。
- 如 Laravel 的
第五类:数据库级缓存(底层优化)
虽然不属于 PHP 直接操作,但对 PHP 性能影响巨大。
- MySQL 查询缓存:
注意:MySQL 8.0 已移除该功能,不推荐依赖。
- SQL 语句预处理与索引:
这是最根本的缓存逻辑,减少昂贵的 Join 查询。
- 慢查询日志与缓存联动:
- 将复杂查询的结果存入 Redis,
$hot_data = Redis::get('complex_query_key') ?: DB::select(...)。
- 将复杂查询的结果存入 Redis,
实际项目中的综合策略(最佳实践)
以一个高并发 API 项目为例,推荐的“缓存金字塔”策略是:
- 第一层(最快):OPcache —— 确保 PHP 代码本身执行快。
- 第二层(业务):Redis —— 针对热点数据,设置
TTL(过期时间)防止缓存雪崩。- 缓存穿透:查询空值也缓存,或使用布隆过滤器。
- 缓存击穿:使用互斥锁(
SETNX)重构缓存。 - 缓存雪崩:给 TTL 加随机值,防止同一时段大面积失效。
- 第三层(网络):CDN —— 对于静态资源,直接由 CDN 拦截,根本不算 PHP 进程。
- 第四层(协议):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(旧) | 一般 | 高 | 已过时,推荐交给中间件处理 |
最核心的三大原则:
- 能开OPcache就开(基本零成本)。
- 优先用Redis做业务层缓存(灵活可控)。
- 不要存“永久”,一定要设 TTL(长期运行时不至于内存爆炸)。