本文目录导读:

在 PHP 项目中选择缓存策略,核心原则是按数据特征分层、按读写比例选择介质,不存在“万能药”,需要根据数据的变化频率、访问频率和一致性要求来决定。
以下是选择缓存策略的完整决策指南:
第一步:明确缓存分层(由快到慢)
PHP 缓存通常分为四个层级,速度递减,容量递增:
- 第一层:进程内缓存(OPcache + 内存变量)
- PHP OPcache:缓存编译后的字节码,必开,这是性价比最高的优化,能提升 30%-50% 的 CPU 开销。
- 运行时内存(如
apcu):缓存热点数据,如配置项、语言包,速度最快(纳秒级),但单机内存有限,且不跨进程同步。
- 第二层:本地集中式缓存(Redis/Memcached/Tair)
- Redis:首选,支持丰富的数据结构(String、Hash、List、Set、ZSet),支持持久化和过期策略。
- Memcached:纯 KV 存储,内存利用率极高,适合存简单字符串,但无法持久化。
- 第三层:数据库查询缓存 / 物化视图
针对复杂的 SQL 查询,将查询结果缓存在 Redis 中(手动实现),或者利用 MySQL 的 Query Cache(8.0 已废弃,不建议依赖)。
- 第四层:HTTP 缓存(CDN + 浏览器)
- 针对静态资源(CSS/JS/图片)和页面片段,通过 HTTP 头(
Cache-Control、ETag)交给 Nginx 或 CDN 缓存,甚至直接在浏览器端缓存。
- 针对静态资源(CSS/JS/图片)和页面片段,通过 HTTP 头(
第二步:按业务场景选择策略(核心决策)
| 业务场景 | 数据特征 | 推荐策略 | 实现要点 |
|---|---|---|---|
| 配置信息 (站点设置、支付参数) |
读多写极少,全局一致 | 进程内缓存 (APCu) | 启动时加载,写入时清空 APCu。 若有多台服务器,用 Redis 兜底。 |
| 用户会话 (Session) | 高频读写,可容忍极短延迟 | Redis / Memcached | 替换默认文件存储,解决多服务器登录状态同步问题。 建议设置 TTL(30分钟)。 |
| 热点新闻/商品详情 | 读多写少,允许短暂延迟 | Redis 全量缓存 + 失效重建 | 调用时取缓存,若不存在则查库并写入。 防击穿:使用互斥锁(Redis SETNX)控制重建过程。 |
| 排行榜 (热门文章、销量) |
写频繁,读密集,实时性要求高 | Redis ZSet(有序集合) | 写入时直接 ZADD 更新分数,读取时 ZREVRANGE 获取前 N 名。无需数据库排序,性能极高。 |
| 计数器 (点赞、浏览量、库存) |
高并发写,不允许超卖 | Redis Lua 脚本 / INCR 原子操作 | 使用 INCR 直接操作 Redis 计数,定期(如每5分钟)异步同步到 MySQL。高并发秒杀需配合 Lua 保证原子性。 |
| 复杂列表/分页 (用户订单列表) |
查询条件多,数据量大 | Redis String/Hash 序列化 + 最近最少使用(LRU)淘汰 | 将 SQL 的 MD5 作为 Key,结果 JSON 序列化存入。 防雪崩:设置随机过期时间(基础 TTL + 随机数)。 |
| 完整 HTML 页面 (整页静态化) |
极端读多写少,内容变化慢 | Redis 存储 HTML 片段 / Nginx 静态文件 | 伪静态化:后台编辑保存时,生成 HTML 存入 Redis 或写文件。 一旦写入,后续 HTTP 请求直接返回,PHP 几乎不参与。 |
| 数据库连接/查询结果 | 查询复杂,耗时较长 | Redis 查询结果缓存 (手动) | 仅缓存高频且结果集小于 1MB 的查询。 必须建立缓存失效机制(删除、更新操作时主动清理相关 Key)。 |
第三步:必须解决的三个缓存难题(陷阱)
如果选择了 Redis 缓存,以下三个问题决定了系统的稳定性:
-
缓存穿透(查询不存在的数据)
- 现象:请求一个不存在的商品 ID,每次都打数据库。
- 方案:
- 空值缓存:缓存一个空对象,TTL 设为 5 分钟。
- 布隆过滤器:启动时加载所有存在的 ID,过滤掉肯定不存在的请求。
-
缓存击穿(热点 Key 失效)
- 现象:某个超级热点 Key(如首页数据)在过期瞬间,大量请求同时打到数据库。
- 方案:
- 互斥锁:进程内判断 Key 不存在时,先加锁(
SET NX EX),只有拿到锁的进程去查库并重建,其他进程等待锁释放后直接读缓存。
- 互斥锁:进程内判断 Key 不存在时,先加锁(
-
缓存雪崩(大量 Key 同时失效)
- 现象:设置的 TTL 相同,导致同一时间大量缓存过期。
- 方案:
- 随机 TTL:
TTL = base_time + random(0, 300)秒。 - 多级缓存:本地进程缓存(APCu) 作为第一级,Redis 作为第二级,即使 Redis 挂了,本地缓存也能扛住流量。
- 随机 TTL:
第四步:技术选型清单(落地参考)
- PHP 8.x + OpCache:确保
opcache.enable=1,并设置合理的opcache.memory_consumption=128。 - Redis 6.0+:
- 存储复杂结构用 Redis(Hash/ZSet)。
- 必须开启持久化(RDB + AOF)。
- 设置
maxmemory-policy allkeys-lru作为兜底策略。
- APCu 拓展:如果服务器内存 > 2GB,建议开启 APCu 用于本地缓存。
- 依赖注入容器:使用 PHP-DI 或 Laravel Container,但不要将缓存容器本身放进容器,以免引起循环依赖。
第五步:监控与调优(用什么来判断好坏)
- 命中率监控:Redis 的
INFO stats查看keyspace_hits和keyspace_misses,命中率低于 80% 说明缓存策略需要优化(可能是 TTL 太短或 Key 设计不合理)。 - Redis 内存峰值:使用
redis-cli --stat监控,内存超过 80% 时应考虑集群扩容。 - 慢日志:开启 Redis 的
slowlog,排查是否有大 Key 操作(如HGETALL大 Hash)。
选择顺序建议
如果你是中小项目,按以下顺序逐个加缓存,不要一开始就全上:
- 第一优先级:开启 PHP OPcache(零成本,立竿见影)。
- 第二优先级:用 Redis 缓存 Session 和 热点查询(用户相关数据、商品列表)。
- 第三优先级:当高并发出现时,引入 APCu 缓存配置和语言包,减轻 Redis 网络开销。
- 第四优先级:对于稳定的页面,做 整页静态化 或 CDN 加速。
最重要的是:缓存永远只是加速器,数据库(MySQL)才是数据源,在设计缓存 Key 时,务必确保修改数据(写/删)时,能够准确通知并清除相关的缓存 Key,避免脏读。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播