点赞与点赞列表方案设计
背景概况
点赞系统是社交平台或内容平台中常见的功能,用户通过点赞来表达对内容的喜好。为了高效地处理大量用户的点赞请求并快速展示点赞列表,需要设计一个高效的点赞存储与查询系统。
点赞流程
- 判断点赞对象是否存在:检查要点赞的内容是否存在。
- 检查是否已经点赞:判断当前用户是否已经对该内容进行过点赞。
- 没有点赞:如果用户没有点赞过,执行以下操作:
- 操作 Redis ZSET 进行点赞记录。
- 发送消息队列(MQ)将数据持久化到数据库。
如何判断是否已被点赞?
Redis Set 存储点赞记录
每个用户维护一个 Set 集合,记录该用户已点赞的内容 ID。
-
优点:
- 操作简单。
- 查询速度快。
-
缺点:
- Redis Set 存储较大数据时,内存占用较高,尤其是当用户量和点赞数很大时。
Redis Bitmap
实现原理:
Bitmap 是一种基于位操作的结构,可以高效地存储某一集合内元素是否存在的信息。对于每个用户,使用一个 Bitmap,每个用户在该 Bitmap 中占用一段连续的位,表示其对某个内容是否点赞。
-
优点:
- 内存占用非常小。
- 查询效率高。
-
缺点:
- 需要设计合理的 ID 和位图偏移策略。
- Bitmap 操作的颗粒度限制在二进制位,无法进行复杂的多维数据处理。
- 不支持删除或取消点赞,一旦用户点赞,就无法撤销。
对于海量用户或大量点赞数据的场景,Bitmap 是一个较为合适的选择,但对于取消点赞的需求无法很好支持。
查询数据库
将点赞信息直接存储在数据库中,并根据用户与内容进行查询。
-
优点:
- 数据存储稳定,适合小规模应用。
-
缺点:
- 在高并发场景下,数据库压力较大。
- 查询与写入性能较低,不适合应对大规模的点赞操作。
由于数据库的查询性能无法满足高并发的需求,本文不推荐使用数据库查询点赞记录。
Redis Bloom Filter(布隆过滤器)
实现原理:
布隆过滤器是一种空间效率高的概率型数据结构,能够判断某个元素是否在一个集合中。布隆过滤器可以用来判断某个用户是否可能已经点赞过,具有一定的误判率(误报)。
-
优点:
- 显著减少内存消耗,适合海量用户场景。
- 查询效率高,适合处理大规模数据。
-
缺点:
- 存在误判(false positive),即可能判断出用户已经点赞,但实际上并未点赞。
- 不支持取消点赞功能。一旦用户点赞,该信息无法撤销。
布隆过滤器适用于需要快速判断是否存在且能容忍一定误差的场景,但其误判问题和无法取消点赞的缺点也需要注意。
点赞列表设计
在社交平台中,用户可以查看自己对内容的点赞列表。点赞列表通常没有数量限制,但由于平台用户数可能极为庞大,使用数据库查询显然不够高效。因此,使用缓存是必不可少的。
点赞列表的特点:
- 近期点赞内容曝光率高:最近被点赞的内容在短时间内被再次查看的几率较高。
- 过久的点赞内容曝光率低:点赞时间较久的内容,曝光率较低。
优化方案:
为提高查询效率,可以将最近被点赞的内容(如前 10 页的点赞记录)存储在 Redis ZSET 中。超过第 10 页的点赞记录,则需要通过数据库查询获取。
具体设计:
- 使用 Redis ZSET 存储点赞记录,其中每个元素表示一个用户对某个内容的点赞记录,ZSET 的分数(score)可以表示点赞的时间戳。这样,点赞时间越近的记录分数越大。
- 当用户查看点赞列表时,首先从 Redis 中获取前 10 页的点赞记录,剩余的部分则从数据库中查询。
- 利用 Redis 的有序集合(ZSET)特性,可以高效地实现按时间排序的点赞记录查询。
流程:
- 用户请求查看点赞列表:
- 查询 Redis 中的 ZSET 获取前 10 页的点赞记录。
- 对于超过第 10 页的记录,从数据库中查询并返回。
- 当用户进行点赞时:
- 在 Redis 中的 ZSET 中记录该用户对内容的点赞。
- 通过 MQ 异步将点赞数据持久化到数据库。
总结
- 对于 高并发和海量用户 的场景,推荐使用 Redis 的 Bitmap 或 布隆过滤器 来判断是否已经点赞,能显著减少内存消耗并提高查询效率。
- 点赞列表 使用 Redis ZSET 存储前 10 页的点赞记录,超过的部分通过数据库查询获取。ZSET 通过按时间排序的方式,能够高效地查询最近的点赞记录,避免全量查询带来的性能瓶颈。
通过这样的设计,系统能够在保证高并发情况下,提供流畅的点赞体验,并且具备较高的扩展性。