本文目录导读:

在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);
}
}
最佳实践建议
-
缓存策略选择
- 热点数据:Redis缓存,TTL 5-10分钟
- 静态资源:CDN + 浏览器缓存,TTL 1-7天
- 用户会话:Redis,TTL 30分钟
- 数据库结果:Redis,TTL 1-5分钟
-
代码示例(完整实现)
// 初始化缓存配置 $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应用的响应速度和并发处理能力,关键是根据业务场景选择合适的缓存策略,同时注意处理缓存一致性、雪崩、穿透等问题。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播