场景题--设计微信运动的排行榜


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

问题

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

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

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

4.每天的数据都存储在 Redis 中吗?如何实现数据的冷热备份

Zset 底层跳表

Zset 底层结构在数据量比较小的时候,元素数量小于 128,元素的大小小于 64,使用的是 ziplist(压缩列表).大数据量的时候会变成字典和跳表 skiplist。

通过 dict 是实现 o1 的查询,通过 skiplist 实现 logn 的 socre 范围查询.

在原始的单链表上面向上建立索引.

https://blog.csdn.net/Appleeatingboy/article/details/119948340

问题分析

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

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

基本的操作

# 更新用户步数
ZADD step_rank:20250415 15000 user:1001
   
# 获取排行榜前10名
ZREVRANGE step_rank:20231001 0 9 WITHSCORES

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

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

如果用户达到了上亿,那么一个 Redis 的主机是否能存下这么多呢?分片存储到不同的主机上面去。或者根据用户的 id 进行取模,存储到不同的主机上面去,查询的时候根据。

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

将 socre*1e13+(1e13-时间戳)+ 这样就不会有相同的 socre 存在了。排序的时候也就解决了这个问题,还可以定义其他的规则.

距离当前的时间越近,那么对应的分数值越小,也就是排名月考前面.

# 将时间戳编码到Score中(假设时间戳为13位)
score = actual_score * 1e13 + (1e13 - timestamp)


原理:
13位时间戳
指的是Unix时间戳,它表示自1970年1月1日00:00:00 UTC(协调世界时) 以来的总毫秒数;

13位时间戳是10位时间戳的扩展,将时间精度提高到了毫秒级,在需要高精度时间记录和分析的场景中尤为有用;

   

1. <font style="color:rgb(0, 0, 0);">actual_score * 1e13</font>

这里的 <font style="color:rgb(0, 0, 0);">1e13</font> 代表 <font style="color:rgb(0, 0, 0);">10</font><font style="color:rgb(0, 0, 0);">13</font> 次方,也就是 <font style="color:rgb(0, 0, 0);">10000000000000</font>

<font style="color:rgb(0, 0, 0);">actual_score</font> 乘以 <font style="color:rgb(0, 0, 0);">1e13</font> 之后,实际得分会左移 <font style="color:rgb(0, 0, 0);">13</font> 位。这么做的目的是为时间戳留出 <font style="color:rgb(0, 0, 0);">13</font> 位的空间。

2. <font style="color:rgb(0, 0, 0);">1e13 - timestamp</font>

时间戳 <font style="color:rgb(0, 0, 0);">timestamp</font> 通常是一个 <font style="color:rgb(0, 0, 0);">13</font> 位的整数,代表从某个固定时间点(像 1970 年 1 月 1 日 00:00:00 UTC)开始到当前时刻所经过的毫秒数。

<font style="color:rgb(0, 0, 0);">1e13</font> 减去 <font style="color:rgb(0, 0, 0);">timestamp</font>,能得到一个新的时间戳编码值。这个编码值的特点是,时间越近,其值越小;时间越远,其值越大。

3. <font style="color:rgb(0, 0, 0);">actual_score * 1e13 + (1e13 - timestamp)</font>

<font style="color:rgb(0, 0, 0);">actual_score * 1e13</font><font style="color:rgb(0, 0, 0);">(1e13 - timestamp)</font> 相加,就得到了最终的得分 <font style="color:rgb(0, 0, 0);">score</font>

由于 <font style="color:rgb(0, 0, 0);">actual_score * 1e13</font> 占据了高位,<font style="color:rgb(0, 0, 0);">(1e13 - timestamp)</font> 占据了低位,所以最终的得分既包含了实际得分信息,又包含了时间戳信息。

更新排行榜 mq 消息队列

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

当用户上传步数时,直接高频写入Redis可能对数据库造成压力(尤其在用户量激增时)。

消息队列方案

  • 生产者:用户上传步数后,将更新请求发送到消息队列 kafka.
  • 消费者:后台服务异步消费队列中的消息,批量更新Redis的Zset。

优势

  • 流量削峰:缓冲突发流量,避免Redis写入过载。
  • 批量处理:合并多个步数更新操作,减少Redis的**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">ZADD</font>**命令调用次数。
  • 解耦:步数采集服务与排行榜更新服务独立扩展。

冷热数据隔离

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

详细细节

获取用户的排行榜

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

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

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

ZSCORE step_rank:20231001 friend2

查询出来分数存储到集合中在后端排序完成之后返回给前端进行展示
数据集介绍:神经元细胞核检测数据集 一、基础信息 数据集名称:神经元细胞核检测数据集 图片数量: - 训练集:16,353张 - 测试集:963张 分类类别: - Neuron(神经元细胞核):中枢神经系统的基本功能单位,检测其形态特征对神经科学研究具有重要意义。 标注格式: - YOLO格式,包含边界框坐标及类别标签,适用于目标检测任务 - 数据来源于显微镜成像,覆盖多种细胞分布形态和成像条件 二、适用场景 神经科学研究: 支持构建神经元定位分析工具,助力脑科学研究和神经系统疾病机理探索 医学影像分析: 适用于开发自动化细胞核检测系统,辅助病理诊断和细胞计数任务 AI辅助诊断工具开发: 可用于训练检测神经元退行性病变的模型,支持阿尔茨海默症等神经疾病的早期筛查 生物教育及研究: 提供标准化的神经元检测数据,适用于高校生物学实验室和科研机构的教学实验 三、数据集优势 大规模训练样本: 包含超1.6万张训练图像,充分覆盖细胞核的多样分布状态,支持模型深度学习 精准定位标注: 所有标注框均严格贴合细胞核边缘,确保目标检测模型的训练精度 任务适配性强: 原生YOLO格式可直接应用于主流检测框架(YOLOv5/v7/v8等),支持快速模型迭代 生物学特性突出: 专注神经元细胞核的形态特征,包含密集分布、重叠细胞等真实生物场景样本 跨领域应用潜力: 检测结果可延伸应用于细胞计数、病理分析、药物研发等多个生物医学领域
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈阿星

您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值