4.1 缓存机制与更新缓存的正确姿势

搞清Discuz! 缓了什么、什么时候该清、什么时候清就是自伤。

4.1.1 Discuz! 到底缓了什么

Discuz! 的缓存不是「一块黑盒内存」,而是四类东西堆在 data/cache/ 目录里,各管一段路。分清这四类,后面所有「改了没生效」的毛病都能自己定位。

缓存类型 落盘位置(以你的版本为准) 缓的是什么 谁让它失效
模板编译缓存 data/cache/ 下的模板编译文件 template/{标识}/ 里的模板编译成的 PHP 代码 改模板文件后更新缓存
数据缓存 data/cache/、data/cache/data.php 这类文件 后台设置项、用户组权限、版块列表、导航等读多写少的数据 后台改设置时自动重建
数据表缓存 Table 类(C::t('xxx'))在内存中的对象副本 主键查询命中的那一行记录 表数据变更时按 TTL 或显式失效
内存缓存 单次请求内共享的 $_G 全局变量池 同一个请求里反复要用的东西,比如 $_G['setting'] 请求结束即释放

打个比方:数据缓存是图书馆的书目卡——书还在架上,但你改了目录,卡得重抄一遍;模板编译缓存是排好的铅字版,改一个字就得重新排一次。卡齐了就是快,卡缺了就是慢,而「重抄目录」本身要消耗数据库,一不小心就把管理员累趴了。

4.1.2 后台更新缓存入口的每一项

后台路径:界面 → 更新缓存(部分版本在「工具」分组下)。进不去这条路径时,开发者模式能帮上忙:config/config_global.php 末尾加 $_config['plugindeveloper'] = 1;。

  • 数据缓存:重建上面那张书目卡。后台改了站点设置、用户组、版块属性之后走这一项。
  • 模板缓存:清掉 data/cache/ 里的编译产物,下次访问重新编译。模板编译由 source/class/class_template.php 完成。
  • 语言包缓存:刷新 {lang xxx} 调用到的语言条目。语言包文件本身在 source/language/。
  • 分类信息缓存:主题分类、扩展分类的父子结构。这项慢且冷门,不确定就别勾。
  • 全部缓存:上面所有项一起做,日常维护里最该避免的就是无脑点它。

4.1.3 什么时候必须更新缓存

这几类改动,缓存不更新就等于没改:

  • 改了 template/{标识}/ 下任何模板文件(含 common/header、手机版 touch/ 目录)。
  • 新增或修改语言包:系统语言包 source/language/、模板语言包 template/i18n/SC_UTF8/lang_template.php、插件语言包 data/plugindata/{标识}.lang.php。
  • 插件里执行了建表、改表结构的 runquery()。
  • 整包升级 / 打补丁,尤其是 X3.5 升 X5.0 这种跨大版本(X5.0 不再兼容 X3.5 及更早,老插件和模板必须改造)。
  • 安装、启用、禁用、卸载插件后,或改了 config/config_global.php 里的开发者模式开关(查预定义钩子时值改成 2 也要更新一次)。

4.1.4 什么时候千万别更新缓存

高流量站点上,「更新缓存」不是免费动作。它会在几秒内让大量请求同时打向数据库重建缓存文件,这是典型的缓存击穿——缓存刚被清空,所有人一起涌上来,2C4G 的小机器很可能直接卡住。

结论:没人在线的时候更新,能夜里做就别在白天做。 论坛日活低谷通常在凌晨 3 点到 6 点。

# 看当前 data/cache 有多大、文件有多少个
du -sh /www/wwwroot/你的站点/data/cache
ls -1 /www/wwwroot/你的站点/data/cache | wc -l

# 更新前留一份可回滚的快照(放在站点目录外,别让 Web 访问到)
cp -a /www/wwwroot/你的站点/data/cache /root/backup_discuz_cache_$(date +%Y%m%d_%H%M%S)

4.1.5 操作 → 是否需要更新缓存 速查表

改了什么 要更新哪一项 常见误区
模板文件(.htm/.php) 模板缓存 只刷新浏览器按 Ctrl+F5,前台还是老样子
系统语言包 语言包缓存 以为改了 .php 就自动生效
插件语言包 数据缓存 插件没重装,缓存里还是旧字符串
插件安装脚本 / 建表 数据缓存 只清模板不建索引,前台依旧报错
后台站点设置、SEO 设置 一般自动重建,无需手动 反复点全部缓存,纯属浪费数据库
手工UPDATE 直接改库 数据缓存 数据改了但读到的是旧缓存值
升级 Discuz! 版本 全部缓存 只清模板,表结构没对齐
日常发贴、回帖 不需要 每次操作都清一次,数据库直接扛不住

4.1.6 常见故障排查

症状一:改了模板前台没变化。 九成是模板缓存没清;剩下的一成是改错了套系——后台当前启用的模板标识符和你改文件的目录不是同一个。

症状二:data/cache/ 涨到几个 GB。 大多是模板缓存碎片与过期数据缓存堆积。清空后如果反复涨这么快,说明某处代码在高频写缓存文件,值得开 data/log/ 看日志。

症状三:清完缓存第一分钟很慢。 这是正常现象。缓存是空的,接下来每个页面都要重新编译模板、重新查库回填。别在这个窗口里下结论说「更新缓存把站点搞慢了」。

症状四:并发下缓存击穿。 表现是数据库 CPU 瞬间 100%、站点打不开。有 Redis/Memcached 时把数据缓存交给内存缓存;没有就把更新动作挪到低谷时段。

症状五:缓存文件写不进去。 缓存文件属主必须和 PHP-FPM 进程一致,data/ 及其子目录要可写。

<?php
// 放进插件的 .inc.php 或定时任务脚本,用系统自己的接口读写数据缓存
define('IN_DISCUZ', true);
define('DISCUZ_ROOT', dirname(dirname(dirname(__DIR__))));

require './source/class/class_core.php';
$discuz = C::app();
$discuz->cachelist = [];
$discuz->init();

$setting = loadcache('setting');   // 读:命中返回数组,未命中返回 false
savecache('mysite_hotthreads', ['data' => range(1, 10), 'time' => TIMESTAMP]);
C::t('myplugin_log')->insert(['uid' => 1, 'note' => 'demo']);

4.1.7 一条日常维护动线

固定成流程,比记哪些缓存要清更省脑子:

  1. 改什么 —— 先确认改的是模板、语言包,还是插件的表结构。
  2. 做什么 —— 只勾对应的那一项缓存。拿不准、又没别的正事在跑,再上「全部缓存」。
  3. 怎么验证 —— 硬刷新(Ctrl+F5)目标页面;看 data/log/ 有没有新报错;最后用一个未登录的干净会话确认渲染正常。
  4. 留痕迹 —— 记一行「改了什么、清了哪项、结果如何」到运维笔记。

把这套动线走顺了,缓存就从一个「玄学按钮」变成一件顺手的事。