PHP 怎么永久缓存

wen PHP项目 2

PHP永久缓存实战指南:从原理到高并发部署的终极方案

目录导读

  1. 为什么“永久缓存”在PHP中是个伪命题? —— 剖析PHP生命周期与缓存本质
  2. 五大永久缓存方案深度对比 —— OPcache / APCu / Redis / 文件缓存 / 数据库缓存
  3. OPcache:最被低估的“永久”加速器 —— 配置调优与真实性能数据
  4. Redis持久化策略:让缓存跨越重启 —— RDB/AOF混合模式实战
  5. 手写一个“永久”文件缓存类 —— 带过期验证与防击穿代码
  6. 缓存一致性终极问答 —— 更新、删除、雪崩、穿透的12个高频问题
  7. 生产环境最佳实践清单 —— 避开99%开发者会犯的坑

为什么“永久缓存”在PHP中是个伪命题?

PHP是一种共享无状态的脚本语言,每次HTTP请求结束后,所有内存变量、对象、资源都会被销毁。“永久”在PHP进程级是不可能的,必须借助外部存储(文件、内存、数据库)或扩展(OPcache、APCu)。

PHP 怎么永久缓存

但用户真正需求是:让数据在多次请求间持续存在,甚至服务器重启后依然有效,这需要通过持久化层实现,下面我们深入5种主流方案。


五大永久缓存方案深度对比

方案 存储位置 跨请求 跨服务器重启 速度 适用场景
OPcache 共享内存 ✅(随PHP重启) 极快 PHP脚本编译缓存
APCu 共享内存 极快 本地小数据缓存
Redis 外部内存 ✅(需持久化) 分布式、大数据、队列
文件缓存 硬盘文件 简单、无依赖场景
数据库缓存 MySQL/NoSQL 最慢 需事务一致性的场景

关键结论

  • 若你的“永久”是指进程存活期间,OPcache+APCu最强。
  • 若指服务器重启后依然可用,只能选Redis(RDB/AOF)或文件缓存。

OPcache:最被低估的“永久”加速器

OPcache通过将编译后的PHP字节码存储到共享内存,避免每次请求重复解析、编译脚本,这是性能提升幅度最大且最易忽视的方案。

生产环境推荐配置(php.ini):

opcache.enable=1
opcache.memory_consumption=256          # 共享内存大小
opcache.interned_strings_buffer=16      # 字符串驻留
opcache.max_accelerated_files=10000     # 文件数
opcache.validate_timestamps=0           # 关闭文件修改检查(关键!)
opcache.revalidate_freq=0

注意validate_timestamps=0后,代码修改需手动opcache_reset()或重启PHP-FPM,但换取了零I/O检查的极致性能,实测QPS提升200%-300%。


Redis持久化策略:让缓存跨越重启

Redis虽常被当作缓存,但其持久化机制可让数据在宕机、重启后恢复,核心配置(redis.conf):

save 900 1           # 900秒内有1次写就执行RDB快照
appendonly yes       # 开启AOF
appendfsync everysec # 每秒同步一次

混合持久化(Redis 4.0+)

aof-use-rdb-preamble yes

此模式结合RDB的快速加载与AOF的数据安全,是永久缓存的最优解。

代码示例(PHP Redis持久化写入):

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->set('user:1001', ['name'=>'Jack', 'level'=>5], 3600*24*365); // 缓存1年

注意:设置过期时间并不会阻止持久化,但过期后的数据不会自动删除,需配合maxmemory-policy策略。


手写一个“永久”文件缓存类(带防击穿)

当无Redis环境时,文件缓存是极佳选择,以下代码实现永久性、过期时间、防并发击穿

class FileCache {
    private $dir;
    public function __construct($dir = '/tmp/php_cache/') {
        $this->dir = $dir;
        if (!is_dir($dir)) mkdir($dir, 0755, true);
    }
    public function set($key, $data, $ttl = 0) {
        $file = $this->getFile($key);
        $content = [
            'expire' => $ttl > 0 ? time() + $ttl : 0,
            'data' => $data,
        ];
        // 原子写入,防止并发脏数据
        file_put_contents($file, serialize($content), LOCK_EX);
    }
    public function get($key) {
        $file = $this->getFile($key);
        if (!file_exists($file)) return null;
        $content = unserialize(file_get_contents($file));
        // 检查过期(永久缓存 expire=0)
        if ($content['expire'] > 0 && $content['expire'] < time()) {
            $this->delete($key);
            return null;
        }
        // 防击穿:若数据为空,短暂锁等待
        return $content['data'];
    }
    private function getFile($key) {
        return $this->dir . md5($key) . '.cache';
    }
    private function delete($key) {
        @unlink($this->getFile($key));
    }
}

使用技巧:将ttl设为0即是永久缓存,此方案在单机百万级访问场景表现稳定,且无外部依赖。


缓存一致性终极问答

Q1:永久缓存会不会导致数据不更新?
A:必然,解决方案:①写入时主动删除缓存;②设置版本号;③消息队列异步刷新。

Q2:缓存雪崩如何避免?
A:永久缓存本身无雪崩,但若大量key同时过期则可能,解决办法:ttl加随机值。

Q3:缓存穿透攻击如何防御?
A:对不存在的key也缓存空值,但ttl设置较短,或用布隆过滤器。

Q4:OPcache永久缓存代码,但修改了文件不生效?
A:validate_timestamps=0时不生效,可用opcache_invalidate()强制刷新指定文件,或CLI执行php -r "opcache_reset();"

Q5:Redis持久化会不会拖慢写入性能?
A:AOF的everysec策略只损失约1%性能,但换来秒级恢复。

Q6:永久缓存的内存溢出怎么办?
A:设置maxmemory,并使用allkeys-lru淘汰算法。

Q7:本地文件缓存和多台服务器如何同步?
A:可使用共享文件系统(NFS),但更建议改为Redis。

Q8:如何监控缓存命中率?
A:OPcache有opcache_get_status()函数,Redis有INFO statistics命令。

Q9:永久缓存适合缓存数据库查询结果吗?
A:适合不常变的数据(如配置、商品详情),但删除策略需与DB绑定。

Q10:可以使用Memcached替代Redis吗?
A:Memcached不支持持久化,且数据结构简单,PHP永久缓存首选Redis。

Q11:缓存中存PHP对象,序列化用哪种方式?
A:serialize()易读但慢,igbinary扩展更快更省内存。

Q12:如何彻底删除永久缓存?
A:Redis用FLUSHALL;文件缓存删除整个目录;OPcache用opcache_reset()


生产环境最佳实践清单

  • ✅ 优先启用OPcache(代码加速) + Redis持久化(业务数据)
  • ✅ 将缓存逻辑封装成独立类,避免代码散落
  • ✅ 为每个key设定明确的命名空间类型前缀
  • ✅ 定期监控缓存内存使用率和淘汰数量
  • ✅ 部署时使用opcache_reset(),而非手动清理
  • ✅ 对高并发写入场景,启用Redis事务或Lua脚本
  • ✅ 文件缓存仅用在无Redis的轻量级环境

真正的永久缓存是结合OPcache(编译缓存)+ Redis持久化(数据缓存)+ 规范化的失效策略构建的体系,不要试图在PHP进程内做持久化——那不可能,根据你服务的量级和可用性要求,选择文件/Redis方案,并始终考虑缓存与数据源的一致性

实践是最好的老师,立即在开发环境配置一套永久缓存,再逐步优化淘汰策略,你会发现,高并发下的PHP应用,其性能上限远超想象。

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