之前研究了,高性能 PHP 缓存系统设计:智能清理与计数管理。
但我发现,这只能缓存单独的html,不能缓存一些想要缓存的数据。
同时,为了解决inode的限制。
所以我尝试着将缓存文件,放到db数据库里,从而实现高效存储。
缓存代码:
<?php
/**
* 统一缓存类(SQLite 分布式)
* 支持 API 缓存(get/set)和页面缓存(allget)
*/
class ApiCache
{
private $root;
private $dbPool = [];
private $obStarted = false;
private $currentUrl = null;
public function __construct($rootDir)
{
$this->root = rtrim($rootDir, '/') . '/';
if (!is_dir($this->root)) {
mkdir($this->root, 0755, true);
}
}
public function get($url)
{
$md5 = md5($url);
$db = $this->getDb($md5);
if (!$db) return false;
$stmt = $db->prepare("SELECT content, access_count, permanent, first_time FROM cache WHERE md5 = ?");
$stmt->execute([$md5]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) {
return false;
}
$update = $db->prepare("UPDATE cache SET access_count = access_count + 1, last_time = ? WHERE md5 = ?");
$update->execute([time(), $md5]);
return gzuncompress($row['content']);
}
public function set($url, $data, $permanent = 0)
{
$md5 = md5($url);
$db = $this->getDb($md5);
if (!$db) return false;
$compressed = gzcompress($data);
$now = time();
$stmt = $db->prepare("INSERT OR REPLACE INTO cache (md5, content, access_count, first_time, last_time, permanent)
VALUES (?, ?, 0, ?, ?, ?)");
return $stmt->execute([$md5, $compressed, $now, $now, $permanent]);
}
public function allget()
{
if ($this->obStarted) return;
$url = $this->getCurrentUrl();
$this->currentUrl = $url;
$content = $this->get($url);
if ($content !== false) {
echo $content;
exit;
}
ob_start([$this, 'autoStore']);
$this->obStarted = true;
}
public function autoStore($content)
{
if ($this->currentUrl !== null) {
$this->set($this->currentUrl, $content, 0);
}
$this->obStarted = false;
return $content;
}
private function getCurrentUrl()
{
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
return $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
private function getDb($md5)
{
$dir1 = substr($md5, 0, 2);
$dir2 = substr($md5, -2);
$dirPath = $this->root . $dir1 . '/' . $dir2;
$dbFile = $dirPath . '/data.db';
$key = $dir1 . '/' . $dir2;
if (isset($this->dbPool[$key])) {
return $this->dbPool[$key];
}
if (!is_dir($dirPath)) {
if (!mkdir($dirPath, 0755, true)) {
return false;
}
}
try {
$pdo = new PDO("sqlite:" . $dbFile);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec("CREATE TABLE IF NOT EXISTS cache (
md5 TEXT PRIMARY KEY,
content BLOB,
access_count INTEGER DEFAULT 0,
first_time INTEGER,
last_time INTEGER,
permanent INTEGER DEFAULT 0
)");
$pdo->exec("CREATE INDEX IF NOT EXISTS idx_first_time ON cache(first_time)");
$pdo->exec("CREATE INDEX IF NOT EXISTS idx_access_count ON cache(access_count)");
$pdo->exec("CREATE INDEX IF NOT EXISTS idx_permanent ON cache(permanent)"); // 新增索引
$pdo->exec("PRAGMA synchronous = OFF");
$pdo->exec("PRAGMA journal_mode = MEMORY");
$this->dbPool[$key] = $pdo;
return $pdo;
} catch (PDOException $e) {
error_log("SQLite open failed: " . $e->getMessage());
return false;
}
}
public function close()
{
$this->dbPool = [];
}
}
清理代码:
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END










![表情[aoman]-红穆笔记](https://www.4s5.cn/wp-content/themes/zibll/img/smilies/aoman.gif)



暂无评论内容