点赞业务设计
点赞
内容点赞是一个非常高频的业务场景,功能本身复杂度不高,但是业务场景多,QPS 高,而且由于社区的用户体量,整体点赞的数据量非常大
点赞服务需要提供的接口有
- 对某个内容点赞(取消点赞)、点踩(取消点踩)
- 查询是否对 单个 或者 一批内容 点过赞(踩) - 即点赞状态查询
- 查询某个内容的点赞数
- 查询某个用户的点赞列表
- 查询某个内容的点赞人列表
- 查询用户收到的总点赞数
其中最核心的主要是
- 用户是否点赞内容
- 内容点赞数
在刷 Feed 流时,每一次下滑,都需要对数十篇内容进行登录用户是否点赞的判断
方案1
用 Redis 的 set 结构进行存储用户 id
contentId: [userId1, userId2, ...]
用 set 的 Sismember
判断用户是否点赞,用 Scard
判断点赞数量
问题:
- 如果是热点数据,点赞用户很多,容易出现大 Key 问题
- 缓存重建的时候需要查询全部点赞用户,容易出现慢查询问题
大 key 的危害
- 对大 key 执行读请求,会使Redis 实例的带宽使用率被占满,导致自身服务变慢
- 对大 key 进行删除操作,易造成主库长时间阻塞
方案 2
对大 Key 进行分片处理,对同一动态下的点赞用户,进行分片再放到缓存里,每次操作缓存时先根据 userId
计算分片值
1 |
|
问题
- 缓存分片仍然维护了被浏览动态下全部点赞数据,Feed 流场景下,用户浏览过的动态,几乎不会再次被浏览
- 一些点赞量多的历史动态,有人访问时会重建缓存,重建成本高,但是用率不高
- 分片增加了业务复杂性,增加了维护缓存的难度
- 分片会导致产生大量的 Key,Key 也会占用内存空间
方案 3
使用 Hash
结构,userId
作为 key
1 |
|
- 之前的方案访问老旧内容会重建缓存,性价比低,而且内容下点赞用户并不是一直活跃或重新访问的,所以先方案要区分冷热数据
contentId
内容 id,是递增的,一定程度上反应了数据的冷热- 缓存中只维护一定时间和一定数量的
contentId
,并增加minContentId
字段用于区分冷热数据 - 对于冷数据,直接访问 DB,不再重建缓存
点赞业务设计
http://showyoubug.cn/2024/07/03/点赞业务设计/