9. 基于 Redis 实现排行榜功能

在现代应用场景中,排行榜(leaderboard)广泛应用于游戏、社交网络、电子商务等领域,通过排行榜来展示用户排名、评分或成就等数据。而Redis作为一个高性能的内存数据库,特别擅长处理需要快速查询和更新的数据,如排行榜数据。本教程将详细介绍如何使用Redis结合Spring Boot实现一个高效的排行榜系统。

一、使用场景

排行榜系统适用于以下场景:

  1. 游戏排行榜:展示玩家积分、胜利次数等。
  2. 电商平台销量榜单:根据销量或用户评价进行商品排行。
  3. 社交应用的活跃度排名:基于点赞数、分享数等进行用户活跃度排行。

二、原理解析

在Redis中,实现排行榜的核心数据结构是有序集合(Sorted Set, zset)。Redis的zset可以为每个元素关联一个分数,并通过这个分数来自动排序。操作包括添加元素、更新分数、获取排名等,都是O(logN)的复杂度,非常适合高并发环境下的实时排行需求。

Redis有序集合的主要操作:
  • ZADD:向有序集合添加元素或更新分数。
  • ZRANGE:按照分数排序获取指定范围内的元素。
  • ZRANK:获取指定元素的当前排名。
  • ZREVRANK:获取指定元素的逆序排名。
  • ZREM:删除指定元素。
  • ZINCRBY:增加元素的分数。

三、实现过程

1. 项目结构

我们将基于Spring Boot 来构建项目,包含以下模块:

  • Controller:提供REST接口,供前端或其他服务调用。
  • Service:业务逻辑处理,包含与Redis交互的操作。
  • Repository:Redis相关操作的封装。
2. 环境准备

pom.xml中添加以下依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

application.yml中配置Redis:

spring:
  redis:
    host: localhost
    port: 6379
3. Redis配置类

创建一个配置类来初始化RedisTemplate:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}
4. 排行榜Service实现

LeaderboardService中实现添加用户分数、更新分数、查询排名等操作。

@Service
public class LeaderboardService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String LEADERBOARD_KEY = "game:leaderboard";

    // 添加或更新用户分数
    public void addScore(String userId, double score) {
        redisTemplate.opsForZSet().add(LEADERBOARD_KEY, userId, score);
    }

    // 获取用户排名
    public Long getRank(String userId) {
        return redisTemplate.opsForZSet().reverseRank(LEADERBOARD_KEY, userId);
    }

    // 获取排行榜
    public Set<Object> getTopUsers(int topN) {
        return redisTemplate.opsForZSet().reverseRange(LEADERBOARD_KEY, 0, topN - 1);
    }

    // 增加用户分数
    public void incrementScore(String userId, double scoreIncrement) {
        redisTemplate.opsForZSet().incrementScore(LEADERBOARD_KEY, userId, scoreIncrement);
    }
}
5. 创建Controller

通过LeaderboardController来暴露REST API,允许外部调用。

@RestController
@RequestMapping("/leaderboard")
public class LeaderboardController {

    @Autowired
    private LeaderboardService leaderboardService;

    // 增加或更新用户分数
    @PostMapping("/add")
    public ResponseEntity<String> addScore(@RequestParam String userId, @RequestParam double score) {
        leaderboardService.addScore(userId, score);
        return ResponseEntity.ok("Score added/updated successfully");
    }

    // 获取用户排名
    @GetMapping("/rank/{userId}")
    public ResponseEntity<Long> getRank(@PathVariable String userId) {
        Long rank = leaderboardService.getRank(userId);
        return ResponseEntity.ok(rank);
    }

    // 获取前N名用户
    @GetMapping("/top/{count}")
    public ResponseEntity<Set<Object>> getTopUsers(@PathVariable int count) {
        Set<Object> topUsers = leaderboardService.getTopUsers(count);
        return ResponseEntity.ok(topUsers);
    }

    // 增加用户分数
    @PostMapping("/increment")
    public ResponseEntity<String> incrementScore(@RequestParam String userId, @RequestParam double increment) {
        leaderboardService.incrementScore(userId, increment);
        return ResponseEntity.ok("Score incremented successfully");
    }
}

四、测试效果

启动Spring Boot应用后,使用Postman或其他工具测试以下功能:

  1. 添加/更新分数

    • POST请求:/leaderboard/add
    • 参数:userId=player1&score=1500
  2. 获取用户排名

    • GET请求:/leaderboard/rank/player1
  3. 获取前N名玩家

    • GET请求:/leaderboard/top/10
  4. 增加分数

    • POST请求:/leaderboard/increment
    • 参数:userId=player1&increment=100

五、总结与优化

通过Redis的有序集合,排行榜系统能够高效地处理大量数据并且实时更新。在生产环境中,我们还可以做以下优化:

  1. 缓存过期:可以为排行榜设置缓存过期时间,定期清理无效数据。
  2. 数据持久化:启用Redis的RDB或AOF机制确保数据不会因为服务宕机而丢失。
  3. 分布式集群:如果系统对排行榜查询量非常大,可以考虑使用Redis集群来分担负载。
  4. 监控与报警:使用Redis的性能监控工具,如redis-cliRedisInsight,及时发现性能瓶颈。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913112.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

window11安装elasticsearch+Kibana

1、下载elasticsearch与elasticsearch 下载elasticsearch 查看elasticsearch对应的Kibana版本 下载elasticsearch解压后文件目录如下 可执行脚本文件,包括启动elasticsearch服务、插件管理、函数命令等 bin配置文件目录,如elasticsearch配置、角色配置、jvm配置等 conf 默认…

[单例模式]

[设计模式] 设计模式是软件工程中的一种常见做法, 它可以理解为"模板", 是针对一些常见的特定场景, 给出的一些比较好的固定的解决方案. 不同语言适用的设计模式是不一样的. 这里我们接下来要谈到的是java中典型的设计模式. 而且由于设计模式比较适合有一定编程经…

MethodChannel插件的用法

文章目录 1 知识回顾2 示例代码3 经验总结我们在上一章回中介绍了通道相关的内容,本章回中将介绍其中的一种通道:MethodChannnel.闲话休提,让我们一起Talk Flutter吧。 1 知识回顾 我们在上一章回中介绍了通道的概念和作用,并且提到了通道有不同的类型,本章回将其中一种通…

Golang | Leetcode Golang题解之第554题砖墙

题目&#xff1a; 题解&#xff1a; func leastBricks(wall [][]int) int {cnt : map[int]int{}for _, widths : range wall {sum : 0for _, width : range widths[:len(widths)-1] {sum widthcnt[sum]}}maxCnt : 0for _, c : range cnt {if c > maxCnt {maxCnt c}}retur…

通讯录(C 语言)

目录 一、通讯录设计思路1. 伪代码设计思路2. 代码设计思路 二、代码实现三、程序运行演示四、整体分析 一、通讯录设计思路 1. 伪代码设计思路 通讯录可以用来存储 100 个人的信息&#xff0c;每个人的信息包括&#xff1a;姓名、性别、年龄、电话、住址。 提供方法&#x…

深入解析四种核心网络设备:集线器、桥接器、路由器和交换机

计算机网络系列课程《网络核心设备》 在现代网络技术中&#xff0c;集线器、桥接器、路由器和交换机扮演着至关重要的角色。本文&#xff0c;将深入探讨这四种设备的功能、工作原理及其在网络架构中的重要性。 集线器&#xff1a;基础网络连接设备 集线器&#xff08;Hub&…

01 Oracle 数据库存储结构深度解析:从数据文件到性能优化的全链路探究

文章目录 Oracle 数据库存储结构深度解析&#xff1a;从数据文件到性能优化的全链路探究一、Oracle存储结构的物理层次1.1 控制文件&#xff08;Control File&#xff09;1.2 联机重做日志文件&#xff08;Online Redo Log File&#xff09;1.3 数据文件&#xff08;Data File&…

Type-C转DP线方案

在现代数字化生活中&#xff0c;高清视频传输已成为日常需求的重要组成部分。无论是工作中的多屏协作&#xff0c;还是娱乐中的沉浸式体验&#xff0c;高清显示器都扮演着不可或缺的角色。然而&#xff0c;随着设备接口的多样化&#xff0c;如何高效地将Type-C设备连接至Displa…

【c++篇】:栈、队列、优先队列:容器世界里的秩序魔法 - stack,queue与priority_queue探秘

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.容器stack1.介绍2.成员函数3.模拟实现4.注意事项 二.容器qu…

Java基础——循环switch大数值更改器访问器深浅拷贝

目录 1.循环 2.switch多分支选择结构 3.大数值 4.浅拷贝&深拷贝 5.Arrays.sort排序 6.面向对象 7.更改器&访问器 1.循环 for-each循环 在 Java 中&#xff0c;for-each 循环&#xff08;也称为增强型 for 循环&#xff09;是一种用于遍历数组或集合&#xff08…

引入 axios,根据 api 文档生成调用接口

起步 | Axios Docs 安装 axios npm install axios 生成 api 调用接口【可选】 https://github.com/ferdikoomen/openapi-typescript-codegen 安装 npm install openapi-typescript-codegen --save-dev 然后执行生成代码 # http://localhost:8805/api/user/v3/api-docs&a…

wsl2+Ubuntu安装图形化界面(VNC方式)

本章教程,记录在wsl2+Ubuntu操作系统中安装可视化界面步骤。 一、安装桌面环境 尽量以root用户进行安装,避免因权限不足导致部分依赖无法安装。 sudo apt update sudo apt upgrade -y sudo apt install ubuntu-desktop由于可视化桌面程序安装包比较大,网速慢的小伙伴,需要耐…

Linux应用——线程池

1. 线程池要求 我们创建线程池的目的本质上是用空间换取时间&#xff0c;而我们选择于 C 的类内包装原生线程库的形式来创建&#xff0c;其具体实行逻辑如图 可以看到&#xff0c;整个线程池其实就是一个大型的 CP 模型&#xff0c;接下来我们来完成它 2. 整体模板 #pragma …

学习日记_241110_局部线性嵌入(Locally Linear Embedding, LLE)

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

【我的 Anti-AV 学习手札】DLL注入

无敌舍友s神免杀学了一个阶段&#xff0c;达者为师&#xff0c;向s师傅学习&#xff01;&#xff01; ps&#xff1a;我的基础实在薄弱&#xff0c;WIN编程甚至都没做过&#xff0c;所以笔记翔实些 一、注入思路 1.在进程中开辟一段空间 2.存入dll绝对路径地址的字符串 3.使用…

【HarmonyOS NEXT】一次开发多端部署(以轮播图、Tab栏、列表为例,配合栅格布局与媒体查询,进行 UI 的一多开发)

关键词&#xff1a;一多、响应式、媒体查询、栅格布局、断点、UI 随着设备形态的逐渐增多&#xff0c;应用界面适配也面临着很大问题&#xff0c;在以往的安卓应用开发过程中&#xff0c;往往需要重新开发一套适用于大屏展示的应用&#xff0c;耗时又耗力&#xff0c;而鸿蒙提供…

linux 安装 mongodb

选择MongoDB版本 https://www.mongodb.com/try/download/community-kubernetes-operator 我的系统是centos7.9 这里只能最高只能选择mongo7 复制下载链接&#xff1a;https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.15.tgz 获取安装教程&#xff1a; h…

《深入浅出Apache Spark》系列②:Spark SQL原理精髓全解析

导读&#xff1a;SQL 诞生于 20 世纪 70 年代&#xff0c;至今已有半个世纪。SQL 语言具有语法简单&#xff0c;低学习门槛等特点&#xff0c;诞生之后迅速普及与流行开来。由于 SQL 具有易学易用的特点&#xff0c;使得开发人员容易掌握&#xff0c;企业若能在其计算机软件中支…

PostgreSQL pg-xact(clog)目录文件缺失处理

一、 背景 前些天晚上突然收到业务反馈&#xff0c;查询DB中的一个表报错 Could not open file "pg-xact/005E": No such file or directory. 两眼一黑难道是文件损坏了...登录查看DB日志&#xff0c;还好没有其他报错&#xff0c;业务也反馈只有这一个表在从库查询报…

Cursor的chat与composer的使用体验分享

经过一段时间的试用&#xff0c;下面对 Composer 与 Chat 的使用差别进行总结&#xff1a; 一、长文本及程序文件处理方面 Composer 在处理长文本时表现较为稳定&#xff0c;可以对长文进行更改而不会出现内容丢失的情况。而 Chat 在更改长的程序文件时&#xff0c;有时会删除…