You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Queue与MongoDB的点赞系统数据一致性问题咨询

问题1:引入AWS SQS解决一致性问题是否可行?

可行,但属于成本较高的非最优方案。
你需要对SQS做按帖子ID的分区路由,保证同一帖子的所有点赞/取消点赞操作都进入同一队列分区,且单分区仅由一个消费者串行消费,才能从根源避免并行更新的竞争问题。但该方案会额外引入队列重试、死信处理、计数更新延迟(用户点赞后可能数秒才能看到计数变化)等复杂度,仅适合并发极高且可以接受短时间计数不一致的场景。

问题2:队列订阅者扩容后是否还会出现计数不一致?

如果未做分区路由逻辑,直接扩容消费者节点一定会出现计数不一致。
多个消费者会同时拉取到同一帖子的多条点赞操作,并行执行读-改-写流程,和你原本的并发问题完全一致。只有保证同一帖子的所有操作永远由同一个消费者处理、或增加分布式锁保证同一时间仅一个消费者处理同一帖子的操作,扩容后才能保持一致性。

问题3:更合适的解决方案有哪些?

根据你的技术栈,优先推荐以下方案,复杂度从低到高:

  • MongoDB原子操作(优先选择):你原本的问题根源是「先读计数再修改写入」的非原子操作,直接用MongoDB原生的$inc原子操作符即可解决,完全不需要引入额外组件。示例代码:
    // 点赞
    await db.collection('posts').updateOne(
      { _id: postId },
      { $inc: { likeCount: 1 } }
    )
    // 取消点赞把1改为-1即可
    
    数据库层面会自动串行执行同一条记录的更新操作,不会出现计数错误,性能足以支撑绝大多数中小规模应用的并发需求。
  • Redis缓存+异步落库:如果单帖子点赞并发超过MongoDB单文档更新性能上限,可以用Redis的INCR/DECR原子操作先更新缓存中的点赞计数,同时写入用户点赞状态,再异步批量将缓存计数同步到MongoDB。该方案性能极高,同时可以用缓存直接响应计数读请求,降低数据库压力。
  • 乐观锁补偿:如果有特殊场景必须先读后写,可以给帖子文档增加version版本字段,每次更新时携带当前版本号作为查询条件:
    const updateRes = await db.collection('posts').updateOne(
      { _id: postId, version: currentVersion },
      { $inc: { likeCount: 1 }, $set: { version: currentVersion + 1 } }
    )
    
    若更新返回的匹配行数为0,说明有其他请求先修改了数据,执行重试即可。该方案高并发下重试率较高,仅适合并发较低的场景。

问题4:主流社交平台如何解决点赞计数不一致问题?

主流平台的核心思路是「分层拦截+原子更新+最终一致」:

  • 接入层先做请求过滤,拦截同一用户短时间内对同一帖子的重复点赞请求,减少无效后端请求。
  • 计数读写分离:读请求全部走多级缓存(内存缓存+分布式缓存+CDN),不会直接查库;写请求全部走原子操作,避免竞争。
  • 热点数据特殊处理:热度极高的帖子的点赞操作会先写入内存队列,批量合并后再更新数据库,比如100次点赞合并为一次计数+100的更新,大幅降低数据库压力。
  • 后台定期校验:定时任务会定期用用户点赞关联表的统计值修正帖子的计数字段,解决极端场景下的计数偏差,保证最终一致性。

内容的提问来源于stack exchange,提问作者Raghav Mishra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 22:24:02