PHP多级缓存架构思路

wen PHP项目 3

本文目录导读:

PHP多级缓存架构思路

  1. 整体架构示意
  2. 各层缓存实现方案
  3. 缓存优化策略代码
  4. 监控与性能优化

我为您设计一个完整的PHP多级缓存架构方案,从外层到内层逐步解析。

整体架构示意

┌─────────────────────────────────────────────────────────┐
│                   客户端请求                              │
└────────────────────┬────────────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────────────┐
│    L1: CDN缓存层 (静态资源)                               │
│    - 图片、CSS、JS、视频等                                │
└────────────────────┬────────────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────────────┐
│    L2: 页面缓存层 (HTML输出)                              │
│    - Redis/Nginx FastCGI Cache                          │
└────────────────────┬────────────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────────────┐
│    L3: 应用数据缓存层 (业务数据)                          │
│    - Redis主要缓存 + 本地进程缓存(APCu)                    │
└────────────────────┬────────────────────────────────────┘
                     ▼
│    L4: 数据库层 (MySQL/MongoDB)                          │
└─────────────────────────────────────────────────────────┘

各层缓存实现方案

L1 CDN缓存层

// 配置CDN缓存头
header('Cache-Control: public, max-age=86400, s-maxage=86400');
header('ETag: "' . md5($fileContent) . '"');
// 静态资源缓存策略
class CDNCacheManager {
    public function setStaticCacheHeaders($fileType) {
        $cacheTimes = [
            'image' => 604800, // 7天
            'css' => 2592000,  // 30天
            'js' => 2592000,   // 30天
            'html' => 3600     // 1小时
        ];
        header('Cache-Control: public, max-age=' . $cacheTimes[$fileType]);
        header('Vary: Accept-Encoding');
    }
    // 版本控制,解决缓存失效问题
    public function getVersionedUrl($path, $version) {
        return $path . '?v=' . $version;
    }
}

L2 页面缓存层

class PageCacheManager {
    private $redis;
    private $cacheKeyPrefix = 'page:';
    private $ttl = 3600;
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    /**
     * 获取页面缓存
     */
    public function getContent($requestUri) {
        // 生成缓存key,包含URL和参数
        $cacheKey = $this->cacheKeyPrefix . md5($requestUri);
        // 尝试从缓存获取
        $cached = $this->redis->get($cacheKey);
        if ($cached !== false) {
            // 恢复HTML内容
            return unserialize($cached);
        }
        return null;
    }
    /**
     * 存储页面缓存
     */
    public function setContent($requestUri, $html) {
        $cacheKey = $this->cacheKeyPrefix . md5($requestUri);
        // 序列化存储
        $this->redis->setex(
            $cacheKey, 
            $this->ttl, 
            serialize([
                'content' => $html,
                'timestamp' => time()
            ])
        );
    }
    /**
     * 页面缓存失效策略
     */
    public function invalidatePages($patterns) {
        foreach ($patterns as $pattern) {
            $keys = $this->redis->keys($this->cacheKeyPrefix . $pattern);
            foreach ($keys as $key) {
                $this->redis->del($key);
            }
        }
    }
}

L3 应用数据缓存层

class AppCacheManager {
    private $redis;
    private $localCache = [];
    private $apcuEnabled;
    private $ttlMap = [
        'user_profile' => 3600,
        'product_list' => 300,
        'hot_search' => 600,
        'initial_data' => 1800
    ];
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
        $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
        $this->apcuEnabled = function_exists('apcu_add');
    }
    /**
     * 分层获取缓存数据:APCu -> Redis -> DB
     */
    public function get($key, $callback, $ttl = null) {
        // L3.1: 检查本地进程缓存(APCu)
        if ($this->apcuEnabled) {
            $data = apcu_fetch($key);
            if ($data !== false) {
                return $data;
            }
        }
        // L3.2: 检查Redis缓存
        $data = $this->redis->get($key);
        if ($data !== false) {
            // 写入本地缓存
            if ($this->apcuEnabled) {
                apcu_store($key, $data, 60); // 本地缓存只有60秒
            }
            return $data;
        }
        // L3.3: 缓存未命中,从数据库获取
        $data = $callback();
        // 写入各级缓存
        $effectiveTtl = $ttl ?? $this->ttlMap[$key] ?? 3600;
        $this->redis->setex($key, $effectiveTtl, $data);
        if ($this->apcuEnabled) {
            apcu_store($key, $data, 60);
        }
        return $data;
    }
    /**
     * 批量获取缓存,避免击穿
     */
    public function getMulti(array $keys) {
        // 首先从APCu获取
        $localData = [];
        if ($this->apcuEnabled) {
            $localData = apcu_fetch($keys);
            $missingKeys = array_diff($keys, array_keys($localData));
        } else {
            $missingKeys = $keys;
        }
        // 从Redis获取缺失的
        $redisData = [];
        if (!empty($missingKeys)) {
            $redisData = $this->redis->mget($missingKeys);
            $redisData = array_combine($missingKeys, $redisData);
            // 处理Redis缓存未命中的情况
            $stillMissing = [];
            foreach ($redisData as $k => $v) {
                if ($v === false) {
                    $stillMissing[] = $k;
                }
            }
            // 从数据库获取(略)
        }
        return $localData + $redisData;
    }
    /**
     * 缓存防击穿策略
     */
    public function getWithMutex($key, $callback, $ttl = null) {
        // 使用Redis的SETNX实现互斥锁
        $lockKey = $key . ':lock';
        // 尝试获取缓存
        $data = $this->redis->get($key);
        if ($data !== false) {
            return $data;
        }
        // 尝试获取锁
        $locked = $this->redis->set($lockKey, 1, ['NX', 'EX' => 10]);
        if ($locked) {
            // 获取到锁,从数据库获取数据
            $data = $callback();
            $effectiveTtl = $ttl ?? $this->ttlMap[$key] ?? 3600;
            $this->redis->setex($key, $effectiveTtl, $data);
            // 释放锁
            $this->redis->del($lockKey);
            // 写入本地缓存
            if ($this->apcuEnabled) {
                apcu_store($key, $data, 60);
            }
            return $data;
        } else {
            // 未获取到锁,等待然后重试
            usleep(50000); // 50ms
            return $this->redis->get($key);
        }
    }
}

多级缓存协调层

class MultiLevelCache {
    private $pageCache;
    private $appCache;
    private $config;
    public function __construct() {
        $this->config = [
            'page_cache_enabled' => true,
            'app_cache_enabled' => true,
            'cache_prefix' => 'app:',
            'default_ttl' => 3600
        ];
        $this->pageCache = new PageCacheManager();
        $this->appCache = new AppCacheManager();
    }
    /**
     * 统一缓存入口
     */
    public function handleRequest($request) {
        // 1. 页面级缓存检查
        if ($this->config['page_cache_enabled']) {
            $pageContent = $this->pageCache->getContent($request->getUri());
            if ($pageContent) {
                return $this->response($pageContent['content']);
            }
        }
        // 2. 执行业务逻辑
        $data = $this->processBusinessLogic($request);
        // 3. 生成HTML
        $html = $this->renderView($data);
        // 4. 存储页面缓存
        if ($this->config['page_cache_enabled']) {
            $this->pageCache->setContent($request->getUri(), $html);
        }
        return $this->response($html);
    }
    /**
     * 动态数据处理
     */
    public function getBusinessData($key, $callback) {
        // 应用级缓存
        return $this->appCache->getWithMutex(
            $this->config['cache_prefix'] . $key,
            $callback
        );
    }
    /**
     * 局部缓存刷新策略
     */
    public function refreshData($keys) {
        foreach ($keys as $key) {
            // 删除应用缓存
            $this->appCache->delete($key);
        }
        // 删除相关页面缓存
        $this->pageCache->invalidatePages($keys);
    }
    /**
     * 缓存命中率监控
     */
    public function getCacheStats() {
        // 使用内存存储获取缓存统计
        $stats = [
            'redis_hits' => apcu_fetch('cache_redis_hits'),
            'redis_misses' => apcu_fetch('cache_redis_misses'),
            'apcu_hits' => apcu_fetch('cache_apcu_hits'),
            'apcu_misses' => apcu_fetch('cache_apcu_misses'),
            'page_caches' => apcu_fetch('cache_page_count')
        ];
        return $stats;
    }
}

缓存优化策略代码

class CacheOptimization {
    // 缓存预热
    public function preWarmCache() {
        $hotData = [
            'hot_search' => '热点搜索',
            'navigation' => '导航数据',
            'recommendation' => '推荐内容'
        ];
        foreach ($hotData as $key => $callback) {
            // 预先获取数据
            $data = $this->loadDataFromDB($callback);
            // 写入Redis
            $this->redis->setex($key, 3600, $data);
            // 写入APCu
            apcu_store($key, $data, 60);
        }
    }
    // 缓存穿透处理
    public function handleCachePenetration($key, $callback) {
        // 使用值-1表示不存在的数据
        $data = $this->redis->get($key);
        if ($data === -1) {
            return null; // 已知不存在的数据
        }
        if ($data === false) {
            // 先从数据库获取
            $result = $callback();
            if ($result === null) {
                // 缓存空结果,防止穿透
                $this->redis->setex($key, 300, -1); // 5分钟
            } else {
                $this->redis->setex($key, 3600, $result);
            }
            return $result;
        }
        return $data;
    }
    // 缓存雪崩预防
    public function setWithRandomTTL($key, $data, $baseTTL) {
        // 添加随机偏移,避免同一时间失效
        $randomOffset = mt_rand(0, 300); // 0-5分钟随机
        $effectiveTTL = $baseTTL + $randomOffset;
        $this->redis->setex($key, $effectiveTTL, $data);
    }
}

监控与性能优化

class CacheMonitor {
    public function logCacheEvent($event, $key, $layer) {
        $logData = [
            'timestamp' => time(),
            'event_type' => $event, // hit/miss/expire
            'cache_key' => $key,
            'cache_layer' => $layer,
            'request_time' => microtime(true)
        ];
        // 异步发送到监控系统
        $this->asyncLog($logData);
    }
    public function getCacheHitRate() {
        // 计算各级缓存的命中率
        return [
            'cdn' => $this->calculateHitRate('cdn'),
            'page' => $this->calculateHitRate('page'),
            'redis' => $this->calculateHitRate('redis'),
            'apcu' => $this->calculateHitRate('apcu')
        ];
    }
    private function calculateHitRate($layer) {
        // 从统计数据计算
        $stats = $this->getStatsFromMetrics($layer);
        if ($stats['total'] == 0) {
            return 0;
        }
        return $stats['hits'] / $stats['total'] * 100;
    }
}

核心要点:

  1. 分层缓存:CDN -> 页面缓存 -> 应用缓存 -> 数据库
  2. 分布式与本地结合:Redis(分布式)+ APCu(本地进程)
  3. 防击穿:使用互斥锁
  4. 防穿透:缓存空值
  5. 防雪崩:随机过期时间
  6. 监控统计:命中率、延迟监控

建议:

  • 根据业务特点调整各层TTL
  • 实时数据不缓存,热点数据优先缓存
  • 使用缓存版本控制方便失效
  • 确保缓存与数据源的一致性

这种架构能显著提升PHP应用性能,适用于高并发场景。

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