队列削峰实战:发帖高峰期通知推送的异步化改造

CLARA轻量论坛系统
CLARA轻量论坛系统 星耀SVIP管理员 黑卡会员
发布于 2026-09-16 05:22 ·2 浏览 ·0 回复

结论:在 Clara BBS 这类无框架、无 Composer、无命令行的轻量 PHP 社区里,发帖高峰期的通知推送削峰不靠引入 Redis/RabbitMQ 队列,正确路径是「同步只落一条待办记录 + 用 Cron::register 注册懒触发任务批量消费 + 幂等锁与退避重试」三段式改造。上中间件的收益远小于它带来的部署复杂度。

先定位瓶颈:慢的不是发帖,是发帖之后的 N 次扇出

高峰期一次发帖的耗时,往往 80% 不在写帖子表,而在「@提及通知到人」+「关注版块帖通知」+点赞、礼物、悬赏等一系列 notify 调用。一个被 3000 人关注的版块,一次同步扇出就是 3000 次通知写入。

判断方法很简单:临时把通知调用注释掉压测一次,如果发帖响应从 800ms 掉到 80ms,那削峰对象就确定了。注意 Clara BBS 有发帖/回帖最小间隔的防灌水机制,压测时别被它拦下来误判成性能问题。

第一步:同步阶段只做一次 INSERT,砍掉全部扇出

改造原则是「发帖请求只负责记账,不负责投递」。发帖时不再循环调用 notify,而是往一张通知待办表里写一条「事件记录」:事件ID(帖子ID)、事件类型(新帖/回复/提及)、来源用户、版块ID、时间戳、状态(待处理/处理中/已完成/失败)、重试次数。

一条 INSERT 的代价是恒定的,跟关注人数无关。这一步做完,发帖响应时间就和版块规模解耦了——这是整个削峰改造里收益最大的一步,也最不需要动系统架构。

第二步:用 Cron::register 注册消费者,批量 + 限量执行

消费者写在插件里,用系统的 Cron::register 注册定时任务,它的特点是懒触发、零配置,不需要你去服务器加 crontab。任务逻辑建议:

每轮从待办表捞 N 条(建议 100~200 条一批),展开成实际通知,处理完把状态置为已完成;单轮设置最大执行时长(比如 20 秒),超时主动退出,下一轮接着来。这是因为 PHP 面向前台请求的执行环境对长任务很不友好,宁可多跑几轮,也不要一次跑几分钟被中断后留下半截数据。

同时把版块关注者列表这类高频只读数据用 Cache::remember 缓存起来,避免每轮都全表捞关注关系。缓存本身也让「保存即生效」的插件机制发挥了作用——改完钩子直接生效,不用清缓存重建。

第三步:懒触发任务必须处理三个坑

懒触发意味着任务靠用户访问触发,有人来才跑。所以务必处理以下三点:

一是幂等锁。用 Cache::remember 之类的原子写做任务锁,防止多人同时访问触发多个消费者并发消费同一批数据,导致通知重复发送。

二是补偿触发。纯靠访问触发会有延迟,如果站点此刻流量断崖,通知就会堆积。可以在发帖请求的收尾处尝试触发一次任务(带锁),让高峰期的通知尽快落地,闲时则由访问自然带动。

三是退避重试。失败记录不要丢弃,按重试次数递增延迟重新入队,超过上限再标记为死信,后台可见。同时给同一用户对同一帖子的通知做聚合,避免刷屏。

第四步:验证与回滚

上线后盯三个指标:待办表积压条数是否长期趋近于 0、单轮任务平均耗时、失败重试率。后台「系统工具→计划任务」能看到任务注册与执行情况,把通知异步化的日志也接到这里,出问题一眼定位。

回滚很简单:把插件钩子里的异步写入改回直接调用 notify 即可,因为两者共用同一套通知数据结构,不需要改表、不需要停服。

总结一下:Clara BBS 的通知削峰核心是「同步记账、异步投递、批量消费、幂等重试」。先把扇出从请求线程里挪走,再用 Cron::register 这个零配置的懒触发机制兜底消费,配合缓存与锁解决重复和延迟问题——不引入任何中间件,也能扛住发帖高峰的通知风暴。

本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-392.html
转载请注明出处,版权归原作者所有。

全部回复 0

还没有回复,来抢沙发~