如何设计微信运动的排行榜功能

腾讯二面的场景题,设计微信运动的排行榜,使用 Redis 的 Zset 数据结构来实现。

下面是我自己的分析,欢迎交流和补充,你提的更多问题,我会添加到文章中,提供给大家去思考。

需求分析:

1.存储所有用户的微信步数,使用什么结构,key value 分别是啥?

因为要存储每一天的数据,key 可以是:业务名称加上日期,value 是用户的 ID、score 就是对应的步数。

2.不同用户有不同的好友,每个人要单独实现一个排行榜吗?

不用,只需要维护一个排行榜,每一个用户都有自己的好友列表,可以用 Set 来存储,拿到好友列表之后,通过 ZScore 拿到好友 ID 的步数,排序之后返回给前端。

3.相同步数的还有如何排序?微信可能不太重要,但是在游戏中,相同的分数或者王者多少颗星,如果排序呢?

给分数 score 赋值的时候可以带上一个时间戳,这样就不会有相同的 socre 存在了。排序的时候也就解决了这个问题。

数据结构设计 每日使用一个 Zset 来存储用户当天的步数。

key 设计: step_rank:{date} 比如 step_rank:20254003.

微信运动的排行榜对于业务的场景并不是要求实时的,比如间隔五分钟去实现更新。 可以将步数先放入到消息队列中, Zadd key member value 或者累加操作等,实现排行榜的变化。

冷热数据隔离

Redis 的内存容量也是有限的,不能直接存储所有天数的数据。可以保留近三天的数据,对于历史的数据都是固定了,可以保存到数据库里面去,在每天晚上的时候自动将三天前的数据备份到数据库中。

详细细节:

好友排行榜生成:

1.每一个用户好友都用 Set 存储,key 为 friends:{userId}

1.获取用户123的所有好友ID
SMEMBERS friends:user123

批量的拿到好友的分数  拿到friend1和friend2的分数
ZSCORE step_rank:20231001 friend1

ZSCORE step_rank:20231001 friend2

查询出来分数存储到集合中在后端排序完成之后返回给前端进行展示

问题

1.如果数据量很大,底层的效率如何保证呢?

通过 哈希表+跳表来实现, 通过哈希表 O1 的时间复杂度找到跳表中的位置。

跳表不需要平衡树那样需要平凡的重新位置平衡,只是需要更新局部节点。

异步批量的跟新,通过消息队列实现异步更新。

#排行榜##RedisZ#
牛牛的面试专栏 文章被收录于专栏

牛牛的面试专栏,希望自己在25年可以拿到一份大厂的SP Offer 你的点赞和收藏都是我持续更新的动力

全部评论
无敌了二面
1 回复 分享
发布于 04-03 17:38 福建
mark场景题:微信运行排行榜设计
点赞 回复 分享
发布于 05-28 09:36 广东
mark场景题
点赞 回复 分享
发布于 04-04 00:24 广东

相关推荐

09-16 19:41
门头沟学院 Java
依旧只写记得的部分一面:1.自我介绍+介绍个人博客2.看我个人博客,让我讲讲我写的博客的东西(有关线程池源码的,参考性并不是很大)2.5.在讲博客内容时穿插多线程八股3.看我多线程这块好像挺好的,手撕奖励一道多线程打印,一个打印A,一个打印B(还好上次回去恶补了一下)4.问实习相关,主要是自己做了啥事情,整个系统大概啥样,回答思路是首先大致介绍系统作用,然后聚焦个人做的模块,再补充上下游把全链路讲清楚大概这么多,一共45-50min,出来等了5min告知通过准备第二轮二面:1.看我项目用了限流的东西问了一下我对限流算法有无了解,回答了令牌桶和时间窗口2.初现端倪,开始问我TCP有无限流概念的体现(主播简历一点408计网没写),回答流量控制和拥塞控制3.接2,给了一个例子,比如通过TCP连接下载数据的时候的场景,让我画TCP数据传输速率时间图(v-t图)。直接给我干懵逼了,他说你们应该学过吧,我说我完全没听过,他说没事,你学过的知识里应该有体现(体现在哪),于是开始画图。这题我主要的考虑是作为发送方来发数据的速率,因为流量控制和拥塞控制实际上都是控制发送方的窗口大小,其中拥塞控制是发送方根据网络拥堵程度控制自己的窗口大小。所以主播在这里考虑拥塞避免的一些算法(慢开始、拥塞避免、快重传、快恢复),通过窗口变化来推算传输速率的变化。所以首先画了一个拥塞窗口随时间变化的图,然后根据这个图画出最终他要的v-t图。他当时没说对不对,下来之后我用claude给我模拟了一下,思路基本没啥问题,最后的v-t图实际上跟窗口变化是基本差不多的。4.继续问计网,让我讲讲TCP三次握手和四次挥手,主播已经不记得那些状态具体叫啥了,索性说那我继续画图吧,然后就直接开画,画的中间穿插一些细节问题,比如第二次挥手跟第三次挥手之间可能是谁给谁传数据(服务端给客户端传)之类的细节。5.画完开始问一些我觉得自己擅长的,我说线程池,然后开始吟唱一些普通线程池八股6.追问你看过一些Web容器的源码比如tomcat吗?回答没看过,说没事那你觉得像这种Web服务的容器用传统线程池合适吗?回答思路是不太合适,我是从用户响应这块考虑的,假设用传统线程池,那么请求只来了一部分,就到达核心线程数,只有等任务队列满之后才会继续创临时线程来处理,这样如果请求多一点的话,请求的平均响应时间可能就会慢,我的想法就是优先创建线程,实在没线程可创了再放进队列里可能会好一些。下来查发现tomcat也确实是这样设计。7.然后继续问我看过啥源码吗,我依然回答线程池。。。大哥看我这么喜欢线程池奖励了一道设计题,让我设计一个工业可用的线程池,我的大概思路就是1.线程池集中管理、2.线程池配置热更新(分成本地更新和远程更新,本地可以考虑WatchService,远程比如放配置中心Nacos这种,Nacos的SDK里有ConfigService可以注册监听器监听配置发布)、3.线程池监控、4.线程池告警8.然后说是给我一个拔高的问题,问我线程池中死锁如何产生的,这个一时没想出来,依然从死锁的四个必要条件开始推,1.互斥、2.请求保持、3.不可剥夺、4.循环等待,推断出应该是由于出现循环等待导致四个条件同时满足(死锁只有在四个条件同时成立时可能出现,注意是可能),但是推了一会依然没推出来,让下来再想想。9.剩下就问了一个Spring有哪些拓展点,BeanPostProcessor、InitializingBean、还有Aware系列比如AppilicationContextAware这种,当时只记得这三个了。大概就这些,貌似也30-40min左右,哥们看手机显示您今天的面试已结束,还以为凉透了,刚准备去抽奖然后hr喊我名字说我通过了,前脚刚迈出来后脚就过了属于是,有点懵逼,然后抽奖走人,抽了个水杯正好拿来泡茶。总结就是真的蛮看运气的,周末两天复习实际上他问我的东西一点没看,上周刚被拷打过JVM于是恶补了一下,结果两面都基本在问线程池和408,所以感觉还是平常心看待吧,面试官想问啥确实不是面试者能左右的。。。主播以面一次赚一次的态度来的,降低预期,反而没这么紧张了,反正还是那句话,找工作就是找屎,别让一坨屎影响生活吧,虽然该找还得找。。。而且线下面的好处就是流程快和好沟通,一言不合直接画图给面试官看感觉确实比线上用手比划爽多了。发出来让大火了解一下线下面大概是个啥强度,同时希望后续顺利一些吧。。
查看14道真题和解析
点赞 评论 收藏
分享
评论
9
32
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务