返利APP排行榜数据实时更新:基于 WebSocket 与 Redis 的高并发数据推送技术

大家好,我是阿可,微赚淘客系统及省赚客APP创始人,是个冬天不穿秋裤,天冷也要风度的程序猿!

在返利APP运营中,用户对排行榜数据的实时性要求极高——无论是“今日收益TOP10”还是“热门商品销量榜”,延迟超过1秒就可能影响用户体验。传统的轮询方案不仅会造成服务器资源浪费,还无法满足高并发场景下的实时推送需求。本文将基于WebSocket的全双工通信能力与Redis的高性能缓存特性,提供一套可落地的高并发数据推送方案,全程附带完整Java代码实现。
返利 APP 排行榜

一、技术选型核心依据

1.1 WebSocket 替代轮询的必然性

传统轮询通过客户端定时发送HTTP请求获取数据,存在两大问题:一是空请求占比高(当数据无更新时,请求仍会占用带宽与服务器资源);二是实时性差(轮询间隔决定了数据延迟)。而WebSocket通过一次TCP握手建立持久连接,服务器可主动向客户端推送数据,推送延迟可控制在100ms内,且单个连接的资源占用仅为HTTP轮询的1/10。

1.2 Redis 高并发支撑能力

排行榜数据需频繁更新(如用户返利金额变动)与查询,Redis的Sorted Set(ZSet) 结构天然适合排序场景,支持O(logN)复杂度的插入、删除与排序操作。同时,Redis的发布订阅(Pub/Sub)功能可实现数据更新后的实时通知,配合WebSocket完成端到端推送。

二、核心技术实现(Java代码)

2.1 Redis 排行榜操作封装(cn.juwatech.redis.RankRedisService)

package cn.juwatech.redis;import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.Set;@Service
public class RankRedisService {// 返利排行榜Redis Key前缀private static final String RANK_KEY_PREFIX = "rebate:rank:";// 排行榜数据更新订阅频道public static final String RANK_UPDATE_CHANNEL = "rebate:rank:update";@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Resourceprivate ZSetOperations<String, Object> zSetOperations;/*** 更新用户排行榜数据* @param rankType 排行榜类型(如"daily_income":日收益,"month_sales":月销量)* @param userId 用户ID* @param score 排序分数(如收益金额、销量)*/public void updateRankScore(String rankType, String userId, double score) {String rankKey = getRankKey(rankType);// 存储用户ID与对应分数到ZSet,分数相同按插入顺序排序zSetOperations.add(rankKey, userId, score);// 限制排行榜长度(仅保留前100名,避免数据膨胀)zSetOperations.removeRange(rankKey, 0, -101);// 发布数据更新通知redisTemplate.convertAndSend(RANK_UPDATE_CHANNEL, rankType);}/*** 获取排行榜前N名数据* @param rankType 排行榜类型* @param topSize 前N名* @return 有序集合(score从高到低)*/public Set<ZSetOperations.TypedTuple<Object>> getTopRank(String rankType, int topSize) {String rankKey = getRankKey(rankType);// ZSet默认按score升序,reverseRange按降序获取前topSize条return zSetOperations.reverseRangeWithScores(rankKey, 0, topSize - 1);}/*** 构建完整Redis Key*/private String getRankKey(String rankType) {return RANK_KEY_PREFIX + rankType;}
}

2.2 WebSocket 连接管理与数据推送(cn.juwatech.websocket.RankWebSocketServer)

基于Spring WebSocket实现,支持用户建立连接时订阅指定排行榜,数据更新时定向推送。

package cn.juwatech.websocket;import cn.juwatech.redis.RankRedisService;
import cn.juwatech.redis.RankRedisService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import javax.annotation.Resource;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Component
public class RankWebSocketServer extends TextWebSocketHandler implements MessageListener {// 存储用户会话与订阅的排行榜类型(线程安全)private final Map<WebSocketSession, String> sessionRankMap = new ConcurrentHashMap<>();// 排行榜Redis服务@Resourceprivate RankRedisService rankRedisService;/*** 客户端建立WebSocket连接时触发*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {// 从连接参数中获取用户订阅的排行榜类型(如?rankType=daily_income)String rankType = session.getUri().getQuery().split("=")[1];sessionRankMap.put(session, rankType);// 首次连接时推送当前排行榜数据pushRankData(session, rankType);}/*** 接收Redis数据更新通知,推送排行榜数据*/@Overridepublic void onMessage(Message message, byte[] pattern) {// 解析Redis订阅消息(排行榜类型)String rankType = new String(message.getBody());// 遍历订阅该排行榜的所有会话,推送数据sessionRankMap.forEach((session, type) -> {if (rankType.equals(type) && session.isOpen()) {pushRankData(session, rankType);}});}/*** 推送排行榜数据到客户端*/private void pushRankData(WebSocketSession session, String rankType) {try {// 从Redis获取前10名排行榜数据var topRank = rankRedisService.getTopRank(rankType, 10);// 构建JSON格式响应(包含排行榜类型、数据列表)JSONObject response = new JSONObject();response.put("rankType", rankType);response.put("data", topRank.stream().map(tuple -> {JSONObject item = new JSONObject();item.put("userId", tuple.getValue());item.put("score", tuple.getScore());return item;}).toList());// 发送文本消息session.sendMessage(new TextMessage(response.toJSONString()));} catch (IOException e) {// 记录推送失败日志(实际项目中需结合监控告警)e.printStackTrace();}}/*** 客户端关闭连接时清理会话*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessionRankMap.remove(session);}
}

2.3 WebSocket 配置类(cn.juwatech.config.WebSocketConfig)

package cn.juwatech.config;import cn.juwatech.redis.RankRedisService;
import cn.juwatech.websocket.RankWebSocketServer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;import javax.annotation.Resource;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Resourceprivate RankWebSocketServer rankWebSocketServer;/*** 注册WebSocket处理器,配置访问路径*/@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {// 允许跨域访问,配置WebSocket访问路径为/ws/rebate-rankregistry.addHandler(rankWebSocketServer, "/ws/rebate-rank").setAllowedOrigins("*");}/*** 配置Redis消息监听器,订阅排行榜更新频道*/@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,MessageListenerAdapter listenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);// 订阅排行榜更新频道container.addMessageListener(listenerAdapter, new PatternTopic(RankRedisService.RANK_UPDATE_CHANNEL));return container;}/*** 绑定Redis消息监听器与WebSocket处理器*/@Beanpublic MessageListenerAdapter listenerAdapter(RankWebSocketServer rankWebSocketServer) {return new MessageListenerAdapter(rankWebSocketServer);}
}

三、高并发场景优化策略

3.1 连接数承载优化

单个WebSocket服务器的并发连接数受限于操作系统文件句柄数(默认1024),生产环境需通过以下配置提升承载能力:

  1. 调整Linux系统参数:echo "net.core.somaxconn=65535" >> /etc/sysctl.conf(最大监听队列数);
  2. 采用Nginx反向代理实现WebSocket集群负载均衡,配置示例:
http {upstream websocket_servers {server 192.168.1.100:8080 weight=1;server 192.168.1.101:8080 weight=1;}server {listen 80;location /ws/rebate-rank {# 启用WebSocket代理proxy_pass http://websocket_servers;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header Host $host;}}
}

3.2 Redis 性能优化

  1. 开启Redis持久化(AOF+RDB),避免排行榜数据丢失;
  2. 对排行榜Key设置过期时间(如日收益榜24小时过期),减少内存占用;
  3. 使用Redis集群(3主3从),提升读吞吐量与可用性。

四、客户端接入示例(JavaScript)

// 建立WebSocket连接(根据环境替换域名)
const rankType = "daily_income"; // 订阅日收益排行榜
const ws = new WebSocket(`ws://your-domain.com/ws/rebate-rank?rankType=${rankType}`);// 接收服务器推送的排行榜数据
ws.onmessage = function(event) {const rankData = JSON.parse(event.data);console.log("实时排行榜更新:", rankData);// 渲染排行榜到页面(示例:更新表格)renderRankTable(rankData.data);
};// 连接关闭处理
ws.onclose = function() {console.log("WebSocket连接关闭,尝试重连...");// 重连逻辑(避免频繁重连,添加延迟)setTimeout(() => window.location.reload(), 3000);
};// 渲染排行榜表格
function renderRankTable(data) {const table = document.getElementById("rankTable").getElementsByTagName("tbody")[0];table.innerHTML = "";data.forEach((item, index) => {const row = table.insertRow();row.insertCell(0).textContent = index + 1; // 排名row.insertCell(1).textContent = item.userId; // 用户IDrow.insertCell(2).textContent = (item.score).toFixed(2); // 收益金额(保留2位小数)});
}

本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/923627.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/923627.shtml
英文地址,请注明出处:http://en.pswp.cn/news/923627.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[论文阅读] 人工智能 + 软件工程 | 告别冗余HTML与高算力消耗:EfficientUICoder如何破解UI2Code的token难题

告别冗余HTML与高算力消耗&#xff1a;EfficientUICoder如何破解UI2Code的token难题 论文信息信息类别具体内容论文原标题EfficientUICoder: A Dual-Modal Token Compression Framework for UI-to-Code Generation with Multimodal Large Language Models论文链接https://arxiv…

【STM32项目开源】STM32单片机智能语音风扇控制系统

目录 一、设计背景和意义 1.1设计背景&#xff1a; 1.2设计意义&#xff1a; 二、实物展示 三、硬件功能介绍 2.1 硬件清单&#xff1a; 2.2 功能介绍&#xff1a; 四、软件设计流程图 五、硬件PCB展示 六、软件主函序展示 七、单片机实物资料 资料获取 查看主页介…

git clone vllm

这个错误不是 vLLM 本身的问题&#xff0c;而是 pip 在 clone GitHub 仓库时失败了&#xff1a; error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush after ref listing根因通常是&#xff1a; 网络问题&#xff08;访问 GitHub 被中断 / 代理…

光谱相机的新兴领域应用

光谱相机在‌新兴领域‌的应用正快速拓展&#xff0c;结合‌AI、纳米技术、量子传感‌等前沿科技&#xff0c;突破传统检测极限。以下是六大最具潜力的新兴应用方向及技术突破点&#xff1a;‌1. 元宇宙与数字孪生‌‌应用场景‌&#xff1a;‌虚拟材质建模‌&#xff1a;通过高…

深入理解数据结构之复杂度

文章目录1.数据结构前言1.1 数据结构1.2 算法2.算法效率2.1 复杂度的概念2.2 复杂度的重要性3.1 大O的渐进表式法3.2 时间复杂度计算示例3.2.1 示例13.2.2 示例23.2.3 示例33.2.4 示例43.2.5 示例53.2.6 示例63.2.7 示例74.空间复杂度4.1 空间复杂度计算示例4.1.1 示例14.1.2 示…

【Vue3】10-编写vue项目时,ref的应用(2)

合集篇&#xff1a; 1.【Vue3】创建并运行一个简易的Vue3项目 2.【Vue3】编写vue实现一个简单效果&#xff0c;并使用setup糖简化代码 目录refref 定义对象类型的响应式数据1. 概念理解a. 概念b. 分析2. 代码实操代码场景步骤一&#xff1a;导入ref步骤二&#xff1a;修改数据形…

clickhouse 中SUM(CASE WHEN ...) 返回什么类型?

文章目录clickhouse 中SUM(CASE WHEN ...) 返回什么类型&#xff1f;CASE WHENSUM(CASE WHEN ...) 返回什么类型&#xff1f;clickhouse 中SUM(CASE WHEN …) 返回什么类型&#xff1f; CASE WHEN ClickHouse中的CASE WHEN用法与SQL标准中的用法基本相同&#xff0c;用于实现…

【算法】C语言多组输入输出模板

在 C语言 里&#xff0c;“多组输入输出”是很多在线评测系统&#xff08;OJ&#xff09;常见的模式&#xff0c;通常有两种情况&#xff1a;1. 输入到文件结束&#xff08;EOF&#xff09;比如题目没有告诉有多少组数据&#xff0c;就需要一直读直到输入结束。#include <st…

【Ubuntu】sudo apt update出现E :仓库***没有Release文件

【Ubuntu】sudo apt update出现E &#xff1a;仓库***没有Release文件 1 问题描述 在执行sudo apt update更新一下软件包时出现了如下报错 E: 仓库***没有Release 文件。 N: 无法安全地用该源进行更新&#xff0c;所以默认禁用该源。 N:参见apt-secure&#xff08;8&#xf…

全球后量子迁移进展:区域特色与产业落地差异

一、量子威胁具象化&#xff1a;从技术风险到产业冲击量子计算对传统密码体系的威胁已从理论走向现实&#xff0c;其破坏性不仅体现在算法破解效率的飞跃&#xff0c;更渗透到数据全生命周期的安全防护中。以金融领域为例&#xff0c;2024 年国际安全机构模拟实验显示&#xff…

贪心算法应用:决策树(ID3/C4.5)详解

Java中的贪心算法应用&#xff1a;决策树&#xff08;ID3/C4.5&#xff09;详解 决策树是一种常用的机器学习算法&#xff0c;它通过递归地将数据集分割成更小的子集来构建树形结构。ID3和C4.5是两种经典的决策树算法&#xff0c;它们都使用了贪心算法来选择最优的特征进行分割…

华为任旭东:开源协作,激发创新,共创智能世界 | GOSIM HANGZHOU 2025

GOSIM HANGZHOU 2025峰会盛大开幕&#xff0c;华为首席开源联络官、CNCF基金会董事任旭东以《开源协作&#xff0c;激发创新&#xff0c;共创智能世界》为题发表Keynote演讲。颠覆性技术到工业应用的转换时间越来越短&#xff0c;AI技术正在推动传统软件产业的演进&#xff0c;…

本地部署 GPS 跟踪系统 Traccar 并实现外部访问

Traccar 是一款集成了强大的 java 后端服务的 GPS 跟踪系统 。它支持在多种设备使用&#xff0c;在物流运输、资产管理和个人安全等领域应用。本文将详细的介绍如何利用 Docker 在本地部署 Traccar 并结合路由侠实现外网访问本地部署的 Traccar 。 第一步&#xff0c;本地部署…

【开题答辩全过程】以 “川趣玩”旅行团预定微信小程序为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

Android Doze低电耗休眠模式 与 WorkManager

1. Doze模式下&#xff0c;WorkManager setInitialDelay设置小于15分钟&#xff0c;被系统强制到15分钟执行&#xff0c;怎么办 ? Android 拥有两项省电功能&#xff0c;通过管理设备未连接电源时应用的行为来延长用户电池续航时间&#xff1a;低电耗模式 (Doze) 和应用待机模…

iOS 能耗监控与电池优化实战:如何查看App耗电量、分析CPU、GPU内存使用、(uni-app iOS开发性能调试指南)

在 iOS 应用开发中&#xff0c;能耗与电池消耗是用户最直观的体验指标。 即便功能完善&#xff0c;如果 App 存在以下问题&#xff1a; 电池掉电快、设备发热严重&#xff1b;后台任务执行过多&#xff1b;页面渲染与文件操作引发 CPU/GPU 过载&#xff1b;日志或缓存导致频繁 …

Git 本地分支推送多个远程分支

方法一&#xff1a;一次性推送命令 命令格式&#xff1a; git push <远程仓库名> <本地分支引用>:<远程分支名1> <本地分支引用>:<远程分支名2> ...具体步骤&#xff1a; 确保你的代码修改已经提交到了本地分支 git add . git commit -m "你…

抖音私信评论互动消息通知监听自动获取,通过qq机器人转发到qq来通知

抖音私信评论互动消息通知监听自动获取&#xff0c;通过qq机器人转发到qq来通知 如果不是抖音平台&#xff0c;其他平台也类似的&#xff0c;也可以实现&#xff0c;只是目前懒得写了 本期视频点赞过10个就开源代码 有需要的人可以在视频底下留言 需求反馈多的我可以实现

UVM验证工具--gvim

目录 gvim语法高亮 gvim支持git Linux环境自带gvim工具&#xff0c;我们需要做如下设置&#xff1a; 支持UVM、SystemVerilog、verilog语法高亮支持git&#xff08;实时显示对文件的修改&#xff09; gvim语法高亮 gvim支持git

MyBatis 从入门到精通(第二篇)—— 核心架构、配置解析与 Mapper 代理开发

在第一篇博客中&#xff0c;我们掌握了 MyBatis 的基础概念与环境搭建&#xff0c;成功通过简单查询实现了数据持久化。但要真正用好 MyBatis&#xff0c;还需深入理解其 “内部工作原理” 与 “企业级开发规范”。本篇将聚焦三大核心&#xff1a;MyBatis 架构与核心类、全局配…