BLOG

个人网站缓存应该从哪里开始做

缓存应先解决重复且昂贵的读取,不要一开始把所有页面都缓存。

分类:PHP 全栈开发 阅读:194
个人网站缓存应该从哪里开始做
个人网站缓存应该从哪里开始做

个人网站做缓存,最容易犯的错是一上来就想“全站缓存”。实际上,个人站点流量不大,服务器资源也有限,真正拖慢响应的是那些每次请求都要重复执行的数据库查询。比如首页的栏目统计、分类树、站点配置,这些数据不常变化,却会在每个访客访问时被反复读取。缓存要解决的,正是这类“重复且昂贵”的读取。

先判断哪些内容值得缓存

动手之前,先别急着写缓存代码,而是确认三件事:这个页面是给谁看的,数据从哪里来,多久变一次。个人网站通常分两类内容:一类是公开的、所有访客看到都一样的内容,比如文章列表、分类导航、站点配置;另一类是和用户状态相关的,比如登录后的个人中心、草稿箱、管理后台的统计数据。

区分这两类的意义在于,公开内容可以放心做缓存,而涉及登录态和权限的内容,一旦误用公共缓存,就会造成用户之间串数据。比如管理员在后台更新了站点公告,普通访客却因为缓存还看到旧内容;又比如某个页面包含当前登录用户的用户名或专属数据,如果被公共缓存命中,另一个用户打开时就会看到别人的信息。

判断方法很简单:在浏览器无痕窗口打开页面,再登录后打开同一页面,如果内容有差异,就说明这个页面依赖用户状态,不能放进公共缓存。涉及用户身份的页面,要么不做缓存,要么用包含用户ID的独立缓存键,并设置很短的过期时间。

处理顺序:先测量,再动手

缓存不是拍脑袋加的,先确认瓶颈在哪。打开数据库慢查询日志,或者用简单的计时脚本统计每个页面里查询耗时最长的几条SQL。个人网站最常见的瓶颈通常是首页,因为首页往往要聚合最新文章、热门分类、站点统计等多个数据源。

确认范围后,先做一件事:保留修改前的状态。把原文件复制一份,记录当前页面的响应时间,最好截图保存页面效果。这样改完缓存后,能直接对比前后差异,出了问题也能快速回滚。

核心处理逻辑是:设置短期缓存,并在内容更新时主动清除。所谓短期,不是固定的数值,而是根据内容更新频率来定。比如站点配置可能一周才改一次,缓存一天都没问题;但最新文章列表,每发一篇新文章就要立即更新,缓存时间就不能太长,或者在发布文章时主动删除对应缓存。

一个可落地的PHP处理逻辑

以首页的分类树为例,这个数据通常来自数据库,每次访问都要查询,但实际变化频率很低。可以用文件缓存保存查询结果,设置一个合理的过期时间,同时在后台修改分类时主动删除缓存。

下面是一个原生PHP的示例,演示了“先读缓存,没有则查询并写入”的基本逻辑:

```php
<?php
// 缓存文件路径,可按业务拆分为多个key
$cacheFile = __DIR__ . '/cache/category_tree.php';
$expire = 3600; // 缓存有效期:1小时

// 1. 尝试读取缓存
if (is_file($cacheFile) && (time() - filemtime($cacheFile)) < $expire) {
$categoryTree = include $cacheFile;
} else {
// 2. 缓存不存在或已过期,查询数据库
$pdo = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
$stmt = $pdo->query('SELECT id, parent_id, name FROM category ORDER BY sort_order');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 3. 构建树形结构(简化示例,实际需递归处理)
$categoryTree = buildTree($rows);

// 4. 写入缓存文件
file_put_contents($cacheFile, '<?php return ' . var_export($categoryTree, true) . ';');
}

// 5. 后续代码直接使用 $categoryTree
```

这段逻辑的关键在于:每次请求先检查缓存文件是否存在且未过期,命中就直接返回,避免查询数据库;未命中才执行查询并重建缓存。后台修改分类时,只需要执行一句 unlink($cacheFile),下次请求就会自动重新查询。

容易出错的位置

第一类是缓存键设计不合理。如果只用固定文件名,不区分数据来源或版本,那么修改了数据结构后,旧缓存可能还在生效,导致页面报错或显示旧字段。建议在缓存文件名中加入数据版本号,比如 category_tree_v2.php,结构变更时同步更新版本号。

第二类是只缓存了成功结果,忽略了空数据的情况。假设分类表是空的,查询结果为空数组,如果把这个空结果也缓存起来,那么后台新增分类后,缓存未过期之前,前台始终看不到新分类。处理办法是:只有查询结果非空时才写入缓存,空结果直接返回,不缓存。

第三类是清理缓存不彻底。很多个人网站后台有“更新缓存”按钮,但只清理了部分缓存,遗漏了首页统计、侧边栏组件等位置。建议把缓存清理逻辑集中到一个函数里,每次内容更新时统一调用,而不是在多个地方分别写删除逻辑。

如何检查缓存是否生效

改完缓存后,不能只看页面“能打开”就结束。检查分两步:

第一步,确认缓存确实命中。在PHP代码里临时加一行日志,记录每次请求是“读取缓存”还是“查询数据库”,访问页面几次后查看日志,如果每次都显示“查询数据库”,说明缓存没有生效,可能是文件路径写错或权限不足。

第二步,验证内容更新是否及时。在后台修改一条分类名称,然后立即刷新前台页面,确认新名称已经显示。如果仍然显示旧名称,说明缓存没有在内容更新时被清除,需要检查后台修改逻辑是否调用了缓存清理函数。

另外,注意缓存文件的写入权限。PHP进程需要对该目录有写权限,否则缓存文件创建失败,代码会每次走数据库查询,缓存形同虚设。检查方法很简单:在浏览器访问页面后,查看缓存目录下是否生成了对应文件。

维护记录比缓存本身更重要

个人网站的缓存方案不需要很复杂,但一定要留下记录。写明改动了哪些文件、缓存的有效期是多少、后台哪些操作会触发缓存清理、出现问题时如何手动清除缓存。这份记录不用很长,几行字即可,但半年后服务器迁移或网站改版时,能帮你快速回忆起当时的判断依据。

如果以后想继续优化,可以关注两个方向:一是把文件缓存替换为内存缓存,适合查询量更大的场景;二是对文章详情页做页面级缓存,减少PHP解析开销。但在那之前,先把当前这层数据库查询缓存做好,个人网站的响应速度通常已经有明显改善。

评论

登录后可发表评论。