Yihui’s Blog

如何设计一个点赞系统?

日期:2026-07-11
标签:#面试 #八股 #系统设计 #点赞 #场景题

一句话答案

点赞系统要同时维护用户与对象的唯一关系和可快速读取的计数,高并发写入可先落 Redis/日志再异步汇总,数据库唯一约束保证最终正确。

面试口语版

核心接口是点赞、取消、查询是否点赞和查询点赞数。关系表以 targetType + targetId + userId 唯一,支持幂等;计数是派生数据,可放 Redis 并异步写数据库。高并发时请求先经过限流,用 Lua 原子修改用户点赞状态和计数,再写 MQ 落关系表;或者先可靠写日志,由流处理聚合。读详情时批量查询用户是否点赞,避免 N+1。热门对象要分桶计数或本地缓存,最终通过关系表重算和对账修正计数。

数据模型

like_relation(target_type, target_id, user_id, status, updated_at)
like_count(target_type, target_id, count, version)
唯一键:(target_type, target_id, user_id)

关键细节

  • 点赞和取消是状态设置,不是盲目 +1/-1。
  • 展示计数允许短暂最终一致,用户自己的点赞状态通常要求读己之写。
  • 防刷包括用户/IP/设备限流、异常频率检测和账号风险。
  • 批量列表接口必须批量获取状态和计数。

面试官追问

  1. Redis 成功但数据库落库失败怎么办?
  2. 如何避免重复点赞导致计数错误?
  3. 百万点赞的热门内容如何处理?

面试官追问参考答案

1. Redis 成功但数据库落库失败怎么办?

状态变化必须形成可靠事件,发送失败可通过 Outbox、Redis Stream 或变更日志重试。关系表按唯一键幂等 upsert,定时根据关系明细或事件日志校准计数;不能把一次异步失败当作永久成功。

2. 如何避免重复点赞导致计数错误?

Lua 先检查当前状态,只有从未点赞变为已点赞才加一,从已点赞变为取消才减一。数据库唯一键和状态条件更新再次兜底,所有请求携带业务幂等标识。

3. 百万点赞的热门内容如何处理?

读走多级缓存;单个计数 Key 写热点可按对象和分桶编号拆分,由流处理或读取时聚合。关系明细按 targetId 分片,计数异步合并,展示可容忍秒级延迟并定期校准。

学习清单

  • 区分点赞关系与点赞计数。
  • 能说明幂等、热点和最终一致性。
Maintained by · YihuiEdit on GitHub

Keep reading

View all posts