排行榜怎么设计?
排行榜怎么设计?
排行榜是很常见的一个功能,在社交软件、游戏等各种场景中都有应用,积分、点赞、礼
物、战绩排名等各类排行榜功能,这些排行本质都是基于计数进行排序的。不同的场景会
有细微的设计差异,这里只讲通用的排行榜系统该如何设计,遇到具体的场景再做细微的
调整即可,就算在面试过程中只能答出本文所设计的通用排行榜,也足够了,毕竟对于应
届生也只会考察到这个程度,面试是尽可能多的回答问题,很难追求所有问题都能回答出
来……
技术派中就有排行榜的应用,文档密码获取方式,参考星球置顶帖球友必看:https://
t.zsxq.com/91hPx
✅技派术派 Redis ?用活户活强排行榜(烈推荐)跃排 行 榜 ( ? 强 烈 推 荐 )
简版可以这样回答:将每个用户的得分作为 zset 中元素的 score,将用户 ID 作为元素的
value。使用 zset 提供的排序功能,可以按照分数从高到低排序。
面试官追问:如果分数相同,按照默认的排序规则会按照 value 值排序,他希望按照时间
顺序排序,也就是分数相同的情况下先上榜的排在前面。
一个可行的方案:
为了实现分数相同按照时间顺序排序,可以将分数 score 设置为一个浮点数,其中整数部
分为得分,小数部分为时间戳
即:score = 分数 + 1 - 时间戳/1e13
此时在分数相同的情况下,时间早的时间戳小,除以一个很大的数后得到的数字就小,被
1 减去以后得到的差就会大,也就实现了分数相同的情况下先上榜的排在前面。
如果面试还希望你聊一些系统设计的思路:
• (1)明晰项目诉求:在这里就是设计出一个根据积分或点赞等数据进行排序。同时关
注请求量,是否需要做高并发/高可用的扩展设计;此外对实时性是否也要要求,追
求强一致性还是最终一致性
• (2)确定业务逻辑:新用户上榜后排行榜要产生变化;用户积分发生变化后调整排名
• (3)架构设计:存储(MySQL/Redis)+服务(是否需要拆分为多个服务)
大体上排行榜由两部分组成,排序结构和信息汇总结构。也就是我们在排行榜上看到的根
据点赞数排出前一百,而信息汇总则是我们点击某一个用户头像可以看到其具体的用户信
息。 系统设计初期,前端同步调用排行榜系统,对于并发量不大的情况,可以直接使用
MySQL 作为存储,直接操作数据库 io 即可,这里数据库的极限在 5000/s。也可以先把全
量数据从数据库里取出来后在内存中进行排序(前提是数据量不大的情况下)
但随着并发量和用户量上升,这种强依赖的同步调用会增加接口延迟。 这时可以增加中
间层,也就是应对接口性能提不上去的三板斧之一(缓存,消息队列,分库分表)。如使
用 Rocket MQ 或 Kafka 等消息队列(MQ)。流量大时可对排行榜系统起到削峰作用,还可
批量插入数据库减少 IO 次数,提高插入效率。
不过,使用 MQ 后要做好幂等处理(八股提问,MQ 的消息幂等有哪些方式可以实现)。
当流量和并发量持续上升,数据库读写锁竞争加剧,可采用主从分离等方式均摊读压力,
当然也可以直接考虑使用 Redis 作为排行榜。利用 Redis 的 sortset 类型排序(这里需要掌
握 zset,相关的八股文也要熟悉,可能会被问到),如排行评论数可使用 ZINCRBY 命令
更新,查询用 ZREVRANGE 命令获取前 N 名排名和分数。 架构上可以由 Redis 作为消费
者,它订阅 MQ 消息,消费时做幂等判断,用 Lua 脚本保证操作原子性。(这段话可以作
为经典话术使用)
总结:
针对排行榜,简单的就直接可以使用 Redis 排序,但如果需要保证时间戳小的在前面就需
要做一点小处理。
面对设计一个通用的排行榜系统,考察系统设计能力,这里就可以从前面列举的方法论进
行展开。
PS:其实在整个分析过程中大家可以发现,场景题其实就会把我们背的那些八股和技术
运用起来,所以在学习场景题的时候就可以把八股文进行问题,有点像单词背不住就去读
阅读文章,在读文章的时候记住八股文,在上面的分析过程中我也有几处进行了随机的八
股提问。排行榜这个过程系统设计过程中有用到 MQ,那是不是可以顺带复习一下 MQ 的
相关八股呢?
• (1)如何保证 MQ 的消息幂等性?
• (2)MQ 的推模式和拉模式是什么?
• (3)如何保证 MQ 消息不丢?
……