目录
- Redis 为什么能够作为消息队列
- 三种消息队列实现方式概览
- Redis List 队列机制及 Spring 实战
- Redis Pub/Sub 发布订阅机制及使用方式
- Redis Stream:最强队列机制(含 ACK、消费组)
- Spring Boot 整合 Stream(完整可运行)
- Redis Stream 与 Kafka 的特点对比
- 使用场景总结
1. Redis 为什么可以用作消息队列
Redis 是一个基于内存的高性能 Key-Value 数据库,它的数据结构丰富且操作均为 O(1)。
队列的本质是“先进先出,按顺序取出”,而 Redis 的 List、Pub/Sub 与 Stream 结构分别可以满足不同层次的队列需求:
- List:可以充当普通队列
- Pub/Sub:提供实时的发布订阅
- Stream:提供带持久化、消费组、ACK 确认机制的专业队列能力
这让 Redis 在轻量级 MQ 场景下非常灵活,也非常高效。
2. Redis 三种消息队列方案对比
| 方案 | 持久化 | 是否丢消息 | 是否支持消费组 | 是否需要 ACK | 使用难度 | 适用场景 |
|---|---|---|---|---|---|---|
| List(LPUSH/RPOP) | 支持 | 有可能丢失 | 不支持 | 不支持 | 最简单 | 简单后台任务、异步执行 |
| Pub/Sub | 不支持 | 订阅者离线即丢失 | 不支持 | 不支持 | 中等 | 实时消息推送、广播通知 |
| Stream | 支持 | 不容易丢失 | 支持 | 支持 | 相对复杂 | 订单处理、任务调度、分布式队列 |
从功能完善度来看,Stream 是最推荐的方案。
从使用简单度来看,List 是最容易上手的。
3. Redis List 队列机制(LPUSH + RPOP)
List 是 Redis 最经典的队列实现方式。通过“左进右出”就可以模拟一个典型的 FIFO 队列。
特点说明
- 实现简单,可快速上手
- 使用 RedisTemplate 就能轻松实现
- 不支持消费者确认机制,消息投递后无法保证成功处理
- 多消费者会导致竞争同一条消息,不适合任务分布式分发
因此,List 更适合简易异步任务、低可靠场景。
生产者示例:
@AutowiredprivateStringRedisTemplateredisTemplate;publicvoidsendMessage(Stringmsg){redisTemplate.opsForList().leftPush("task_queue",msg);}消费者示例:
@Scheduled(fixedDelay=1000)publicvoidconsumer(){Stringmsg=redisTemplate.opsForList().rightPop("task_queue");if(msg!=null){System.out.println("处理任务:"+msg);}}这种方式虽然简单,但不具备强队列能力。
4. Redis Pub/Sub 发布订阅模式
Pub/Sub 提供了一种非常实时化的消息推送方式,它不存储历史消息,只有在线订阅者才能收到。
模式特点
- 适合实时通知,如系统消息、广播消息、在线聊天
- 不会保存消息,订阅者掉线即丢失
- 没有 ACK,无法保证每条消息被处理
Pub/Sub 不适合作为任务队列,但适合“实时推送”。
监听器配置
@ConfigurationpublicclassRedisConfig{@BeanMessageListenerAdapterlistenerAdapter(MessageReceiverreceiver){returnnewMessageListenerAdapter(receiver,"onMessage");}@BeanRedisMessageListenerContainercontainer(RedisConnectionFactoryfactory,MessageListenerAdapterlistenerAdapter){RedisMessageListenerContainercontainer=newRedisMessageListenerContainer();container.setConnectionFactory(factory);container.addMessageListener(listenerAdapter,newPatternTopic("notice"));returncontainer;}}消费者
@ComponentpublicclassMessageReceiver{publicvoidonMessage(Stringmessage){System.out.println("收到通知:"+message);}}生产者
redisTemplate.convertAndSend("notice","系统通知:服务器即将维护");5. Redis Stream:专业级消息队列方案
Stream 是 Redis 5.0 引入的全新数据结构,是一套完整的消息队列系统,特点如下:
- 支持持久化,数据不会因断电丢失
- 支持消费者组,可由多个消费者组成消费集群
- 支持 ACK 确认机制,确保消息不会丢失
- 单条消息被确定处理后自动从 Pending 列表中移除
- 支持自动或手动 Claim,保证消息不会被遗忘
- 顺序性和性能都非常优秀
Stream 可以被认为是小型版的 Kafka,但更轻量、更容易部署。
6. Spring Boot 整合 Redis Stream
1)依赖引入
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>2)初始化消息队列的消费组
为了防止不存在的消费组导致报错,一般在项目启动时创建消费组:
@ComponentpublicclassStreamInit{@AutowiredprivateStringRedisTemplateredisTemplate;@PostConstructpublicvoidinit(){try{redisTemplate.opsForStream().createGroup("order_stream","order_group");}catch(Exceptionignored){}}}3)生产者发送消息
@AutowiredprivateStringRedisTemplateredisTemplate;publicvoidsendOrder(StringorderNo){Map<String,String>map=newHashMap<>();map.put("orderNo",orderNo);redisTemplate.opsForStream().add("order_stream",map);}4)消费者处理消息(包含 ACK)
@ComponentpublicclassOrderConsumerimplementsStreamListener<String,MapRecord<String,String,String>>{@AutowiredprivateStringRedisTemplateredisTemplate;@OverridepublicvoidonMessage(MapRecord<String,String,String>record){StringorderNo=record.getValue().get("orderNo");System.out.println("正在处理订单:"+orderNo);redisTemplate.opsForStream().acknowledge("order_stream","order_group",record.getId());}}5)注册 Stream 监听器
@ConfigurationpublicclassStreamConfig{@BeanpublicRedisMessageListenerContainerlistenerContainer(RedisConnectionFactoryfactory,OrderConsumerconsumer){RedisMessageListenerContainercontainer=newRedisMessageListenerContainer();container.setConnectionFactory(factory);StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String,MapRecord<String,String,String>>options=StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder().pollTimeout(Duration.ofSeconds(2)).build();StreamMessageListenerContainer<String,MapRecord<String,String,String>>streamContainer=StreamMessageListenerContainer.create(factory,options);streamContainer.receiveAutoAck(Consumer.from("order_group","consumer_1"),StreamOffset.create("order_stream",ReadOffset.lastConsumed()),consumer);streamContainer.start();returncontainer;}}至此,Redis Stream 的生产-消费整体链路完整实现,可以直接在实际项目中使用。
7. Redis Stream 与 Kafka 的对比分析
| 特点 | Redis Stream | Kafka |
|---|---|---|
| 吞吐量 | 中等偏高 | 极高 |
| 消费机制 | 消费组 + ACK | 消费组 + Offset |
| 持久化方式 | 内存主导 + AOF | 磁盘顺序写 |
| 依赖环境 | 极简,部署容易 | 较复杂,需要 Zookeeper 或 Kraft |
| 使用场景 | 中小型业务,订单流、异步任务 | 海量日志、实时流处理、大型数据系统 |
结论:当系统规模较小时,Redis Stream 是简单高效的队列方案;当系统达到大规模吞吐需求时,Kafka 才是更合适的选择。
8. 使用场景总结
以下场景适合完全使用 Redis Stream 或 List/PubSub:
- 订单创建后的异步处理
- 秒杀请求异步落库
- 延迟任务队列
- 短信/邮件异步发送
- 系统通知、用户消息推送
- 日志或审计消息收集
- 数据同步、事件驱动架构
Redis 的灵活性使它能够同时承担缓存、分布式锁和消息队列等多种角色,适用于多种中小型分布式系统架构。
结语
Redis 不仅是一个高性能的缓存数据库,同时也是一个非常灵活且强大的轻量级消息队列解决方案。依托于其多样化的数据结构、极高的读写性能以及简单易部署的特点,Redis 在现代微服务架构中扮演着远超“缓存”本身的角色。在许多中小型项目中,它可以承担消息传递、事件驱动、异步任务处理等职责,甚至可以在一定程度上替代专业消息中间件。
在 Spring 体系中,Redis 的集成方式非常成熟且丰富,无论是基于 List 的简易队列、基于 Pub/Sub 的实时广播消息,还是基于 Stream 的分布式消息队列,都可以通过 Spring Data Redis 顺畅地接入应用系统。其中 Redis Stream 是目前最值得推荐的方案,它具备消息持久化、消费者组、消息确认机制(ACK)、Pending 列表管理、顺序性保证等能力,能够提供接近 Kafka 那样的消息投递可靠性,同时又保持了 Redis 一贯的简单部署和轻量成本。