项目没亮点?那就来学下pk功能设计吧

简介: 它的流程是这样,主播点击申请pk按钮,匹配其他同时申请pk的主播,粉丝通过送礼给心爱的主播提高pk进度条,pk结束后失败的一方主播接受惩罚。但进度条数据主要是提供给在pk开始后才进来直播间的观众,这类人进行直播间后,客户端调用pk进度的查询接口,获取最新的pk进度条。每场pk都有倒计时,这里我们在pk匹配成功时就在Redis里设置一个倒计时键值对,该键值对的初始值是本场pk的总pk时间。,我们给他设计为WebSocket数据实时推送,只要主播的进度有增加,把增加的数值推送到所有在pk直播间的用户。

先赞后看,南哥助你Java进阶一大半

麻省理工学院开源的Redis adapter适配器,可以将事件广播到多个单独的 socket.io 服务器节点。这一点和下文精彩的内容相关。

在这里插入图片描述

我是南哥,一个Java学习与进阶的领路人。

相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。

⭐⭐⭐本文收录在《Java学习/进阶/面试指南》:https://github/JavaSouth

1. 直播pk功能设计

1.1 pk玩法

直播pk的功能,要设计出来看起来容易,实则一点都不简单。直播pk玩法在抖音、虎牙、斗鱼各大平台都有出现,能帮互联网公司、主播赚不少钱。

南哥先说说pk的玩法是如何如何?它的流程是这样,主播点击申请pk按钮,匹配其他同时申请pk的主播,粉丝通过送礼给心爱的主播提高pk进度条,pk结束后失败的一方主播接受惩罚。但惩罚又有何妨呢,失败的主播也赚到收益了。

看看直播pk的大概界面。

在这里插入图片描述

1.2 pk进度条

pk进度条数据我们打算存储到高性能内存数据库Redis,这里使用Redis的Map结构,存储两个pk主播的进度条数据。

# Map的k-v结构
pk:progress:pk_id = [{主播A : 100}, {主播B : 90}]

但进度条数据主要是提供给在pk开始后才进来直播间的观众,这类人进行直播间后,客户端调用pk进度的查询接口,获取最新的pk进度条。

// 查询pk进度条接口
public Map<Object, Object> getPKProgress(String pkId) {
   
    String pkProgressKey = "pk:progress:" + pkId;
    return redisTemplate.opsForHash().entries(pkProgressKey);
}

而处于直播间的用户的进度条增加,我们给他设计为WebSocket数据实时推送,只要主播的进度有增加,把增加的数值推送到所有在pk直播间的用户。

但有个问题,如果刚进来的观众第一次进来直播间后,他获取了最新的pk进度。此时刚好某个主播的pk进度增加,但由于是新进来的观众,WebSocket数据推送不到这个最新用户,怎么办

这涉及到数据一致性的问题!我们可以在用户进入直播间后,每隔一段时间调用以上的接口,获取pk最新进度条,进行数据纠正

同时,在pk结束后,仍然要调用一次查询接口,确保不会出现这个情况:欸,主播你的分数明明比她高,怎么输了呢?这个情况还是数据不一致的问题。

1.3 pk匹配

主播点击pk申请按钮,我们把主播id与直播间信息加入到pk匹配池。

这个pk池子我们依然利用Redis,采用Redis五大基本数据类型之一:Zset。Zset的元素存储主播id与直播间id,元素的score存储主播的pk积分。那Zset会根据主播的积分进行顺序排序。

后面就是匹配算法的设计了,通过匹配算法 + Zset主播的积分,挑选出积分相近的两个pk主播进行匹配。

# Zset结构:
pk:matching_pool = [{anchor_id_1_room_id_1 : 100}, {anchor_id_2_room_id_2 : 110}]

南哥上面这几个关键数据结构都存储在Redis,我们要保证Redis的高可用性。那用Redis集群可以吗?

如果采用这种Redis架构,因为Redis集群把键值分为16384个槽给到各个集群节点,建议给集群里每个节点配上从节点,即集群架构搭配主从模型。防止某个集群节点失效了导致数据全部丢失。

1.4 pk倒计时

每场pk都有倒计时,这里我们在pk匹配成功时就在Redis里设置一个倒计时键值对,该键值对的初始值是本场pk的总pk时间。

// 设置pk倒计时
public void setPKCountdown(String pkId, int totalTime) {
   
    String pkCountdownKey = "pk:countdown:" + pkId;

    // 在 Redis 中设置倒计时
    redisTemplate.opsForValue().set(pkCountdownKey, totalTime, totalTime, TimeUnit.SECONDS);
}

1.5 pk流程设计

总结上文,清晰地梳理下整个pk流程的设计。

主播发送pk申请 -> 匹配 -> 成功则WebSockett推送成功通知、倒计时信息 -> 创建监控线程 -> pk中 -> pk结算

首先两个主播在客户端点击pk申请按钮,申请请求到达后端,客户端告知主播:pk匹配中

主播申请后,后端服务把主播加入pk匹配池。而专门用于配对pk主播的微服务持续处理pk池子中请求,合适则把两个主播进行pk配对,同时把两个主播踢出pk匹配池。

当然匹配成功后还有后续流程需要处理,配对成功后使用WebSocket服务端主动推送技术,实时告知主播包括直播间用户:pk已配对成功。

同时,在Redis创建上文1.3节的pk倒计时,同步也推送给主播包括观众。

在后台,我们还需要创建一个监控线程,来去监控pk是否结束,当结束时进行pk结算,告知观众与主播究竟哪一方获胜。

监控线程取自监控线程池子,方便线程复用,线程池的最大好处就是减少了系统频繁创建、销毁线程带来的资源消耗。

// 从监控线程池获取一个线程
public void monitorPKProgress(String pkId) {
   
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);

    scheduler.scheduleAtFixedRate(() -> {
   
        // 检查倒计时是否结束
        String countdownKey = "pk:countdown:" + pkId;
        Integer countdown = (Integer) redisTemplate.opsForValue().get(countdownKey);
        if (countdown != null && countdown <= 0) {
   
            System.out.println("PK结束,开始结算...");
            // 调用结算逻辑
        }
    }, 0, 1, TimeUnit.SECONDS);  // 每秒监控一次
}

1.6 WebSocket长连接问题

pk匹配成功通知、pk进度条增加等,都需要WebSocket技术去实时推送数据。

但一个直播间成千上万个观众,大多数观众的客户端都长连接着不同的WebSocket服务器。要推送数据时,怎么知道要从哪些WebSocket服务器进行推送??

(1)集中式连接状态管理

有一些公司WebSocket服务器只有固定一台,推送数据时绑定这台服务器的ip即可,也不需要处理我们讨论的问题。

我们把用户的连接信息,包括用户id、长连接的WebSocket服务器地址,都存储在Redis中进行集中式的状态管理。当要推送数据时,获取用户所在WebSocket服务器地址即可。

(2)广播推送

进行数据推送时,对所有WebSocket服务器进行消息广播。接收到广播消息后,服务器检查本地是否有该用户的连接信息,如果有则进行消息推送。

(3)WebSocket集群框架

如果WebSocket框架使用的是Socket.IO的话,以上的问题已经有很好的集群解决方案了。Socket.IO Redis adapter适配器可以将事件广播到多个单独的 socket.io 服务器节点,用于在多台WebSocket服务器共享连接状态。

戳这,《JavaSouth》作为一份涵盖Java程序员所需掌握核心知识、面试重点的神秘文档。

我是南哥,南就南在Get到你的点赞点赞点赞。

在这里插入图片描述

创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️

相关文章
|
Linux Docker 容器
Docker 容器抓包说明
正常情况下,操作系统层面可以通过 tcpdump 来抓包。但对于容器环境,根据所使用的 base 镜像的不同,容器内不一定含有抓包工具,所以无法直接抓包。本文简要介绍如何通过 ```nsenter``` 工具来对容器快速抓包。 # nsenter 工具介绍 nsenter 包含在绝大部分 Linux 发行版预置的 util-linux 工具包中。它可以进入指定进程的关联命名空间。包
9599 0
|
消息中间件 Java Kafka
掌握Kafka事务,看这篇就够了
先赞后看,南哥助你Java进阶一大半Kafka事务实际上引入了原子多分区写入的概念,播客画了以下流程图,展示了事务在分区级别如何工作。我是南哥,一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。
676 3
掌握Kafka事务,看这篇就够了
|
人工智能 自然语言处理 架构师
2025年,租赁企业如何借瓴羊Data x AI实现弯道超车?
在新一代技术浪潮下,数据智能正深刻重塑租赁行业。阿里云瓴羊联合得宸科技推出大模型解决方案,助力租赁企业实现智能化转型。通过融合通义千问与专业数据库,方案覆盖经营分析、风险识别等9大场景,推动业务全流程重构,构建以数据驱动和智能引领的增长引擎,赋能行业高质量发展。
649 0
|
机器学习/深度学习 算法 TensorFlow
Python 强化学习实用指南:1~5
Python 强化学习实用指南:1~5
519 1
|
JSON 移动开发 算法
从JDK8飞升到JDK17,再到未来的JDK21
2022年,Spring6和 SpringBoot3都推出了,在此之前,Java社区很坚挺,一直是&quot;新版任你发,我用Java 8&quot;,不管新版本怎么出,很少有人愿意升级。 这一次,Spring 直接来了个大招,SpringBoot3和Spring6的最低依赖就是JDK17!跨过 JDK 8-16,直接升级到 JDK 17。那么为什么是 JDK 17呢?
31168 24
从JDK8飞升到JDK17,再到未来的JDK21
vs code常见的查找快捷键大全
【11月更文挑战第1天】本文介绍了 VS Code 中的基本查找和替换操作,包括在当前文件中查找(Ctrl + F)、查找替换(Ctrl + H)、查找下一个(F3)和查找上一个(Shift + F3)。还涵盖了在多个文件中查找(Ctrl + Shift + F)和查找替换(Ctrl + Shift + H),以及符号查找相关操作,如转到符号(Ctrl + T)和在文件中查找符号(Ctrl + Shift + O)。这些快捷键和功能帮助用户高效地管理和编辑代码。
3359 2
|
Oracle NoSQL 关系型数据库
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
3413 3
|
前端开发
HTML+CSS 速成10分钟!一键实现你的后台管理系统首页梦想!
HTML+CSS 速成10分钟!一键实现你的后台管理系统首页梦想!
|
Ubuntu Linux Docker
window10下安装ubuntu系统以及docker使用
window10下安装ubuntu系统以及docker使用
711 1