PHP数据缓存策略与更新模式
PHP数据缓存策略与更新模式
缓存是提升应用性能最有效的手段。今天说说各种缓存策略和缓存更新模式。
旁路缓存是最常用的模式。
```php
class CacheAside
{
private Redis $redis;
private PDO $pdo;
public function __construct(Redis $redis, PDO $pdo)
{
$this->redis = $redis;
$this->pdo = $pdo;
}
public function get(string $key, callable $loader, int $ttl = 3600): mixed
{
$cached = $this->redis->get($key);
if ($cached !== false) return unserialize($cached);
$value = $loader();
$this->redis->setex($key, $ttl, serialize($value));
return $value;
}
public function delete(string $key): void
{
$this->redis->del($key);
}
}
?>
先更新数据库后删除缓存的策略。
```php
class CacheConsistency
{
private Redis $redis;
private PDO $pdo;
public function updateUser(int $id, array $data): void
{
// 先更新数据库
$sets = [];
$params = [];
foreach ($data as $key => $value) {
$sets[] = "{$key} = ?";
$params[] = $value;
}
$params[] = $id;
$this->pdo->prepare("UPDATE users SET " . implode(', ', $sets) . " WHERE id = ?")->execute($params);
// 再删除缓存
$this->redis->del("user:{$id}");
}
}
?>
缓存穿透、击穿、雪崩的防护。
```php
class CacheProtection
{
private Redis $redis;
public function __construct(Redis $redis)
{
$this->redis = $redis;
}
// 防止缓存穿透
public function get(string $key, callable $loader, int $ttl = 3600): mixed
{
$cached = $this->redis->get($key);
if ($cached === 'NULL') return null;
if ($cached !== false) return unserialize($cached);
$value = $loader();
if ($value === null) {
$this->redis->setex($key, 60, 'NULL');
} else {
$this->redis->setex($key, $ttl, serialize($value));
}
return $value;
}
// 防止缓存击穿
public function getWithLock(string $key, callable $loader, int $ttl = 3600): mixed
{
$cached = $this->redis->get($key);
if ($cached !== false) return unserialize($cached);
$lockKey = "lock:{$key}";
if ($this->redis->setnx($lockKey, 1)) {
$this->redis->expire($lockKey, 10);
$value = $loader();
$this->redis->setex($key, $ttl + rand(0, 300), serialize($value));
$this->redis->del($lockKey);
return $value;
}
usleep(100000);
return $this->getWithLock($key, $loader, $ttl);
}
}
?>
缓存在提升性能方面立竿见影。但不是所有数据都适合缓存。频繁变化的数据、每次请求都不同的数据、对实时性要求高的数据就不适合缓存。先分析业务场景,再选择合适的缓存策略,效果才会好。
