Redis点赞功能到底咋实现的,有啥特别技巧没说清楚呢
- 问答
- 2025-12-25 15:49:11
- 2
说到Redis实现点赞功能,网上很多文章都说了个大概,比如用集合(Set)来存谁点了赞,用字符串(String)来计数,这没错,但就像只告诉你怎么把米放进电饭锅,却没告诉你怎么控制火候才能煮出香喷喷的米饭,这里头有几个关键技巧和容易踩的坑,咱们来细说。
第一,为啥非要用集合(Set),而不用列表(List)?
很多新手会想,点赞记录不就是一条条往里加吗?用List的LPUSH也行啊,这里的关键在于“唯一性”,一个人只能点一次赞,重复点赞要算作取消,Set天生就去重,你用SADD命令给一个帖子(比如帖子ID为post:123)添加用户ID(比如user:456),无论你加多少次,集合里都只会有user:456这一个值,你再用SISMEMBER命令查一下这个用户在不在集合里,就能立刻知道他是否点过赞,最后用SCARD命令统计集合的大小,就是点赞总数。
如果用List,你得先遍历整个列表检查用户ID是否存在,才能决定是追加还是删除,这个操作在数据量大时非常慢,而且删除操作也麻烦,Set的自动去重和高效的成员检查,是点赞功能的基石,这是第一个没太说清楚的技巧:选择数据结构的根本原因在于业务逻辑的“唯一性”约束。
第二,点赞数和点赞列表要不要同步更新?怎么保证不出错?
这是个核心问题,你既要记录下谁点了赞(存到Set里),又要更新点赞的总数(存到一个String里),如果先加集合,后加计数,中间万一出错了,计数就会少1,反过来也一样,这就是需要“事务”或“原子性操作”的地方。
网上可能只提用MULTI/EXEC事务,但Redis事务并不是严格意义上的原子性(不像数据库事务,失败会回滚),它只是确保一系列命令按顺序执行,不会被其他命令打断,更优雅的做法是使用Redis脚本(Lua脚本),你可以写一个Lua脚本,把判断用户是否在集合里、添加/移除用户、增减计数这一连串操作,全部写在一个脚本里,Redis会单线程原子性地执行整个脚本,这样就万无一失了,这是第二个关键技巧:使用Lua脚本保证核心逻辑的原子性,避免数据不一致。
第三,怎么应对高并发点赞?比如明星发微博,瞬间几十万点赞。
Set的SCARD命令在集合很大时,性能会有轻微下降,因为它需要遍历整个集合?(其实不对,Redis的Set在存储整数且范围较小时是使用intset编码,非常高效;即使是大集合,SCARD也是O(1)时间复杂度,因为它在内部维护了大小),这里真正的瓶颈不一定是SCARD,而是大Key问题。
如果一个帖子有几百万甚至上千万点赞,这个Set本身就会成为一个巨大的Key,占用很多内存,在进行SADD、SREM操作时可能会短暂阻塞Redis的其他请求,对于这种“爆款”内容,一个常见的优化技巧是采用“冷热数据分离”。
- 热数据:只保留最近一段时间(比如最近三天)的点赞用户ID在Redis的Set里,这样大部分近期活跃的点赞操作速度依然飞快。
- 冷数据:定期(比如每天凌晨)把旧的、不再变化的点赞Set从Redis里导出来,持久化到MySQL或者其他数据库中,总的点赞数依然保存在Redis里,因为只是一个数字,占用空间极小。
当需要查询一个用户很久以前是否点过赞时,先查Redis里的热数据,如果找不到,再去查后端的冷数据库,虽然查询变慢了点,但保证了Redis核心服务的高性能,这是第三个高级技巧:通过冷热分离,解决“爆款”内容带来的大Key压力。
第四,除了点赞,还有点赞列表(谁赞了)的分页查询怎么做?
直接对一个大Set使用SMEMBERS命令会一次性返回所有成员,网络传输压力大,可能拖慢Redis,正确做法是使用SSCAN命令,SSCAN可以增量式地、分批地遍历整个集合,每次只返回一小部分数据,这样你就可以像翻书一样,一页一页地把点赞列表展示给用户,避免了单次操作的大数据量冲击,这是第四个实用技巧:使用SSCAN进行分页遍历,避免阻塞和网络风暴。
第五,要不要给点赞数据设置过期时间?
Redis内存很宝贵,不能无限期存着所有点赞数据,你可以给存储点赞数的Key和点赞集合的Key设置一个过期时间(TTL),比如一个月,这意味着一个月前的帖子,其点赞详情会被自动清理,只保留最终的点赞总数(这个总数最好在过期前同步到MySQL里),这是一种内存管理的策略。
Redis实现点赞,基础是Set+String,但真正的门道在于:
- 用Set是利用其去重特性。
- 用Lua脚本保证操作原子性。
- 用冷热分离应对大Key问题。
- 用SSCAN命令实现安全分页。
- 用TTL做好数据生命周期管理。
把这些技巧都考虑进去,一个健壮、高效、可扩展的点赞功能才算真正实现。

本文由凤伟才于2025-12-25发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/68249.html
