Spring Boot中的SSE与缓存集成:使用Redis加速事件推送

Spring Boot中的SSE与缓存集成:使用Redis加速事件推送

实时事件推送在现代Web应用中变得越来越重要,而Spring Server-Sent Events(SSE)为实现实时推送提供了一种简单而有效的方式。然而,随着应用规模的增长,实时事件推送可能会面临性能瓶颈。为了解决这个问题,我们可以考虑将Spring Boot中的SSE与缓存(如Redis)集成,以加速事件推送,提高系统的性能和可扩展性。

基础SSE配置

首先,我们需要建立基础的Spring Boot SSE配置。我们可以使用SseEmitter来处理SSE请求,并通过WebSocket进行实时事件推送。

@RestController
public class SSEController {@Autowiredprivate SimpMessageSendingOperations messagingTemplate;private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();@GetMapping("/sse/{clientId}")public SseEmitter handleSSE(@PathVariable String clientId) {SseEmitter emitter = new SseEmitter();// 处理连接关闭时的清理逻辑emitter.onCompletion(() -> cleanupEmitter(clientId));// 添加到emitters集合emitters.put(clientId, emitter);return emitter;}private void cleanupEmitter(String clientId) {// 清理资源,例如从emitters集合中移除对应的emitteremitters.remove(clientId);}// 其他处理SSE请求的逻辑...
}

在上述代码中,我们创建了一个SseEmitter,并在onCompletion回调中定义了连接关闭时的清理逻辑。emitters集合用于存储每个客户端的SseEmitter对象,以便后续进行事件推送。

缓存与事件推送集成

现在,让我们将缓存(Redis)集成到SSE事件推送中,以提高性能。

1 、集成Redis作为缓存

首先,我们需要在Spring Boot项目中集成Redis作为缓存。可以通过在pom.xml文件中添加相应的依赖,以及在application.properties中配置Redis连接信息来实现。

<!-- pom.xml -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
# application.properties
spring.redis.host=127.0.0.1
spring.redis.port=6379

2 、使用Redis进行事件推送

在SSE事件推送中,我们可以使用Redis的消息发布/订阅机制。每当有新的实时事件产生时,我们将事件发送到Redis的某个频道,然后所有订阅了该频道的客户端都会接收到相应的事件。

@Component
public class RedisEventPublisher {@Autowiredprivate SimpMessageSendingOperations messagingTemplate;@Autowiredprivate StringRedisTemplate stringRedisTemplate;public void publishEvent(String clientId, Event event) {// 将事件序列化为JSON字符串String eventJson = convertEventToJson(event);// 发布事件到Redis频道stringRedisTemplate.convertAndSend("sse-events:" + clientId, eventJson);}private String convertEventToJson(Event event) {// 将事件对象转换为JSON字符串// 使用Jackson等库进行JSON序列化// ...return jsonString;}
}

在上述代码中,RedisEventPublisher负责将事件发布到Redis频道。每个客户端的频道名由"sse-events:" + clientId构成,确保每个客户端都有一个独立的频道。

3 、处理Redis频道消息并推送事件

我们需要编写一个监听器来处理Redis频道的消息,并将事件推送给相应的客户端。

@Component
public class RedisMessageListener {@Autowiredprivate SimpMessageSendingOperations messagingTemplate;@MessageMapping("/subscribe")public void subscribe(@Payload String clientId, SimpMessageHeaderAccessor headerAccessor) {// 订阅Redis频道stringRedisTemplate.execute((RedisCallback<Void>) connection -> {connection.subscribe(new MessageListener() {@Overridepublic void onMessage(Message message, byte[] pattern) {// 处理接收到的事件消息String eventJson = new String(message.getBody(), StandardCharsets.UTF_8);Event event = convertJsonToEvent(eventJson);// 将事件推送给客户端messagingTemplate.convertAndSendToUser(clientId, "/queue/sse", event);}}, ("sse-events:" + clientId).getBytes(StandardCharsets.UTF_8));return null;});}private Event convertJsonToEvent(String eventJson) {// 将JSON字符串转换为事件对象// 使用Jackson等库进行JSON反序列化// ...return event;}
}

在上述代码中,一RedisMessageListener通过@MessageMapping("/subscribe")监听客户端订阅事件。当客户端订阅时,它会订阅对应的Redis频道,并在接收到频道

消息时处理事件,并使用
SimpMessageSendingOperations将事件推送给客户端。

性能考虑与优化

为了确保性能和可扩展性,我们可以考虑以下几个方面的优化:

1 、事件批处理

当有多个事件需要推送时,可以考虑批处理事件而不是逐个推送。通过使用stringRedisTemplate的convertAndSend方法,我们可以将多个事件以列表的形式一次性发送到Redis频道,减少网络开销。

public void publishEvents(String clientId, List<Event> events) {// 将事件列表转换为JSON字符串列表List<String> eventJsonList = events.stream().map(this::convertEventToJson).collect(Collectors.toList());// 一次性发送事件列表到Redis频道stringRedisTemplate.convertAndSend("sse-events:" + clientId, eventJsonList);
}

2 、事件过滤

在事件推送之前,可以考虑对事件进行过滤,只推送客户端感兴趣的事件。这可以通过在subscribe方法中增加逻辑来实现。

public void subscribe(@Payload String clientId, SimpMessageHeaderAccessor headerAccessor) {// 订阅Redis频道,仅接收客户端感兴趣的事件stringRedisTemplate.execute((RedisCallback<Void>) connection -> {connection.subscribe(new MessageListener() {@Overridepublic void onMessage(Message message, byte[] pattern) {// 处理接收到的事件消息String eventJson = new String(message.getBody(), StandardCharsets.UTF_8);Event event = convertJsonToEvent(eventJson);// 仅推送客户端感兴趣的事件if (isInterested(clientId, event)) {messagingTemplate.convertAndSendToUser(clientId, "/queue/sse", event);}}}, ("sse-events:" + clientId).getBytes(StandardCharsets.UTF_8));return null;});
}private boolean isInterested(String clientId, Event event) {// 判断客户端是否对该事件感兴趣// ...return true;
}

通过增加isInterested方法,我们可以根据具体业务逻辑判断客户端是否对某个事件感兴趣,从而减少不必要的事件推送。

总 结

通过将Spring Boot中的SSE与缓存(Redis)集成,我们实现了实时事件推送的性能优化。通过使用Redis作为事件缓存,我们可以加速事件推送,提高系统的性能和可扩展性。在优化过程中,我们考虑了事件批处理、事件过滤等方面,以确保推送的事件是高效且符合客户端需求的。这种集成方式不仅能够提升用户体验,而且在大规模应用中具有良好的性能表现。

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

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

相关文章

【UI】element-ui的el-dialog的遮罩层在模态框的前面bug

最近在写element ui 的时候使用dialog组件&#xff0c;偶然出现了这种情况 原因&#xff1a; 是因为遮罩层插入进了body标签下&#xff0c;z-index高于当前父元素。 解决&#xff1a;在el-dialog标签里加上:modal-append-to-body"false"就可以了。 饿了么官网文档&a…

Ardupilot OpenIPC 基于WFB-NG构架分析和数据链路思考

Ardupilot & OpenIPC & 基于WFB-NG构架分析和数据链路思考 1. 源由2. OpenIPC安装2.1 安装2.2 配置2.2.1 天空端配置文件2.2.2 地面端配置文件 2.3 当前配置选择 3. WFB-NG安装3.1 RTL8812AU安装3.1.1 驱动安装3.1.2 定位设备 3.2 wfb-ng安装3.2.1 传输层安装3.2.2 配置…

照片相似性搜索引擎Embed-Photos;赋予大型语言模型(LLMs)视频和音频理解能力;OOTDiffusion的基础上可控制的服装驱动图像合成

✨ 1: Magic Clothing Magic Clothing是一个以可控制的服装驱动图像合成为核心的技术项目&#xff0c;建立在OOTDiffusion的基础上 Magic Clothing是一个以可控制的服装驱动图像合成为核心的技术项目&#xff0c;建立在OOTDiffusion的基础上。通过使用Magic Clothing&#xf…

Jenkins CI/CD 持续集成专题二 Jenkins 相关问题汇总

一 问题一 pod [!] Unknown command: package 1.1 如果没有安装过cocoapods-packager&#xff0c;安装cocoapods-packager&#xff0c;sudo gem install cocoapods-packager 1.2 如果已经安装cocoapods-packager&#xff0c;还是出现上面的错误&#xff0c;有可能是pod的安…

javaScript数组-(进阶算法)-计算滑动窗口最大值

滑动窗口 给定数组中的连续子数组&#xff0c;使其和达到最大值&#xff0c;并记录该子数组的起始和结束索引。最后&#xff0c;将最大和及其起始和结束索引存储在数组当中。 const arr [-1,-2,3,9,-4,8];let max null; let sum null;let i0,j0;let length arr.length;if…

什么是康养专业产教融合实训中心

康养专业产教融合实训中心是高等教育体系中的一种创新型教学设施&#xff0c;它整合了产业实践与教学研究的双重功能&#xff0c;旨在培养适应康养产业发展需求的专业人才。这种实训中心通过深度对接康养产业链上的各个环节&#xff0c;创建一个集教学、实训、科研、服务于一体…

什么是中医养生康复实训中心

中医养生康复实训中心是高等教育机构中专门设立的&#xff0c;集教学、实践、研究于一体的综合性教育平台&#xff0c;主要面向中医养生康复、针灸推拿、康复治疗技术等专业学生&#xff0c;目的是传承和发扬中医养生康复理念&#xff0c;培养具有扎实中医理论基础和实践经验的…

防、治、管融合一体化旅居健康守护系统

随着人口老龄化趋势的加剧和人们生活水平的提高&#xff0c;养老服务需求不断增长。旅居养老作为一种新型的养老模式&#xff0c;逐渐受到广大老年人的青睐。在生命健康服务运营平台中&#xff0c;为了给老人提供全方位、个性化的生命健康服务&#xff0c;我们平台也特意开设了…

31 信号量

概念 共享内存在通信的过程中&#xff0c;没有任何保护机制。当A进程写入了一部分&#xff0c;就被B、拿走了&#xff0c;导致双方发和收的数据不完整&#xff0c;数据不一致问题 1.A和B看到同一份资源&#xff0c;共享资源&#xff0c;如果不加保护&#xff0c;会导致数据不…

Uni-App 生命周期

在 Uni-App 中&#xff0c;页面和组件都有自己的生命周期函数&#xff0c;以下是一些常用的生命周期函数&#xff1a; 页面生命周期函数&#xff1a; onLoad: 页面加载时触发 onShow: 页面显示时触发 onReady: 页面初次渲染完成时触发 onHide: 页面隐藏时触发 onUnload: …

PyCharm添加外部工具

QtDesigner 可视化UI设计客户端工具 路径&#xff1a;File | Settings | Tools | External Tools点号&#xff0c;给External Tools组添加一个条目&#xff0c;填写如下内容 Name&#xff1a;QtDesignerProgram&#xff1a;C:\Users\用户名\AppData\Local\Programs\Python\Py…

在誉天学习云计算HCIE,担心考试考不过?

誉天定制化课程内容覆盖了所有考试重点&#xff0c;可以系统地掌握理论与实践知识。 对于笔试&#xff0c;类似于备考驾照理论学习阶段&#xff0c;誉天为大家提供在线模拟测试系统&#xff0c;帮助大家掌握云计算笔试考点。笔试通过后&#xff0c;18个月内&#xff08;一年半…

【QT进阶】Qt http编程之nlohmann json库使用的简单介绍

往期回顾 【QT进阶】Qt http编程之http相关类的简单介绍-CSDN博客 【QT进阶】Qt http编程之用户登录注册功能实现-CSDN博客 【QT进阶】Qt http编程之json解析的简单介绍-CSDN博客 【QT进阶】Qt http编程之nlohmann json库使用的简单介绍 一、nlohman json库 1、C常用Json库 J…

Github 2024-04-22 开源项目日报Top10

根据Github Trendings的统计,今日(2024-04-22统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4C++项目2Go项目2JavaScript项目1TypeScript项目1非开发语言项目1Zig项目1免费编程书籍和学习资源清单 创建周期:3762 天协议类型:…

Docker 哲学 - docker save | load | export | import 及实践

当我们说 "归档文件包含了容器的所有文件&#xff0c;但不包含容器的元数据和配置"&#xff0c;我们是指 docker export 命令导出的 tar 归档文件包含了容器的文件系统中的所有文件&#xff0c;包括应用程序、库、数据等。但是&#xff0c;这个归档文件不包含关于容器…

Python 网络与并发编程(一)

文章目录 并发编程介绍串行、并行与并发的区别进程、线程、协程的区别进程线程协程 并发编程解决方案同步和异步介绍 并发编程介绍 串行、并行与并发的区别 有任务A、B、C&#xff0c;一个CPU去执行他们&#xff0c;有几种方式 1、一个cpu按顺序执行ABC&#xff0c;这就是串行…

go语言并发实战——日志收集系统(六) 编写日志收集系统客户端

上节回顾 在上一篇文章中我们介绍了编写客户端的四个步骤&#xff0c;分别是&#xff1a; 读取配置文件&#xff0c;寻找日志路径初始化服务根据日志路径l来收集日志将收集到的日志发送Kafka中 关于上述的内容博主画了一个思维导图(有点丑&#xff0c;大家勉强看看&#xff0…

燃冬之yum、vim和你

了解了很多指令和权限&#xff0c;搞点真枪实弹来瞅瞅 学Linux不是天天就在那掰扯指令玩&#xff0c;也不是就研究那个权限 准备好迎接Linux相关工具的使用了么码农桑~ yum 软件包 什么是软件包呢&#xff1f; 首先来举个生活中常见点的例子&#xff1a;比如我的手机是华为…

Leetcode 20:有效的括号

给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括…

【项目部署-apache】windows系统下apache部署django+channels

一、系统环境 1、原生的python3.8.5&#xff08;默认安装&#xff0c;不更改安装目录&#xff09;&#xff0c;不要使用Anaconda做虚拟环境。 2、在windows系统下需要&#xff0c;mod_wsgi 模块。 创建虚拟环境&#xff1a;(在当前目录下创建名为 gzgs_alert 的虚拟环境) py…