找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 28|回复: 0

[维护日志] [2026-06-16] [修复] [Redis缓存失效] - 修复帖子回复后页面不跳转/显示旧数据问题

[复制链接]
  • 打卡等级:本地老炮

9337

威望

7448

金钱

1万

贡献

管理员

自由的灵魂

积分
107434
主题
5630
回帖
26661
注册时间
2003-4-10
最后登录
2026-10-2
发表于 2026-6-16 15:05:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

1、问题缘起

现象:
用户反馈回帖后页面不自动跳转到新回复,必须手动清空Redis缓存后才能看到新内容,但问题会反复出现。

初步判断:
Redis缓存与数据库状态不一致。数据库已成功写入新回复,但缓存未失效,导致页面仍展示旧的缓存数据。

排查过程:
  • 检查发帖/回帖核心文件 source/function/function_post.php。
  • 发现 updatethreadcount() 和 updateforumcount() 函数在更新数据库后,没有任何清理Redis缓存的操作。
  • 进一步发现 updateattach() 函数在更新附件状态后,同样缺失缓存清理逻辑。
  • 确认这是Discuz! X3.5(20250901版本)在Redis缓存失效机制上的一个设计遗漏。




2、解决方案

(1)简要技术分析
采用Cache-Aside Pattern(旁路缓存)的精准失效策略:在数据库写入成功后,立即删除(而非全量清空)该操作对应的Redis键。下次读取数据时,系统会自动从数据库回填最新数据至缓存,以此保证数据一致性,且性能损耗极小。

(2)修改文件列表
文件路径操作修改位置
/www/wwwroot/www.dianbo.org/source/function/function_post.php修改updatethreadcount() 函数末尾
/www/wwwroot/www.dianbo.org/source/function/function_post.php修改updateforumcount() 函数末尾
/www/wwwroot/www.dianbo.org/source/function/function_post.php修改updateattach() 函数末尾


(3)关键作用代码段全文

修改点一:updatethreadcount() 函数(约第330行)
  1. function updatethreadcount($tid, $updateattach = 0) {
  2.     // ... (省略原有数据库更新逻辑) ...
  3.     C::t('forum_thread')->update($tid, $data);

  4.     // [缓存修复] 回帖后精准清理该帖子的Redis缓存
  5.     if(function_exists('memory') && memory('check')) {
  6.         memory('rm', 'forum_thread_' . $tid);   // 清理帖子主信息缓存
  7.         memory('rm', 'forum_post_' . $tid);     // 清理帖子回复内容缓存
  8.         memory('rm', 'forum_threadlist_' . C::t('forum_thread')->fetch_thread($tid)['fid']);  // 清理该版块帖子列表缓存
  9.     }
  10.     // [/缓存修复]
  11. }
复制代码


修改点二:updateforumcount() 函数(约第312行)
  1. function updateforumcount($fid) {
  2.     // ... (省略原有数据库更新逻辑) ...
  3.     C::t('forum_forum')->update($fid, $setarr);

  4.     // [缓存修复] 版块统计更新后精准清理该版块的Redis缓存
  5.     if(function_exists('memory') && memory('check')) {
  6.         memory('rm', 'forum_forum_' . $fid);   // 清理版块信息缓存
  7.         memory('rm', 'forum_forumlist');        // 清理版块列表缓存
  8.     }
  9.     // [/缓存修复]
  10. }
复制代码


修改点三:updateattach() 函数(约第160行末尾)
  1. C::t('forum_thread')->update($tid, array('attachment'=>$attachment));
  2. C::t('forum_post')->update_post('tid:'.$tid, $pid, array('attachment' => $attachment), true);

  3. // [缓存修复] 附件状态变更后精准清理该帖子的Redis缓存
  4. if(function_exists('memory') && memory('check')) {
  5.     memory('rm', 'forum_thread_' . $tid);   // 帖子主信息缓存(含attachment字段)
  6.     memory('rm', 'forum_post_' . $tid);     // 帖子回复内容缓存
  7. }
  8. // [/缓存修复]
复制代码





3、最终实现效果

场景修改前修改后
普通回帖数据库更新,Redis缓存未失效,页面显示旧数据。数据库更新后立即清理对应缓存,下次读取自动回填。
带附件回帖attachment字段变更但缓存未更新,附件状态显示异常。附件状态变更后缓存即时失效,状态同步更新。
版块统计更新版块最后回复/帖子数显示严重滞后。版块缓存精准失效,统计数据实时同步。
性能影响无。每次操作仅删除2-3个Redis键,O(1)操作,耗时在微秒级,可忽略。
是否需要手动清理Redis需要,且问题会反复出现。不需要,由系统自动完成精准失效。





4、重要技术沉淀(固化摘要)

  • Discuz! X3.5 缓存缺陷: 核心函数 updatethreadcount()、updateforumcount()、updateattach() 均存在“写数据库但不清理缓存”的设计遗漏,这是官方版本的一个已知问题。
  • Cache-Aside Pattern 实践: 在写操作后,必须主动失效(Invalidation)对应的缓存键,而不能单纯依赖TTL过期或全量清空。
  • 精准失效优于全量清理: 使用 memory('rm', 'key') 仅影响单条记录,比执行 flushall 或批量删除键值要安全、高效得多。
  • 核心文件定位: function_post.php 是发帖、回帖、附件处理的核心文件,未来任何涉及帖子状态变更的修改,都必须检查并补充相应的缓存失效逻辑。




5、进一步优化的可能性

优化方向说明优先级
给Redis缓存加TTL兜底在 config_global.php 中设置 $config['memory']['redis']['ttl'] = 3600,即使失效逻辑有遗漏,缓存也能自动过期,作为最终防线。低(当前修复已足够)
增加监控脚本编写一个检测“帖子回复数与缓存内容”是否一致的脚本,发现异常时自动清理对应的缓存键,作为兜底方案。低
检查其他核心表排查 source/class/table/ 目录下,其他表的 update/insert 操作是否存在类似的缓存失效遗漏。中
升级到官方补丁版持续关注Discuz!官方是否发布X3.5的Redis缓存修复补丁,以便后续跟进。中

不懂就搜!点此搜点拨论坛。如果本坛没有,请尝试点此问AI,或跟帖提问。
发帖前注意看置顶帖。
不定期借助AI对点拨论坛陈年老帖进行挖坟回复,打扰勿怪!
学然后知不足,教然后知困。知不足,然后能自反也;知困,然后能自强也。故曰:教学相长也。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|点拨论坛 |网站地图

GMT+8, 2026-10-2 02:04 , Processed in 0.061537 second(s), 5 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表