社区发帖接口接入现有系统后,回帖通知推了整宿才推完三千条

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
站长杂谈 132 浏览 1 回复

上周把社区模块的回帖通知接进主站消息中心,本以为就是个循环查库+调推送接口的体力活,结果凌晨两点被阿里云短信余额告警炸醒——三千条通知,推了六个多小时还没完,账单先扛不住了。

问题出在"联动"这两个字上。我原来的设计是:回帖落库 → 触发事件 → 遍历该帖所有参与用户 → 逐个写消息表 → 调第三方推送。本地测试十条数据跑得飞快,上线后一个热帖两百多层楼,参与用户去重后八百多人,每次回帖都要扫一遍历史记录,还要防重复通知。更坑的是第三方推送接口有 QPS 限制,我没做令牌桶,直接裸调,超频了就重试,重试又超频,死循环了。

第二天改成异步队列削峰,Redis List 做缓冲,消费者端用滑动窗口控速。但新的坑来了:消息表主键是自增 ID,队列里只存了帖子 ID 和用户 ID,消费者批量插入时,需要回查消息表确认"这条回帖通知是否已经发过"。这个查库又成了瓶颈,而且如果队列积压,用户可能先看到回帖内容,半小时后才收到"有人回复了你"的推送,体验很割裂。

最后换成"写时标记"方案:在帖子参与用户表加个字段 `last_notify_reply_id`,每次回帖只更新这个标记,不立即发通知。定时任务五分钟扫一轮,把 `last_notify_reply_id > notified_reply_id` 的用户批量推进队列。这样单次回帖只改一行,通知延迟固定在五分钟内可接受,队列长度也变得可预测。

积分接口那边倒是顺一些,但踩了个"幽灵并发"。用户发帖奖励积分,我用的先查余额再加减,PHP-FPM 多进程下两个请求同时读到 100 分,都加成 110,实际应该 120。以为是事务问题,上了 `SELECT FOR UPDATE` 还是偶发,最后发现表引擎是 MyISAM……迁移到 InnoDB 后解决。这锅得怪三年前某个外包兄弟的"优化",他大概觉得 MyISAM 查得快。

现在社区模块和主站的消息、积分、用户体系全打通了,但接口文档还是手写的 Markdown,每次改字段要翻三个群找对接人。最近在试把控制器层的入参校验抽成 JSON Schema,配合 Postman 自动化测试,至少能保证"接口没挂"这个底线。有兄弟做过类似的接口契约管理吗,求指条明路。

评论1
回复 · 1
风信子
风信子 超管 志愿先锋新站启章 · #1 ·
感谢分享!
微信客服 微信客服