·更新于 2026年10月25日· 4 次浏览 Node.jsRedisMongoDBNuxt工程实践BUG解决

Node.js 博客评论一夜被灌 500 条:我用 Redis 滑动窗口、内容指纹和异步审核队列止血

一次垃圾评论爆发让我意识到,评论系统不能只靠前端表单和后台人工删。本文记录如何用 Redis 限流、内容指纹去重和异步审核队列,把垃圾评论挡在展示前。

Node.js 博客评论一夜被灌 500 条:我用 Redis 滑动窗口、内容指纹和异步审核队列止血 封面
ZHOUYI

作者

ZHOUYI

早上打开后台,评论表一夜多了 500 条,内容几乎全是推广链接。第一反应不是删,而是先看入口:评论接口没限流,提交后直接入库并展示,等于把门开着。止血思路很快定下来:先挡突发流量,再挡重复内容,最后把展示和审核拆开。

Redis 滑动窗口:先挡住突发请求

最开始我想用简单计数器,但固定窗口在临界点容易被刷穿。改成滑动窗口后,按 IP 统计最近 60 秒内的评论请求,超过阈值就拒绝。这里我用 Redis 的有序集合存时间戳,每次先清过期记录,再判断数量。多实例部署也共享状态,比应用内存稳。不同客户端封装略有差异,以官方文档为准。

js
// 伪代码:按 IP 做 60 秒滑动窗口
const key = 'comment:rl:' + ip;
const now = Date.now();
await redis.zRemRangeByScore(key, 0, now - 60000);
if (await redis.zCard(key) >= 5) return false;
await redis.zAdd(key, now, now + ':' + Math.random());
await redis.pExpire(key, 60000);
return true;

内容指纹:把重复垃圾拦在入库前

垃圾评论常常不是完全一样,只是链接、联系方式换了几次。我先做归一化:去空格、转小写、提取链接数量,再算一个 SHA-256 指纹。指纹在 Redis 里设置 24 小时过期,命中后不直接展示,而是进入待审核。为了避免误伤普通用户重复提交,我会返回“已收到,请勿重复提交”,而不是粗暴报错。

异步审核队列:展示和入库分离

评论先写 MongoDB 的 pending 状态,再通过队列做审核。低风险评论自动通过,高风险评论留在后台人工确认。这样即使机审规则误判,前台也不会立刻被污染。队列消费失败时会重试,超过次数进入死信,避免一条坏数据把消费者卡死。

  1. 先放开只记录日志,观察真实流量,再收紧阈值。
  2. 登录用户和匿名访客分开限流,避免误伤正常互动。
  3. 管理后台加“按指纹批量删除”,处理已漏进来的垃圾。
  4. 限流、指纹、审核状态都放 Redis 或数据库,别只放进程内存。

“这类问题没有银弹:限流挡突发,指纹挡重复,审核链路兜底。先止血,再慢慢把规则调准。”


Guestbook

留言

若这篇文章也曾停在你心上,留一行字吧,我会看的。

先确认一下邮箱

多这一步,是为了少些机器骚扰,也让我能更踏实地读每一条真人写下的字。验证码 10 分钟内有效;同一邮箱 60 秒内只能发一封。

本文留言

共 0 条已加载 0 条

这里还静悄悄的——愿意做第一个留下脚印的人吗?