PHP 缓存策略大全:文件缓存 / Redis / Memcached 对比

不语
不语 正式会员正式会员认证极客认证极客
发布于 2026-09-28 15:06 ·2 浏览 ·2 回复
本文转载自 Clara轻量论坛系统 - 轻量级 PHP 论坛系统,原文地址:https://www.leleweb.cn/thread-623.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
CLARA轻量论坛系统

全部回复 2

ipzh
ipzh 正式会员正式会员认证极客认证极客 Lv2 1楼 2026-09-28 15:16

选型就一句话:单机小站「文件缓存 + OPcache」足够,多机或需要原子操作/队列直接上 Redis,Memcached 只在你已有存量运维、又纯做 KV 高并发读时才值得留,新项目没必要选它。

补一下 Memcached 这块的边界,帖子里刚好断在这:它的优势是多线程 + 纯内存,读并发确实猛,做 HTML 片段和计数器很合适;但它是纯 KV,value 默认上限 1MB,没有 scan、没有持久化、没有复杂结构,一旦你要排行榜、分布式锁、消息队列,就得再搭一套 Redis,等于维护两套中间件。所以除非团队已有积累,直接 Redis 全家桶更省事。

帖子里文件缓存那段有个隐患值得补:`file_put_contents(..., LOCK_EX)` 只保证写端互斥,读端的 `include` 并不参与锁。A 进程正在写、B 进程 include 读到半个文件,会直接 parse error,而且 include 的报错很难优雅兜住。正确姿势是先写临时文件再 `rename()` 原子替换(同分区 rename 是原子的),读端永远只能看到完整文件。另外 md5 建议取两层子目录(前两位 / 次两位),单目录文件数才控得住。

Redis 侧三个必踩的:生产禁用 `keys *`,一律 `scan` 游标;大 key 删除会阻塞,用 `unlink()` 异步删;雪崩给 TTL 加随机抖动、击穿用 setnx 单飞重建、穿透缓存空值。还有 `maxmemory` 一定要设死并配 `allkeys-lru`,不然内存打满触发 swap,全站一起拖死。

最后提一句:如果是在 Clara 上写插件,不用自己造这套轮子,它内置了 `Cache::remember` 公共设施,键名前缀和清理交给框架处理就行。另外 OPcache 上线后记得把 `validate_timestamps` 关掉(发布时 reload php-fpm),否则每次请求都 stat 一遍文件,缓存收益要大打折扣。

shandian
shandian 见习用户见习用户 #228 2楼 2026-09-28 15:25
ipzh:选型就一句话:单机小站「文件缓存 + OPcache」足够,多机或需要原子操作/队列直接上 Redis,Memcached 只在你已有存量运维、又纯做 KV 高…

ipzh 这几条基本都对,但有个隐藏冲突需要点出来:帖子前面推荐的 `.php` 文件缓存 + 后面建议的关闭 `validate_timestamps`,两个一起用会让缓存永不更新。

原因是 OPcache 是按 realpath 缓存编译结果的,`rename()` 换掉了 inode 但路径没变;关掉 `validate_timestamps` 后它不再 stat 文件,于是永远吐旧字节码。你那套「原子替换」写入逻辑是对的,但读端如果走 `include`,必须配 `opcache_invalidate($file, true)`,或者干脆别用 `.php` 存缓存——改成 `serialize()` 写 `.txt`/`.dat`,读出来 `unserialize()`,就绕开了 OPcache 这层,代价是多一次反序列化。真要用 `.php` 又想要 OPcache 收益,也可以保留 `validate_timestamps`,把 `revalidate_freq` 设成 2~5 秒,用一点点 stat 换正确性。

`rename()` 那点再补一句:原子性只在同分区成立,临时文件必须建在缓存目录同一层,别用系统 `/tmp`(很多机器上是独立分区或 tmpfs,跨设备 rename 会退化成拷贝)。另外多个进程并发写时各写各的临时文件、最后一个 rename 赢,这个"无锁竞争"是安全的,但临时文件名要么带 pid,要么 `tempnam()`,别复用固定名。

Clara 这边 `Cache::remember` 确实是内置的公共设施,插件里直接调就行,不用自己糊一套;不过它内部具体的前缀规则和清理粒度我没翻过源码,不敢替它打包票,接入前建议自己压一遍过期行为。定时清理也可以挂 `Cron::register`,不用额外配 crontab。

最后一个小坑:Redis 如果只当缓存用,别开 AOF,缓存丢了重建就行,持久化纯属白白吃 IO 和 fork 开销——只有当它同时兼任队列或计数账本时才值得开。