PHP项目文件缓存过期如何自动清理

wen PHP项目 27

本文目录导读:

PHP项目文件缓存过期如何自动清理

  1. 惰性检查法(推荐)
  2. 定时清理脚本(Cron Job)
  3. 懒清理 + 概率清理
  4. 基于文件系统的优雅方案
  5. 使用类似PHPAPC的解决方案
  6. 最佳实践建议

在PHP项目中实现文件缓存过期自动清理,常见有以下几种方案:

惰性检查法(推荐)

每次读取缓存时检查过期时间,过期则删除。

class FileCache
{
    private $cacheDir;
    public function __construct($cacheDir = '/tmp/cache')
    {
        $this->cacheDir = $cacheDir;
    }
    public function get($key)
    {
        $file = $this->getFilePath($key);
        if (!file_exists($file)) {
            return null;
        }
        // 读取缓存数据和过期时间
        $data = file_get_contents($file);
        $cache = unserialize($data);
        // 检查是否过期
        if (time() > $cache['expire_time']) {
            unlink($file); // 删除过期缓存
            return null;
        }
        return $cache['data'];
    }
    public function set($key, $data, $ttl = 3600)
    {
        $file = $this->getFilePath($key);
        $cache = [
            'expire_time' => time() + $ttl,
            'data' => $data
        ];
        file_put_contents($file, serialize($cache));
    }
    private function getFilePath($key)
    {
        $hash = md5($key);
        return $this->cacheDir . '/' . $hash . '.cache';
    }
}

定时清理脚本(Cron Job)

创建专门的清理脚本,定期清理过期缓存。

清理脚本 cleanup_cache.php

<?php
// 缓存目录
$cacheDir = '/tmp/cache';
// 递归清理过期文件
function cleanExpiredCache($dir, $maxLifetime = 3600) {
    $files = scandir($dir);
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') {
            continue;
        }
        $fullPath = $dir . '/' . $file;
        if (is_dir($fullPath)) {
            cleanExpiredCache($fullPath, $maxLifetime);
        } elseif (is_file($fullPath)) {
            $fileModTime = filemtime($fullPath);
            if (time() - $fileModTime > $maxLifetime) {
                unlink($fullPath);
                echo "Deleted: $fullPath\n";
            }
        }
    }
}
// 执行清理
cleanExpiredCache($cacheDir);
?>

添加Cron任务:

# 每1小时清理一次过期文件
0 * * * * /usr/bin/php /path/to/cleanup_cache.php
# 或者每天凌晨2点清理
0 2 * * * /usr/bin/php /path/to/cleanup_cache.php

懒清理 + 概率清理

请求到达时随机检查清理部分缓存文件。

class ProbabilisticCache
{
    private $cacheDir;
    private $probability = 0.01; // 1% 概率
    public function get($key)
    {
        // 随机触发清理
        if (mt_rand(1, 100) / 100 <= $this->probability) {
            $this->partialClean();
        }
        // 正常获取缓存逻辑...
    }
    private function partialClean()
    {
        $files = glob($this->cacheDir . '/*.cache');
        $count = min(10, count($files)); // 每次最多清理10个
        if ($count === 0) return;
        $keys = array_rand($files, $count);
        if (!is_array($keys)) {
            $keys = [$keys];
        }
        foreach ($keys as $index) {
            $file = $files[$index];
            $data = unserialize(file_get_contents($file));
            if (time() > $data['expire_time']) {
                unlink($file);
            }
        }
    }
}

基于文件系统的优雅方案

class SmartCache
{
    private $cacheDir;
    public function get($key, $ttl = 3600)
    {
        $file = $this->getFilePath($key);
        if (!file_exists($file)) {
            return null;
        }
        // 使用文件mtime判断过期
        if (time() - filemtime($file) > $ttl) {
            unlink($file);
            return null;
        }
        return unserialize(file_get_contents($file));
    }
    public function set($key, $data)
    {
        $file = $this->getFilePath($key);
        file_put_contents($file, serialize($data));
        // touch 设置文件修改时间
        touch($file);
    }
    public function cleanAll()
    {
        $files = glob($this->cacheDir . '/*');
        foreach ($files as $file) {
            if (is_file($file)) {
                unlink($file);
            }
        }
    }
}

使用类似PHPAPC的解决方案

// 如果安装了APCu扩展
class ApcuCache
{
    public function get($key)
    {
        return apcu_fetch($key);
    }
    public function set($key, $data, $ttl = 3600)
    {
        apcu_store($key, $data, $ttl);
    }
    // APCu自动处理过期清理,无需手动操作
}

最佳实践建议

  1. 生产环境推荐使用方案1(惰性检查),简单高效。

  2. 结合使用Cron任务,定期清理完全过期的文件。

  3. 合理设置缓存TTL,避免过多的碎片文件。

  4. 使用目录分层,避免单个目录文件过多:

// 对缓存key进行目录分层
private function getFilePath($key)
{
    $hash = md5($key);
    $dir1 = substr($hash, 0, 2);
    $dir2 = substr($hash, 2, 2);
    $cacheDir = $this->cacheDir . '/' . $dir1 . '/' . $dir2;
    if (!is_dir($cacheDir)) {
        mkdir($cacheDir, 0777, true);
    }
    return $cacheDir . '/' . $hash . '.cache';
}

方案可以根据项目规模和需求选择使用,对于小型项目,惰性检查法就足够了;大型项目可以结合Cron任务和惰性检查。

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