实现高效消息处理:在 Spring Boot 中使用 Redis Stream

Redis,作为一个多功能的内存数据结构存储,提供了各种数据结构来满足不同的需求。Redis Stream,作为其提供的一种数据结构,是构建复杂消息处理系统的理想选择。与 Redis 的传统发布订阅模式相比,Stream 提供了更高级的特性,如消费者组和消息确认机制。

理解 Redis Stream

Redis Stream 是 Redis 5.0 引入的一个新的数据类型,它本质上是一个日志数据结构。每个条目都包含一个唯一的序列号和一个键值对。Stream 主要用于存储一系列的事件或消息,这些消息可以由一个或多个消费者消费。

特性

消费者组:类似于 Kafka 中的消费者组,可以确保每条消息只被组内的一个消费者处理。

消息确认:消费者在处理完消息后可以发送确认,确保消息不会被再次处理。

持久化:Stream 中的消息是持久化的,即使在服务器重启后也不会丢失。

应用场景

假设我们有一个应用管理系统,需要在添加新的应用时通知其他服务进行处理。如果用redis发布订阅机制来写的话,若消费者服务多节点,又会发生重复消费的问题,而redis发布订阅机制事实上并没有消费者组的概率,无法避免这个问题。这个过程非常适合使用 Redis Stream 来实现,stream中有消费者组的概念,和rocketmq一样,我们可以创建一个流来保存新应用的信息,并设置消费者来处理这些信息。

Spring Boot 中的实现

配置 RedisTemplate

首先,确保在你的 Spring Boot 应用中已经配置了 RedisTemplate。以下是一个基础的配置示例:

java 复制代码
 
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        return template;
    }
}

发布消息

在我们的应用管理服务中,当添加一个新应用时,我们需要将应用的信息发送到 Redis Stream。

java 复制代码
@RestController
@RequestMapping("/api/applications")
public class ApplicationController {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @PostMapping("/add")
    public ResponseEntity<String> addApplication(@RequestBody SysApplication sysApplication) {
        // 保存应用逻辑...
        
        // 发布消息到 Redis Stream
        Map<String, Object> messageData = new HashMap<>();
        messageData.put("app", sysApplication);
        redisTemplate.opsForStream().add("applications_stream", messageData);

        return ResponseEntity.ok("Application added successfully");
    }
}

消费消息

创建一个服务来定期从 Stream 读取并处理消息。并设置消费者组,这样就避免了多节点情况下,重复消费的问题

java 复制代码
@Service
public class ApplicationStreamConsumer {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Scheduled(fixedRate = 10000)
    public void consumeMessages() {
        String streamKey = "applications_stream";
        String groupName = "app_group";
        String consumerName = "app_consumer_" + UUID.randomUUID().toString();

        // 创建消费者组
        try {
            redisTemplate.opsForStream().createGroup(streamKey, groupName);
        } catch (Exception e) {
            // 组可能已经存在,忽略异常
        }

        // 读取并处理消息
        List<MapRecord<String, Object, Object>> messages = redisTemplate.opsForStream()
            .read(Consumer.from(groupName, consumerName),
                  StreamReadOptions.empty().block(Duration.ofMillis(10000)),
                  StreamOffset.create(streamKey, ReadOffset.lastConsumed()));

        for (MapRecord<String, Object, Object> message : messages) {
            // 处理消息逻辑...
            // 确认消息
            redisTemplate.opsForStream().acknowledge(streamKey, groupName, message.getId());
        }
    }
}

在这个服务中,我们使用 @Scheduled 注解定期执行消息消费逻辑。每次从 Stream 读取消息后,我们处理消息并发送确认,以确保消息不会被重复处理。

使用 Redis Stream 在 Spring Boot 中实现消息的发布和消费是一个高效且可靠的方法,特别适用于构建需要确保消息顺序和可靠性的复杂系统。通过利用 Redis Stream 的高级特性,如消费者组和消息确认,我们可以构建一个强大的事件驱动架构,为微服务和分布式系统提供强有力的支持。

相关推荐
xo1988201111 分钟前
鸿蒙人脸识别
redis·华为·harmonyos
初晴~32 分钟前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·
盖世英雄酱5813638 分钟前
InnoDB 的页分裂和页合并
数据库·后端
小_太_阳1 小时前
Scala_【2】变量和数据类型
开发语言·后端·scala·intellij-idea
直裾1 小时前
scala借阅图书保存记录(三)
开发语言·后端·scala
黑胡子大叔的小屋1 小时前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
星就前端叭2 小时前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
计算机毕设孵化场2 小时前
计算机毕设-基于springboot的校园社交平台的设计与实现(附源码+lw+ppt+开题报告)
spring boot·课程设计·计算机毕设论文·计算机毕设ppt·计算机毕业设计选题推荐·计算机选题推荐·校园社交平台
苹果醋33 小时前
Golang的文件加密工具
运维·vue.js·spring boot·nginx·课程设计
小林coding3 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云