PHP项目怎么加缓存层

wen PHP项目 3

本文目录导读:

PHP项目怎么加缓存层

  1. 缓存架构设计
  2. 核心缓存实现方案
  3. 缓存常见问题解决方案
  4. 监控与调优
  5. 最佳实践建议

在PHP项目中添加缓存层是提升性能的关键手段,以下是系统的实施指南:

缓存架构设计

缓存层级结构

PHP应用
  ├── 第一层:OPcache(字节码缓存)
  ├── 第二层:应用级缓存(Redis/Memcached)
  ├── 第三层:HTTP缓存(CDN/浏览器)
  └── 第四层:数据库查询缓存

核心缓存实现方案

OPcache 配置(必做)

// php.ini 推荐配置
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1

Redis 缓存层(主流方案)

基础封装类

<?php
class CacheManager {
    private $redis;
    private $prefix;
    private $ttl;
    public function __construct($config) {
        $this->redis = new Redis();
        $this->redis->connect($config['host'], $config['port']);
        $this->prefix = $config['prefix'] ?? 'app:';
        $this->ttl = $config['ttl'] ?? 3600;
        if (!empty($config['password'])) {
            $this->redis->auth($config['password']);
        }
    }
    // 防雪崩:设置随机过期时间
    private function getRandomTtl($baseTtl) {
        return $baseTtl + rand(0, 300);
    }
    // 防击穿:互斥锁
    public function remember($key, $callback, $ttl = null) {
        $ttl = $ttl ?: $this->ttl;
        $cacheKey = $this->prefix . $key;
        // 读取缓存
        $data = $this->redis->get($cacheKey);
        if ($data !== false) {
            return unserialize($data);
        }
        // 获取锁,防止缓存击穿
        $lockKey = $cacheKey . ':lock';
        if ($this->redis->set($lockKey, 1, ['NX', 'EX' => 10])) {
            try {
                // 执行原始操作
                $data = $callback();
                // 写入缓存(带随机过期时间)
                $this->redis->setex(
                    $cacheKey, 
                    $this->getRandomTtl($ttl), 
                    serialize($data)
                );
                return $data;
            } finally {
                $this->redis->del($lockKey);
            }
        } else {
            // 等待锁释放后重试
            usleep(100000); // 100ms
            return $this->remember($key, $callback, $ttl);
        }
    }
    // 批量清除
    public function flushPattern($pattern) {
        $keys = $this->redis->keys($this->prefix . $pattern . '*');
        if (!empty($keys)) {
            $this->redis->del($keys);
        }
    }
}

多级缓存策略

<?php
class MultiLevelCache {
    private $memoryCache = [];  // 内存缓存
    private $redis;
    public function get($key, $callback, $ttl = 3600) {
        // L1: 内存缓存(最快)
        if (isset($this->memoryCache[$key])) {
            return $this->memoryCache[$key];
        }
        // L2: Redis缓存
        $redisKey = 'cache:' . $key;
        $data = $this->redis->get($redisKey);
        if ($data !== false) {
            $this->memoryCache[$key] = unserialize($data);
            return $this->memoryCache[$key];
        }
        // L3: 数据库或API调用
        $data = $callback();
        $this->redis->setex($redisKey, $ttl, serialize($data));
        $this->memoryCache[$key] = $data;
        return $data;
    }
}

页面级缓存

<?php
class PageCache {
    private $cacheDir;
    public function start($cacheKey, $ttl = 300) {
        $cacheFile = $this->cacheDir . '/' . md5($cacheKey) . '.html';
        // 检查缓存是否有效
        if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $ttl)) {
            readfile($cacheFile);
            exit;
        }
        // 开始输出缓冲
        ob_start();
        // 注册关闭函数,保存缓存
        register_shutdown_function(function() use ($cacheFile) {
            $content = ob_get_flush();
            file_put_contents($cacheFile, $content);
        });
    }
}

数据库查询缓存

<?php
class QueryCache {
    private $redis;
    private $queryCache = [];
    public function query($sql, $params = []) {
        // 生成查询缓存键
        $cacheKey = 'query:' . md5($sql . serialize($params));
        // 尝试从缓存获取
        $result = $this->redis->get($cacheKey);
        if ($result !== false) {
            return unserialize($result);
        }
        // 执行查询(此处假设使用PDO)
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        // 缓存结果(5分钟)
        $this->redis->setex($cacheKey, 300, serialize($result));
        return $result;
    }
    // 数据变更时清除相关缓存
    public function invalidate($table) {
        $this->redis->del($this->redis->keys('query:*' . $table . '*'));
    }
}

缓存常见问题解决方案

缓存穿透

// 使用布隆过滤器
class BloomFilter {
    private $redis;
    private $key = 'bloom:filter';
    public function add($item) {
        $hash1 = crc32($item);
        $hash2 = md5($item);
        // 设置多个位
        for ($i = 0; $i < 3; $i++) {
            $this->redis->setBit($this->key, $hash1 % 100000, 1);
            $this->redis->setBit($this->key, ($hash2 + $i) % 100000, 1);
        }
    }
    public function exists($item) {
        // 检查所有位是否都设置
    }
}

缓存与数据库一致性

// 使用消息队列异步更新缓存
class CacheUpdateListener {
    public function onDataChanged($event) {
        // 发送到消息队列
        $queue->push('cache:update', [
            'table' => $event->table,
            'id' => $event->id
        ]);
    }
    public function processUpdate() {
        while ($message = $queue->pop('cache:update')) {
            // 重新构建缓存
            $this->rebuildCache($message['table'], $message['id']);
        }
    }
}

监控与调优

命中率监控

class CacheMonitor {
    private $redis;
    public function logHit($key) {
        $this->redis->incr('stats:hits');
        $this->redis->incr('stats:hits:' . $key);
    }
    public function logMiss($key) {
        $this->redis->incr('stats:misses');
        $this->redis->incr('stats:misses:' . $key);
    }
    public function getStats() {
        $hits = $this->redis->get('stats:hits') ?: 0;
        $misses = $this->redis->get('stats:misses') ?: 0;
        return [
            'hits' => $hits,
            'misses' => $misses,
            'rate' => $hits / ($hits + $misses) * 100
        ];
    }
}

本地缓存加速

// 使用APCu作为本地缓存
class LocalCache {
    public function get($key) {
        return apcu_fetch($key) ?: null;
    }
    public function set($key, $value, $ttl = 300) {
        apcu_store($key, $value, $ttl);
    }
}

最佳实践建议

  1. 缓存策略选择

    • 热点数据:Redis缓存,TTL 5-10分钟
    • 静态资源:CDN + 浏览器缓存,TTL 1-7天
    • 用户会话:Redis,TTL 30分钟
    • 数据库结果:Redis,TTL 1-5分钟
  2. 代码示例(完整实现)

    // 初始化缓存配置
    $cacheConfig = [
     'host' => '127.0.0.1',
     'port' => 6379,
     'prefix' => 'mvc:',
     'ttl' => 3600
    ];

$cache = new CacheManager($cacheConfig);

// 使用缓存获取用户信息 $userId = 123; $user = $cache->remember("user:{$userId}", function() use ($db, $userId) { return $db->query("SELECT * FROM users WHERE id = ?", [$userId]); }, 600);


3. **缓存工具类推荐**
   - Symfony Cache组件
   - Laravel Cache门面
   - PHP-Cache库
通过以上多层缓存策略,可以显著提升PHP应用的响应速度和并发处理能力,关键是根据业务场景选择合适的缓存策略,同时注意处理缓存一致性、雪崩、穿透等问题。

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