社区积分体系对接踩坑:从"发帖成功却不加分"到接口幂等性兜底的全流程复盘

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

上周终于把社区的发帖、回帖、积分变动三个模块的接口彻底捋顺了,中间踩的坑比我想象的多得多。记录一下,给同样在折腾社区联动的站长提个醒。

最开始的需求很简单:用户发帖加10分,回帖加3分,被点赞加1分。我吭哧吭哧写了三个接口,分别调用积分服务的/api/credit/add,本地测试一切正常,上线第二天数据库里同一笔发帖记录对应了五条积分流水。

查日志才发现是前端防抖没做好,用户狂点提交按钮,后端接口被调了五次。我第一反应是给按钮加loading,但转念一想,这治标不治本——网络抖动、重试机制、定时任务补偿,任何一个环节都可能再次触发重复加分。

于是给积分接口加了幂等键,用业务类型:业务ID:用户ID做唯一索引,比如post:6181:42。重复请求直接返回"已处理",但这里又埋了个雷:MySQL唯一索引冲突时抛异常还是静默忽略?我选了后者,结果排查问题时完全看不到重复请求的轨迹,后来改成先SELECT再INSERT,重复的记录单独写一张幂等日志表,方便审计。

回帖的联动更麻烦。用户A回复了帖子,要同时触发:帖子回复数+1、楼主消息通知、A的积分+3。一开始我三个操作顺序执行,通知服务挂了,积分和回复数已经改了,数据不一致。改成ThinkPHP6的数据库事务包裹,但通知是HTTP调用,事务里嵌外部请求,锁等待时间暴涨。最后的方案是事务里只保证回复数+积分原子性,通知扔队列异步,队列消费失败有独立重试,和主流程解耦。

还有个冷门坑:积分变动后用户等级可能跨档,前端个人中心要实时刷新。我一开始在积分接口里同步计算等级,P99延迟从80ms飙到400ms。后来把等级计算拆成监听积分变动的异步事件,但用户刚发完帖点进个人中心,等级还没更新过来,体验很差。折中方案是接口返回"预估等级",异步计算完成后如果实际等级有差异,推一条WebSocket修正,没WebSocket的场景就下次请求时刷新。

现在回头看,社区模块联动最难的不是某个单点,而是状态最终一致性的权衡。强一致性性能扛不住,纯异步用户体验又断层,没有银弹,只能根据业务敏感度逐个场景拍板。

你们社区模块是怎么处理这种分布式事务的? Saga还是干脆不纠结最终一致?想听听实际跑起来的方案,纸上谈兵的文章看多了,想看点带真实QPS数字的经验。

评论0
回复 · 0
还没有回复
微信客服 微信客服