首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >带老弟做个实时排行榜

带老弟做个实时排行榜

原创
作者头像
程序员鱼皮
发布于 2021-06-28 13:52:17
发布于 2021-06-28 13:52:17
2.1K0
举报
文章被收录于专栏:鱼皮客栈鱼皮客栈

阿巴可懂的实时排行榜系统设计和实现思路。

大家好,我是鱼皮,暑假快到了,我的老弟小阿巴听说我家有很多好康的,就跑来找我玩。

结果我摆出了几个以前开发过的小系统,准备在这段时间带着小阿巴多做些作品,学习编程项目的设计思路。这样等他开学了,就可以更轻松地跟着老师做做项目了。

今天,就先带他做一个很常见的小功能:用户实时积分排行榜。

实时积分排行榜

需求

先描述下需求,在我的编程导航项目(https://www.code-nav.cn)中,为了鼓励大家共同维护网站,用户可以通过推荐资源、积极评论、举报违规资源等方式获取积分。

为了进一步激励大家,网站需要提供一个用户积分排行榜,分为 实时总积分榜周榜月榜,均 只取前 10 名 。所有用户都能够查看当前排行榜,以及查看自己的 实时 总积分排名,后续管理员就可以给上榜用户颁发奖品了。

效果如下图:

点击 我的排名 按钮,可以查看自己的实时排名:

本文篇幅有限,先仅讨论 实时总积分榜 的设计实现。

听了需求后,小阿巴爽朗一笑:这有啥难的?且让我设计一波,再给你娓娓道来。

设计实现

先看下数据库的结构,总共有 2 个表:用户表用户积分表

用户表存储了用户信息,以及用户的总积分(实时更新),也就是说总积分榜需要的数据可以直接从这里取到,不需要再去计算。

用户表内容:

用户 id

用户名

积分(score)

1

小阿巴

10

2

李鱼皮

1000

3

小李

100

......

100

李老热

66

如果要取前 10 名,只需要把所有用户的信息先取出来,再排个序就好啦,写 SQL 语句查询的话就是:

代码语言:txt
AI代码解释
复制
select * from `user` order by score;

然后如果要取自己的总排名,就对查到的有序数据进行一次遍历,找到自己所在的位置下标就行,伪代码如下:

代码语言:txt
AI代码解释
复制
// 从数据库查询全部用户列表
list = getAllDataList()
for(i = 0; i < total; i++) {
  // 找到自己的位置
  if(list[i].id == '我的id') {
    return i + 1;
  }
}

小阿巴得意到:这不就实现总积分榜了么?你这需求太简单,啧啧。

我笑到:还不错,总积分榜的思路是正确的,起码知道要对所有的数据进行排序。但如果用户数特别多呢?比如几十万个,你只需要查自己的总排名,还需要把全部的数据都做一个排序么?

小阿巴陷入沉思,想了半天,没想出来。

于是我提示到:假如在一次考试中你想知道自己的排名,是不是只需要知道有多少人的分数比自己高就行了,不用去管其他人排第几对吧?

小阿巴一拍脑袋:对啊,我只需要先查出自己的分数,然后统计分数大于我的用户数量,不就知道自己的排名了?

先用 SQL 语句查出用户的分数:

代码语言:txt
AI代码解释
复制
/* 只取需要的列 */
select score as myScore
from `user`
where id = "用户 id";

然后再用 SQL 语句统计分数大于该用户分数的数量:

代码语言:txt
AI代码解释
复制
select count(*) from `user`
where score > myScore;

最后只需要将该查询结果加 1,就是自己的排名啦~

小阿巴感叹到:原来转换一点点思路,就能省去多余的排序带来的性能开销,起飞~

更多思考

鱼皮:先别起飞,其实对于一般用户量的系统,上面的方案就已经足够了。下面让我们加大难度,假如用户数再多一点点呢,比如说一亿个,怎么实时获取前 10 名呢?

小阿巴:还真是 “亿点点”,就您那破编程导航还想着有一亿个用户?

鱼皮:少废话,梦想还是要有的,万一有亿个用户呢?快想想系统怎么做!

小阿巴:且不说对一亿个数据排序有多慢,能不能存的下都是个问题啊。。。啊,等等,这难道就是面试常见的 Top N 问题!

鱼皮:不错,我面试的时候被问过好几次 Top N 问题,如何从海量数据中找出前 N 个数呢?

小阿巴:这我完全不懂啊,算法不会,真要命。

鱼皮:其实 Top N 问题的核心在于保证空间和时间复杂度,先要考虑数据能存入内存运算,在怎样算得更快。

通常 Top N 问题有下列几种解决方案。

Top N 解决方案

全部排序

直接对所有数据进行排序(快排等),缺点是需要将数据一次性加载到内存中。

局部淘汰

内存中维护一个大小为 N 的容器,再让剩余的数一个个进入容器,并淘汰容器内的最小值。最终容器内剩下的数就是前 N 名。优点是能节省内存,缺点是太慢了。

分治

把数据分为多个小组,小组内先分别选出前 N 名小组长,最后再让这些小组长同台竞技,选出最终的前 N 名。

哈希预处理

假如数据重复度很高,可以通过 hash 的方式,去掉很多重复数据。比如 1 亿个数据里,一半是 0,一半是 1,那么取前 10 名时,可以直接淘汰掉另一半为 0 的数据。

但是预处理本身也需要时间和空间,这就需要我们对数据的重复度有一个清晰的判断,否则自作聪明、适得其反。

小根堆

面试算法中的高频考点 —— 堆排序,可以先取前 N 个数组成小根堆,堆顶始终是最小值。 然后遍历后续数字,大于堆顶就替换掉堆顶并调整最小堆结构。该算法时间复杂度和空间复杂度(为 N,常数)都不错,所以必须要掌握。

小根堆
小根堆

但是具体选择哪种方案呢?还是要结合我们实际的项目和业务场景来分析。

实际解决

由于我们的数据库来记录积分,所以当用户量级很大时,首先要 分库分表 ,通常是水平分表,根据一定规则(比如 id)把用户数据行分批存储在多个数据表中。

分表
分表

然后就和大数据 Map / Reduce 处理机制一样了,可以采用 分治 的方式 并行计算 每个表的前 10 名(map),都计算好后,再汇总到一起计算最终的前 10 名(reduce)。

一次大数据并行处理过程
一次大数据并行处理过程

用这种方式,别说 1 亿了,2 亿、3 亿的计算模式都是一样的,加机器水平扩容就好了~

所以遇到 Top N 问题的时候,大家可以先答一下上面的几种方案,再结合具体的场景分析,分治和最小堆是我觉得相对 核心 的点。

Redis

最后,对于实时排行榜的设计,肯定很多背过八股文面试题的朋友在第一时间会想到使用 Redis 的有序集合 zset,的确也是一种方案,但也要结合场景去分析利弊,不要秒答。

使用基于内存的 Redis zset 的确运算更快,且天然支持排序、使用方便。但数据量大时同样面临数据更新、维护、同步、持久化存储等问题,而且对于我们这种实时性要求不高的需求来说,有些大材小用了哈哈。

zset 数据结构
zset 数据结构

我是鱼皮,肝文不易,点赞 还是要求一下的,祝大家都能心想事成、发大财、行大运。

最后再送大家一些 帮助我拿到大厂 offer 的学习资源 ,视频教程 + 习题 + 答案 + 源码、编程书籍、大厂面经、实战项目等。

指路:跑了,留下 6T 的资源!

我是如何从零开始通过自学,拿到腾讯、字节等大厂 offer 的,可以看这篇文章,不再迷茫!

指路:我学计算机的四年,共勉!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Redis实现排行榜实时更新
基本介绍 Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。 有序集合的成员是唯一的,但分数 (score) 却可以重复。 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O (1)。集合中最大的成员数为 2^32 - 1^ (4294967295, 每个集合可存储 40 多亿个成员)。 有序集合首先是集合,其成员(member)具有唯一性,其次,每个成员关联了一个分数(score),使得成员可以按照分数排序。
友儿
2022/09/09
4.2K0
如何使用 Redis 实现排行榜功能
在当今的互联网应用中,排行榜功能是一种常见的需求,无论是社交媒体上的用户热度排行、电商平台的商品销量排行,还是游戏中的玩家积分排行等,排行榜都能为用户提供直观的对比和激励机制。而 Redis 作为一种高性能的键值存储系统,凭借其丰富的数据结构和高效的读写性能,非常适合用于实现排行榜功能。本文将详细介绍如何使用 Redis 来实现排行榜功能,包括其原理、实现步骤以及一些优化建议。
全干程序员demo
2025/05/27
4240
​深度剖析排行榜设计:从基础到亿级用户场景
对于一些数据量较小、业务逻辑相对简单的场景,数据库成为了排行榜设计的首选工具。就拿一个小型比赛的排行榜来说,假设参赛队伍仅有寥寥数支,排行榜表中的数据量始终保持在一个较低的水平。此时,借助数据库的排序功能,如MySQL中的order by语句,便能轻松实现排行榜的基本功能。
用户1142828
2025/03/02
2791
【Go 语言社区】使用 Redis 实现排行榜功能
排行榜功能是一个很普遍的需求。使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择。 一般排行榜都是有实效性的,比如“用户积分榜”。如果没有实效性一直按照总榜来排,可能榜首总是几个老用户,对于新用户来说,那真是太令人沮丧了。 首先,来个“今日积分榜”吧,排序规则是今日用户新增积分从多到少。 那么用户增加积分时,都操作一下记录当天积分增加的有序集合。 假设今天是 2015 年 04 月 01 日,UID 为 1 的用户因为某个操作,增加了 5 个积分。 Redis 命令如下: ZINCRBY ran
李海彬
2018/03/20
2.7K0
你知道怎么基于 redis 实现排行榜吗
同事: 最近我在做一个在线游戏网站,需要实现一个排行榜功能,用来展示每个玩家的积分排名。
灬沙师弟
2023/05/18
6860
你知道怎么基于 redis 实现排行榜吗
SpringBoot应用篇之借助Redis实现排行榜功能
在一些游戏和活动中,当涉及到社交元素的时候,排行榜可以说是一个很常见的需求场景了,就我们通常见到的排行榜而言,会提供以下基本功能
一灰灰blog
2019/05/26
2.1K0
zSet实现排行榜功能
这里就不说具体的zset实现了(我太菜,不敢放肆,等我牛逼了我再写zset实现,估计n年后 ),总之为了速度和稳定性以及持久化,redis肯定是最合适的,而且redis又有zSet这种数据结构,那不用zSet岂不是浪费嘛。 首先简单说一下zSet:
终有救赎
2023/10/22
9790
Redis排行榜的设计与实现
排行榜zset的经典实现,现在的思路全都是查库的操作,由于业务原因,有些是异步操作,难免存在已经计分,但分数还没有入库,这时去查库,导致与实际的分数不一致的情况,通常排行榜本身的操作不是很频繁,但计分的操作很频繁,但也不排除有些业务场景有些"分数怪"刷分的情况,比如王者荣耀实时排列等。
疯狂的KK
2020/09/14
2K0
Redis排行榜的设计与实现
使用redis实现排行榜
排行榜在很多地方都能使用到,redis的zset可以很方便地用来实现排行榜功能。本文是一个示例。
张云飞Vir
2022/09/29
1.5K0
使用Redis实现用户积分及TopN排行榜功能
这类似于一张日志表,因此数据量很大,想要统计用户积分做排行榜时,表数据可能如下:
JavaEdge
2021/02/23
3.4K0
使用Redis实现用户积分及TopN排行榜功能
使用Sorted Set制作排行榜
在许多应用中,排行榜是一个常见的功能,用于展示和比较用户在某个特定指标上的排名情况。Redis提供了Sorted Set(有序集合)数据结构,非常适合用来实现排行榜功能。本文将介绍使用Sorted Set制作排行榜的原理、实现方法以及常见应用场景。
GeekLiHua
2025/01/21
1480
Redis Sorted Set 底层实现原理深度解读与排行榜实战
Sorted Sets 与 Sets 类似,是一种集合类型,集合中不会出现重复的数据(member)。区别在于 Sorted Sets 元素由两部分组成,分别是 member 和 score。
码哥字节
2023/08/22
1.8K0
Redis Sorted Set 底层实现原理深度解读与排行榜实战
手把手教你使用 Redis 实现排行榜
原文链接:https://www.cnblogs.com/chenzhuantou/p/11321848.html
业余草
2019/08/15
1.2K0
手把手教你使用 Redis 实现排行榜
Redis 实现用户积分和积分排行榜微服务优化
在之前的博客中我通过 MySQL数据库实现了积分和积分排行榜功能,在数据量大和并发量高的情况下会有以下缺点:
共饮一杯无
2023/02/03
5740
实现全局积分排行榜的技术方案
使用ORDER BY score, update_time进行排序,并使用LIMIT 10来获取前10名的数据。为了提升性能,需要对score和update_time添加索引。
用户11397231
2025/01/02
1500
实现全局积分排行榜的技术方案
初识Redis · set和zset
在前几篇Redis的基本数据类型中,我们已经了解了string list hash,并且了解了对应的内部编码和实际的应用场景,也是对于基本的命令操作花了比较多的文字描述的去介绍。那么在本文呢,既然有了前几个类型多个基础,我们学习set和zset也是会比较轻松的了。
_lazy
2025/04/17
1690
初识Redis · set和zset
重学SpringBoot3-集成Redis(十三)之点排行榜实现
在现代应用程序中,排行榜功能常用于展示用户或内容的排名,如游戏中的分数排名、社交平台上的活跃度排名等。Redis 提供的有序集合(Sorted Set)结构,能够通过分数进行排序,非常适合用来构建排行榜。本文将介绍如何使用 Spring Boot 3 和 Redis 实现一个简单的排行榜功能。
CoderJia
2024/10/18
2790
重学SpringBoot3-集成Redis(十三)之点排行榜实现
Redis 应用实践-排行榜
Redis是一个高性能的内存数据库,其功能不仅仅限于简单的键值存储,还可以支持各种复杂的数据结构。其中,有序集合(Sorted Set)是Redis中一种非常有用的数据结构,可以用来实现排行榜、评分系统等功能。
玖叁叁
2023/04/15
1K0
移动互联网实战–社交游戏的排行榜设计和实现(1)
前言:   游戏领域, 特别是移动端的社交类游戏, 排行榜成为了一种增强体验交互, 提高用户粘性的大法宝. 这边讲述在不同用户规模下, 游戏服务化/游戏平台化趋势下, 如何去设计和实现游戏排名榜. 本文侧重于传统关系型Mysql的方案实现, 后续会讲解Nosql的作用. 小编(mumuxinfei)对这块认识较浅, 所述观点不代表主流(工业界)做法, 望能抛砖引玉.
全栈程序员站长
2022/02/23
6470
移动互联网实战–社交游戏的排行榜设计和实现(1)
大规模排行榜系统实践及挑战
本文介绍了如何通过修改配置项和代码的方式,实现在不重启Redis服务器的情况下,动态修改Redis的配置项。同时介绍了如何实现通过Redis的配置文件来修改Redis的配置项。最后通过一个具体实例,演示了如何通过修改配置项来实现不同的功能,并总结了整个实现过程。
小时光
2016/10/18
6.6K0
大规模排行榜系统实践及挑战
相关推荐
Redis实现排行榜实时更新
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档