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

 更新时间:2025年11月14日 10:08:48   作者:moxiaoran5753  
使用消息中间件如RabbitMQ或kafka虽然好,但也给服务器带来很大的内存开销,当系统的业务量,并发量不高时,考虑到服务器和维护成本,可考虑使用Redis实现一个轻量级的消息队列,下面就来详细的介绍一下

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

方式一  Redis Pub/Sub(适用于广播通知)

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(适用于任务队列)

使用 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 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 轻量级消息队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于Golang实现Redis分布式锁解决秒杀问题

    基于Golang实现Redis分布式锁解决秒杀问题

    这篇文章主要给大家介绍了使用Golang实现Redis分布式锁解决秒杀问题,文中有详细的代码示例供大家参考,具有一定的参考价值,需要的朋友可以参考下
    2023-08-08
  • golang协程池模拟实现群发邮件功能

    golang协程池模拟实现群发邮件功能

    这篇文章主要介绍了golang协程池模拟实现群发邮件功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • linux下通过go语言获得系统进程cpu使用情况的方法

    linux下通过go语言获得系统进程cpu使用情况的方法

    这篇文章主要介绍了linux下通过go语言获得系统进程cpu使用情况的方法,实例分析了Go语言使用linux的系统命令ps来分析cpu使用情况的技巧,需要的朋友可以参考下
    2015-03-03
  • golang的HTTP基本认证机制实例详解

    golang的HTTP基本认证机制实例详解

    这篇文章主要介绍了golang的HTTP基本认证机制,结合实例形式较为详细的分析了HTTP请求响应的过程及认证机制实现技巧,需要的朋友可以参考下
    2016-07-07
  • Go语言中的Web服务器开发详细指南

    Go语言中的Web服务器开发详细指南

    go提供了一系列用于创建web服务器的标准,而非常简单,下面这篇文章主要给大家介绍了关于Go语言中Web服务器开发的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-07-07
  • Go使用协程交替打印字符

    Go使用协程交替打印字符

    这篇文章主要介绍了Go使用协程交替打印字符,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • 一文带你了解Golang中reflect反射的常见错误

    一文带你了解Golang中reflect反射的常见错误

    go 反射的错误大多数都来自于调用了一个不适合当前类型的方法, 而且,这些错误通常是在运行时才会暴露出来,而不是在编译时,如果我们传递的类型在反射代码中没有被覆盖到那么很容易就会 panic。本文就介绍一下使用 go 反射时很大概率会出现的错误,需要的可以参考一下
    2023-01-01
  • golang语言http协议get拼接参数操作

    golang语言http协议get拼接参数操作

    这篇文章主要介绍了golang语言http协议get拼接参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Golang定时任务框架GoCron的源码分析

    Golang定时任务框架GoCron的源码分析

    本文主要介绍了Golang定时任务框架GoCron的源码分析,原生的gocron存在一些问题,如任务列表维护不当、并发操作不可预测等,经过改进的gocron解决了这些问题,感兴趣的可以了解一下
    2025-03-03
  • 解读go在遍历map过程中删除成员是否安全

    解读go在遍历map过程中删除成员是否安全

    在Go语言中,通过for range遍历map时可以安全地删除当前遍历到的元素,因为遍历过程中的删除操作不会影响遍历的进行,但需要注意,遍历顺序是不确定的,删除元素不会导致程序错误,但可能会影响剩余元素的遍历顺序,在多线程环境下
    2024-09-09

最新评论