Redis5 的新特性 Redis Stream整合Spring Boot

Redis Stream 介绍

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。
而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

在这里插入图片描述

Redis Stream 基本命令

  1. 使用 XADD命令向队列添加消息,如果指定的队列不存在,则创建一个队列,XADD 语法格式:

XADD luolistream * name luoli

  • luolistream 队列名称,如果不存在就创建
  • * 消息 id,我们使用 * 表示由 redis 生成,可以自定义,但是要自己保证递增性
  • name luoli 发送的消息
  1. 使用 XGROUP CREATE 创建消费者组

XGROUP CREATE luolistream group-1 0

  • 最后一个0表示从头开始消费,也你可以使用$代替表示从尾部开始消费,只接受新消息
  • 发送进去的消息需要创建一个消费组来对消息进行消费,一个消费组中可以有多个消费者consumer,但是一个组中只会有一个消费者去消费掉当前的消息,和Kafka很类似。
  1. 消费消息

XREADGROUP GROUP group-1 consumer-luoli COUNT 1 STREAMS luolistream >

  • 会在group-1的消费组中创建一个消费者consumer-luoli来进行消费luolistream中的消息。

整合Spring Boot

第一步:创建消费对象 继承StreamListener 重写onMessage方法即可。

@Component
public class OrderStreamListener implements StreamListener<String, ObjectRecord<String, String>> {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void onMessage(ObjectRecord<String, String> message) {

        // 消息ID
        RecordId messageId = message.getId();

        // 消息的key和value
        String string = JSONUtil.toJsonStr(message.getValue());
        Order order = JSONUtil.toBean(string, Order.class);
        LOGGER.info("StreamMessageListener1  stream message。messageId={}, stream={}, body={}", messageId, message.getStream(), body);
        // 通过RedisTemplate手动确认消息
        this.stringRedisTemplate.opsForStream().acknowledge("group-1", message);
  
    }
}

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.stream.Consumer;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.connection.stream.ReadOffset;
import org.springframework.data.redis.connection.stream.StreamOffset;
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.time.Duration;

@Configuration
@Slf4j
public class RedisStream2 {

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;
    
    @Bean
    public StreamMessageListenerContainer<String, ObjectRecord<String, String>> ocrfristMyGroupStreamContainer(
            RedisConnectionFactory connectionFactory,
            OrderStreamListener streamListener) {
        StreamMessageListenerContainer<String, ObjectRecord<String, String>> container =
                streamContainer("mystream",  connectionFactory, streamListener);
        container.start();
        return container;
    }



    private StreamMessageListenerContainer<String, ObjectRecord<String, String>> streamContainer(String mystream ,RedisConnectionFactory connectionFactory,OrderStreamListener streamListener){

        StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> options = StreamMessageListenerContainer.StreamMessageListenerContainerOptions
                .builder()
                .pollTimeout(Duration.ofSeconds(1))
                .batchSize(10)
                .targetType(String.class)
                .executor(threadPoolTaskExecutor)
                .build();

        StreamMessageListenerContainer<String, ObjectRecord<String, String>> container = StreamMessageListenerContainer
                .create(connectionFactory, options);

        //指定消费最新的消息
        StreamOffset<String> offset = StreamOffset.create(mystream, ReadOffset.lastConsumed());

        //创建消费者
        Consumer consumer = Consumer.from("group-1", "consumer-1");

        StreamMessageListenerContainer.StreamReadRequest<String> streamReadRequest = StreamMessageListenerContainer.StreamReadRequest.builder(offset)
                .errorHandler((error)->log.error(error.getMessage()))
                .cancelOnError(e -> false)
                .consumer(consumer)
                //关闭自动ack确认
                .autoAcknowledge(false)
                .build();
        //指定消费者对象
        container.register(streamReadRequest, streamListener);
        return container;
    }
    
}

需要注意的是我们的key和group需要提前先创建好才行。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中使用Redis Stream进行批量消费可以通过以下步骤实现: 1. 首先,您需要在Spring Boot项目中配置Redis Stream。您可以使用Spring Data Redis来连接Redis数据库并创建Stream对象。 2. 创建一个消费者类,并使用@StreamListener注解指定要消费的Stream。您可以使用Spring Data Redis提供的StreamOperations接口来获取Stream。 3. 在消费者类中,创建一个方法来处理Stream消息。您可以使用Spring Data Redis提供的StreamMessage对象来获取Stream中的消息内容。 4. 使用@BatchSize注解来指定批量消费的大小。 以下是一个示例代码,展示了如何在Spring Boot中使用Redis Stream进行批量消费: ```java @Component public class StreamConsumer { @Autowired private StreamOperations<String, Object, Object> streamOperations; @StreamListener(target = "${spring.redis.stream.key}", condition = "${spring.redis.stream.enabled}", concurrency = "${spring.redis.stream.concurrency}") @BatchSize(max = 100) public void consume(StreamMessage<String, Object> message) { // 处理消息 } } ``` 在上面的示例中,我们使用了@BatchSize注解来指定每次处理100个消息。您可以根据需要调整批量大小。 同时,我们使用@StreamListener注解来指定要消费的Stream。注意,我们还可以使用条件表达式(condition)来控制是否启用Stream消费者,并使用并发度(concurrency)属性来指定消费者的线程数。 希望这个示例能够帮助您在Spring Boot中批量消费Redis Stream消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值