朋友圈点赞功能如何实现,简单说说?
- 标签:后端、系统设计、场景题
🏛 业务架构师
朋友圈点赞看起来是道小题,但它是社交激励闭环的一环,我会从数据模型、可用性取舍、防刷三面答,重点讲清"点赞该选 AP 还是 CP"。
数据模型
- 点赞关系:
(用户ID, 内容ID, 时间),写 Redis Set(like:{postId}存用户集合)+ 计数器(like:count:{postId}INCR/DECR) - 异步落库(MySQL 唯一索引保证幂等)做持久化和分析
- 自己是否点过赞:
SISMEMBER毫秒级判断
核心架构判断:点赞业务选 AP
- 点赞数偶尔少显示几个、短暂不一致,用户无感知也无伤害——它天然适合缓存抗读写、异步持久化、最终一致
- 对比:支付就不能这么设计。识别"这个业务能不能容忍不一致"是方案分档的第一步
- 大 V 内容百万赞:精确计数没必要,展示"1.2 万"这种模糊值 + 定期校准即可,省下的存储和计算是真金白银
必须答的工程点
- 幂等与取消:重复点赞(Set 去重)、取消赞(SREM + DECR)的原子性,用 Lua 保证
- 防刷:单用户对同一内容点赞频率限制、批量异常点赞(新号一天点 1 万个)进风控——点赞是刷量灰产的重点目标(买赞做营销),异常流量要能识别和清洗
- 通知链路异步化:点赞通知走 MQ,"XXX 赞了你"的推送延迟几秒无感知
业务视角收尾:点赞数据的产品价值在于内容热度排序和作者激励——它喂给推荐系统的互动信号价值不低于阅读时长,所以落库的数据规范(维度、时间)一开始就要为分析设计,别只当关系数据存。
🏗 系统架构师
点赞是高频写 + 高频读的计数问题,我按数据规模分档设计。
1. 读写模型(百万级日点赞,秒级实时)
- 计数:Redis
INCR like:post:{postId}/ 点赞取消DECR,扛写压力 - 谁点过赞:Redis Set
SADD like:post:{postId}:users {userId},用于判重、取消、展示前 N 个点赞人 - 用户维度反查(我赞过哪些):
ZSet like:user:{userId}存帖子与时间,朋友圈"我的赞"页要用 - 判重必须先查后写用原子性保证:Set 的
SADD返回 0 表示已点过,直接幂等,不依赖"先查再改"
2. 异步落库(持久化与审计) Redis 只是热层:点赞事件发 MQ,消费者批量聚合落 DB(点赞关系表 post_id + user_id 联合唯一索引,计数表按 post 聚合)。批量 upsert,DB 写 QPS 降两个数量级。Redis 与 DB 的计数以 DB 为准做定时校准。
3. 亿级量级的优化
- 计数膨胀:单条朋友圈赞数过亿不现实,但热点内容会到千万级——
INCR本身 O(1) 无所谓;真正的问题是热点 key 单分片 CPU 瓶颈,用计数分片(like:post:{id}:{0..N}随机加分片,读时 SUM)打散 - 关系数据归档:冷数据(30 天前的)从 Redis 淘汰到 DB/对象存储,判重走 DB 唯一索引
- 朋友圈查看走预渲染的 feed 缓存,点赞数变化时只刷新该条缓存,避免每次读都实时聚合
一致性口径:点赞是"最终一致可接受"的典型,展示数允许短暂滞后,但判重必须强一致(否则重复点赞),这个边界要讲清楚。
💻 全栈开发专家
点赞是典型的高并发写 + 读多写少,我的方案:Redis 为主存,异步落库,计数用独立结构。
数据结构
who liked: SADD like:post:{postId} {userId} -- 去重靠 Set
count: like:post:{postId}:count INCR/DECR -- 独立计数,别实时 SCARD核心逻辑(Lua 保证原子)
lua
-- 点赞:成功加入才计数,天然幂等
if redis.call('SADD', KEYS[1], ARGV[1]) == 1 then
return redis.call('INCR', KEYS[2])
end
return redis.call('GET', KEYS[2])
-- 取消:SREM 成功才 DECR异步落库
点赞消息发 MQ(或本地消息表),消费者批量写 post_like(post_id, user_id) 唯一索引兜底,同时更新 post.like_count。DB 只是审计与兜底,在线读写全走 Redis。
页面展示
- 数量:count key,缺口用 DB 补。
- "是否点赞过":列表页批量
SISMEMBER不行(N 次),改用管道 pipeline 或把用户点赞过的 postId 集合另存一份user:like:{userId}反向 Set,双向结构换查询效率。 - 点赞列表(谁赞过我):
SMEMBERS分页用SSCAN,别一次全拉。
踩过的坑
- 明星官宣场景瞬时百万点赞:先写 Redis + 限流,落库批量聚合(一条 SQL 更新计数),否则 DB 直接被打穿。
- count 与 Set 不一致要靠定时校验任务(SCARD vs count)修复。