投行系统的毫秒级榜单响应:如何用Redis ZSET破解同分排序难题?

简介: 通过Redis的ZSET数据结构和更新时间戳,解决投行交易系统实时排行榜中同分跳变的问题。具体方案为:将交易量作为整数部分,更新时间戳作为小数部分,确保同分时按最新更新排序,实现实时、高效、无需应用层干预的排行榜功能。一句话总结:通过Redis ZSET加更新时间戳,解决百万交易排行榜实时显示及同分难题。

不想看推导过程的小伙伴,直接看结尾一句话也就够了

背景和痛点

投行交易系统交易排行榜,存在以下痛点:

  1. 需要实时排行榜
  2. 当交易量排名相同时怎么解决?要避免同分跳变

设计思路

Redis可以实时显示排行榜
ZSET数据结构: 可以实现存储不重复的数据,包含score和value

如何解决同分僵局?

(✅推荐)方案1:整数部分保持不变(实时交易量),小数部分:采用时间戳

交易量相同的时候,按照最后更新时间进行判断
1)加入更新时间戳。作为小数部分
2)1-小数部分的更新时间戳
score = volume(交易量) + (1 - update_time(更新时间戳)/ 10的12次方)
| 交易id |交易量 |时间戳 |score |
|--|--|--|--|
| 1001 |110 |1740979215805| 110.8259020784195 |
| 1002 |110 |1740979215806| 110.8259020784194 |
| 1003 |120|1740979215812| 120.8259020784188 |
| 1004 |110 |1740979215807| 110.8259020784193 |

这种方案的好处有两个:

  1. 直接在redis中可以进行排序,保证排行的实时性能
  2. 不需要应用层的参与

(❌不推荐)方案2:应用层进行二次排序

没什么好说的,需要从Redis拿到数据之后,再根据业务字段进行排序,性能不好,不要选!

上代码

注意: Redis ZSET格式的添加返回的数据,不要放在一个dto中,分为两个DTO

DTO

@Data
public class TradeVolumeRequest {
   
    // 在Redis中 score = volume(交易量) + (1 - update_time(更新时间戳)/ 10的12次方)
    private String stockId;
    private Integer volume;
    // 更新时间
    private Timestamp updateTime;
}
@Data
public class TradeRanking {
   
    private String stockId;
    private Double rankingzVolume;
}

controller

@RestController
@Slf4j
public class TradeRankingController {
   
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    private static final String TRADE_RANKING_KEY = "trade:volume:ranking";

    @PostMapping("/addTradeVolume")
    public String addTradeVolume(@RequestBody List<TradeVolumeRequest> tradeVolumeRequests) {
   
        tradeVolumeRequests.forEach(tradeVolumeRequest -> {
   
            double rankingScore = tradeVolumeRequest.getVolume() + (1 - System.currentTimeMillis() / 10e12);
            stringRedisTemplate.opsForZSet()
                    .add(TRADE_RANKING_KEY, tradeVolumeRequest.getStockId(), rankingScore);
        });
        return "存入数据成功, key:" + TRADE_RANKING_KEY;
    }

    @GetMapping("/getTopN")
    public List<TradeRanking> getTopN(@RequestParam(value = "topN", defaultValue = "3") int topN) {
   
        List<TradeRanking> tradeRankingList = new ArrayList<>();

        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeWithScores(TRADE_RANKING_KEY, 0, topN - 1);
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
   
            TradeRanking tradeRanking = new TradeRanking();
            tradeRanking.setStockId(typedTuple.getValue());
            tradeRanking.setRankingzVolume(typedTuple.getScore());
            tradeRankingList.add(tradeRanking);
        }
        return tradeRankingList;
    }
}

测试结果

数据存入Redis中,score按照上述的公式

image.png

获取topN

image.png

一句话

通过Redis ZSET加更新时间戳,解决百万交易排行榜实时显示 同分难题

相关文章
|
8月前
|
JSON NoSQL Redis
在Rocky9系统上安装并使用redis-dump和redis-load命令的指南
以上步骤是在Rocky9上使用redis-dump和redis-load命令顺利出行的秘籍。如果在实行的过程中,发现了新的冒险和挑战,那么就像一个勇敢的航海家,本着探索未知的决心,解决问题并前进。
268 14
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
258 6
|
7月前
|
机器学习/深度学习 数据采集 人机交互
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
529 0
|
消息中间件 存储 负载均衡
Redis使用ZSET实现消息队列使用总结二
Redis使用ZSET实现消息队列使用总结二
222 0
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
360 1
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
存储 NoSQL 算法
深入理解Redis数据类型Zset原理
本文深入探讨了Redis中的Zset(有序集合)数据类型,它是一种可以存储排序功能的集合,其中每个元素都具有一个浮点型的score属性,用于根据score进行排序。
深入理解Redis数据类型Zset原理
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
455 0
|
存储 NoSQL 关系型数据库
Redis的ZSet底层数据结构,ZSet类型全面解析
Redis的ZSet底层数据结构,ZSet类型全面解析;应用场景、底层结构、常用命令;压缩列表ZipList、跳表SkipList;B+树与跳表对比,MySQL为什么使用B+树;ZSet为什么用跳表,而不是B+树、红黑树、二叉树
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet