使用Redis实现轻量级消息队列

作者:

文章目录
  • Redis Pub/Sub 适用于 实时消息推送,但不支持消息持久化,如果消费者掉线,消息会丢失。 (1) 发布消息(生产者) import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class OrderService { private final StringRedisTemplate redisTemplate; public OrderService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void createOrder(Long orderId) { System.out.println(“订单创建成功: ” + orderId); // 发布消息 redisTemplate.convertAndSend(“order.channel”, orderId.toString()); } } (2) 订阅消息(消费者) import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.stereotype.Service; @Service public class NotificationService implements MessageListener { @Override public void onMessage(Message message, byte[] pattern) { String orderId = message.toString(); System.out.println(“【通知服务】收到订单创建消息:” + orderId); } } (3) 注册 Redis 监听器 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; @Configuration public class RedisPubSubConfig { @Bean public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(listenerAdapter, new PatternTopic(“order.channel”)); return container; } @Bean public MessageListenerAdapter listenerAdapter(NotificationService receiver) { return new MessageListenerAdapter(receiver, “onMessage”); } } 缺点 无持久化,消费者掉线后无法重新获取消息。 不支持消费组,多个消费者同时订阅时,所有都会收到消息(无法负载均衡)。
  • 使用 Redis List(LPUSH + RPOP)可以实现简单的任务队列,适用于任务异步处理,但不支持回溯消费。 (1) 生产者(推送任务) import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class OrderService { private final StringRedisTemplate redisTemplate; public OrderService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void createOrder(Long orderId) { System.out.println(“订单创建成功: ” + orderId); // 推送到队列 redisTemplate.opsForList().leftPush(“order.queue”, orderId.toString()); } } (2) 消费者(轮询获取任务) import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @Service public class NotificationService { private final StringRedisTemplate redisTemplate; public NotificationService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } @Scheduled(fixedDelay = 5000) // 每5秒轮询一次 public void processOrderQueue() { String orderId = redisTemplate.opsForList().rightPop(“order.queue”); if (orderId != null) { System.out.println(“【通知服务】处理订单:” + orderId); } } } 要想消费者能监听到消息并进行处理,需要在方法上添加@Scheduled注解,同时在服务启动类中添加@EnableScheduling注解,或者在配置类添加 import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.context.annotation.Configuration; @Configuration @EnableScheduling public class SchedulingConfig { } 缺点 无消费组,多个消费者时需要自行分配任务,可能会造成任务重复消费或丢失。 无持久化保障,如果任务未处理完,Redis 发生故障,任务可能会丢失。
  • Redis Stream 是 Redis 6.0 之后的特性,类似于 Kafka,支持持久化、消费组、多消费者模式。 (1) 生产者(推送事件) import org.springframework.data.redis.connection.stream.ObjectRecord; import org.springframework.data.redis.connection.stream.StreamRecords; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class OrderService { private final StringRedisTemplate redisTemplate; public OrderService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void createOrder(Long orderId) { System.out.println(“订单创建成功: ” + orderId); // 推送到 Redis Stream ObjectRecord<String, String> record = StreamRecords.newRecord() .ofObject(orderId.toString()) .withStreamKey(“order.stream”); redisTemplate.opsForStream().add(record); } } (2) 消费者(监听事件) import org.springframework.data.redis.connection.stream.MapRecord; import org.springframework.data.redis.connection.stream.ReadOffset; import org.springframework.data.redis.connection.stream.StreamMessageListenerContainer; import org.springframework.data.redis.connection.stream.StreamOffset; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.stream.StreamListener; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.time.Duration; import java.util.Collections; @Service public class NotificationService implements StreamListener<String, MapRecord<String, String, String>> { private final StringRedisTemplate redisTemplate; private final StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer; public NotificationService(StringRedisTemplate redisTemplate, StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer) { this.redisTemplate = redisTemplate; this.listenerContainer = listenerContainer; } @PostConstruct public void startListening() { listenerContainer.receive(StreamOffset.fromStart(“order.stream”), this); } @Override public void onMessage(MapRecord<String, String, String> message) { String orderId = message.getValue().values().iterator().next(); System.out.println(“【通知服务】订单 ” + orderId + ” 创建成功!”); } } 优点 持久化存储,即使 Redis 重启,消息不会丢失。 支持消费组,多个消费者可以负载均衡地消费消息。 支持回溯,可以读取历史消息。
  • 方案 适用场景 优点 缺点 Pub/Sub 即时消息通知 低延迟 无持久化,消费者掉线丢消息 List 简单任务队列 轻量级 无消费组,任务可能丢失 Stream 高级事件流处理 持久化、消费组 复杂度较高 如果需求是轻量级队列,推荐 Redis Stream,它类似 Kafka,支持消费组和持久化,比 Redis List 更稳定。 到此这篇关于使用Redis实现轻量级消息队列的文章就介绍到这了,更多相关Redis 轻量级消息队列内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Spring boot项目redisTemplate实现轻量级消息队列的方法
  • 目录
    • 方式一  Redis Pub/Sub(适用于广播通知)
    • 方式二:Redis List(适用于任务队列)
    • 方式三:Redis Stream(推荐,支持持久化 + 消费组)
    • 总结

    使用消息中间件如RabbitMQ或kafka虽然好,但也给服务器带来很大的内存开销,当系统的业务量,并发量不高时,考虑到服务器和维护成本,可考虑使用Redis实现一个轻量级的消息队列,实现事件监听的效果。下面介绍下Redis实现消息队列的三种形式。

    Redis Pub/Sub 适用于 实时消息推送,但不支持消息持久化,如果消费者掉线,消息会丢失。

    (1) 发布消息(生产者)

    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Service;
    
    @Service
    public class OrderService {
        private final StringRedisTemplate redisTemplate;
    
        public OrderService(StringRedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        public void createOrder(Long orderId) {
            System.out.println("订单创建成功: " + orderId);
    
            // 发布消息
            redisTemplate.convertAndSend("order.channel", orderId.toString());
        }
    }
    

    (2) 订阅消息(消费者)

    import org.springframework.data.redis.connection.Message;
    import org.springframework.data.redis.connection.MessageListener;
    import org.springframework.stereotype.Service;
    
    @Service
    public class NotificationService implements MessageListener {
    
        @Override
        public void onMessage(Message message, byte[] pattern) {
            String orderId = message.toString();
            System.out.println("【通知服务】收到订单创建消息:" + orderId);
        }
    }
    

    (3) 注册 Redis 监听器

    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;
    
    @Configuration
    public class RedisPubSubConfig {
    
        @Bean
        public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                       MessageListenerAdapter listenerAdapter) {
            RedisMessageListenerContainer container = new RedisMessageListenerContainer();
            container.setConnectionFactory(connectionFactory);
            container.addMessageListener(listenerAdapter, new PatternTopic("order.channel"));
            return container;
        }
    
        @Bean
        public MessageListenerAdapter listenerAdapter(NotificationService receiver) {
            return new MessageListenerAdapter(receiver, "onMessage");
        }
    }
    

    缺点

    • 无持久化,消费者掉线后无法重新获取消息。
    • 不支持消费组,多个消费者同时订阅时,所有都会收到消息(无法负载均衡)。

    使用 Redis ListLPUSH + RPOP)可以实现简单的任务队列,适用于任务异步处理,但不支持回溯消费。

    (1) 生产者(推送任务)

    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Service;
    
    @Service
    public class OrderService {
        private final StringRedisTemplate redisTemplate;
    
        public OrderService(StringRedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        public void createOrder(Long orderId) {
            System.out.println("订单创建成功: " + orderId);
    
            // 推送到队列
            redisTemplate.opsForList().leftPush("order.queue", orderId.toString());
        }
    }
    

    (2) 消费者(轮询获取任务)

    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    @Service
    public class NotificationService {
        private final StringRedisTemplate redisTemplate;
    
        public NotificationService(StringRedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        @Scheduled(fixedDelay = 5000) // 每5秒轮询一次
        public void processOrderQueue() {
            String orderId = redisTemplate.opsForList().rightPop("order.queue");
            if (orderId != null) {
                System.out.println("【通知服务】处理订单:" + orderId);
            }
        }
    }
    

    要想消费者能监听到消息并进行处理,需要在方法上添加@Scheduled注解,同时在服务启动类中添加@EnableScheduling注解,或者在配置类添加

    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @EnableScheduling
    public class SchedulingConfig {
    }

    缺点

    • 无消费组,多个消费者时需要自行分配任务,可能会造成任务重复消费或丢失。
    • 无持久化保障,如果任务未处理完,Redis 发生故障,任务可能会丢失。

    Redis Stream 是 Redis 6.0 之后的特性,类似于 Kafka,支持持久化、消费组、多消费者模式

    (1) 生产者(推送事件)

    import org.springframework.data.redis.connection.stream.ObjectRecord;
    import org.springframework.data.redis.connection.stream.StreamRecords;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Service;
    
    @Service
    public class OrderService {
        private final StringRedisTemplate redisTemplate;
    
        public OrderService(StringRedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        public void createOrder(Long orderId) {
            System.out.println("订单创建成功: " + orderId);
    
            // 推送到 Redis Stream
            ObjectRecord<String, String> record = StreamRecords.newRecord()
                    .ofObject(orderId.toString())
                    .withStreamKey("order.stream");
            redisTemplate.opsForStream().add(record);
        }
    }
    

    (2) 消费者(监听事件)

    import org.springframework.data.redis.connection.stream.MapRecord;
    import org.springframework.data.redis.connection.stream.ReadOffset;
    import org.springframework.data.redis.connection.stream.StreamMessageListenerContainer;
    import org.springframework.data.redis.connection.stream.StreamOffset;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.data.redis.stream.StreamListener;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import java.time.Duration;
    import java.util.Collections;
    
    @Service
    public class NotificationService implements StreamListener<String, MapRecord<String, String, String>> {
    
        private final StringRedisTemplate redisTemplate;
        private final StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer;
    
        public NotificationService(StringRedisTemplate redisTemplate,
                                   StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer) {
            this.redisTemplate = redisTemplate;
            this.listenerContainer = listenerContainer;
        }
    
        @PostConstruct
        public void startListening() {
            listenerContainer.receive(StreamOffset.fromStart("order.stream"), this);
        }
    
        @Override
        public void onMessage(MapRecord<String, String, String> message) {
            String orderId = message.getValue().values().iterator().next();
            System.out.println("【通知服务】订单 " + orderId + " 创建成功!");
        }
    }
    

    优点

    • 持久化存储,即使 Redis 重启,消息不会丢失。
    • 支持消费组,多个消费者可以负载均衡地消费消息。
    • 支持回溯,可以读取历史消息。

    方案 适用场景 优点 缺点
    Pub/Sub 即时消息通知 低延迟 无持久化,消费者掉线丢消息
    List 简单任务队列 轻量级 无消费组,任务可能丢失
    Stream 高级事件流处理 持久化、消费组 复杂度较高

    如果需求是轻量级队列,推荐 Redis Stream,它类似 Kafka,支持消费组和持久化,比 Redis List 更稳定。

    到此这篇关于使用Redis实现轻量级消息队列的文章就介绍到这了,更多相关Redis 轻量级消息队列内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • Spring boot项目redisTemplate实现轻量级消息队列的方法

    站内搜索