tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。
推荐:体系化学习Java(Java面试专题)
Stream 是 Redis 5.0 版本中新增的一种数据结构,它是一个高性能、持久化的消息队列,可以用于实现消息的发布和订阅。Stream 可以看作是一个有序的消息队列,每个消息都有一个唯一的 ID,可以根据 ID 进行消息的查找、删除和确认。在 Stream 中,消息以键值对的形式存储,可以存储任意类型的数据。Stream 还支持多个消费者组,每个消费者组可以独立消费消息,避免消息重复消费。Stream 的引入使得 Redis 在消息队列领域更具竞争力,同时也为开发者提供了一种高效、可靠的消息处理方式。
Redis 设计 Stream 的原因主要是为了满足大规模实时数据处理的需求。在传统的消息队列中,消息的消费者只能消费最新的消息,而无法消费过去的消息。而在实时数据处理中,往往需要对历史数据进行分析和处理,因此需要一种能够存储大量历史数据并支持快速查询和消费的数据结构。Stream 的引入解决了这个问题,它支持持久化存储和快速查询,可以存储大量历史数据,并且支持多个消费者组独立消费消息,从而满足了大规模实时数据处理的需求。此外,Stream 还支持消息的延迟和重试等功能,使得 Redis 在消息队列领域更具竞争力。
Stream 是 Redis 5.0 版本新增的一种数据结构,支持高性能、持久化的消息队列。下面是 Stream 命令的详细介绍:
127.0.0.1:6379> XADD mystream 1000 name John age 30
"1000-0"
127.0.0.1:6379> XRANGE mystream 1000-0 1000-1
1) 1) "1000-0"
2) 1) "name"
2) "John"
3) "age"
4) "30"
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XREVRANGE mystream 1003-0 1001-0
1) 1) "1003-0"
2) 1) "name"
2) "Jack"
3) "age"
4) "30"
2) 1) "1002-0"
2) 1) "name"
2) "Mary"
3) "age"
4) "28"
3) 1) "1001-0"
2) 1) "name"
2) "Tom"
3) "age"
4) "25"
127.0.0.1:6379> XLEN mystream
1
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XREAD COUNT 2 BLOCK 1000 STREAMS mystream 0
1) 1) "mystream"
2) 1) 1) "1001-0"
2) 1) "name"
2) "Tom"
3) "age"
4) "25"
2) 1) "1002-0"
2) 1) "name"
2) "Mary"
3) "age"
4) "28"
127.0.0.1:6379> XACK mystream mygroup 1000-0
(integer) 1
127.0.0.1:6379> XGROUP CREATE mystream mygroup 1000-0
OK
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XGROUP CREATE mystream mygroup $
OK
127.0.0.1:6379> XGROUP SETID mystream mygroup 1002-0
OK
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XGROUP CREATE mystream mygroup $
OK
127.0.0.1:6379> XGROUP DESTROY mystream mygroup
(integer) 1
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XGROUP CREATE mystream mygroup $
OK
127.0.0.1:6379> XREADGROUP GROUP mygroup myconsumer COUNT 1 STREAMS mystream >
1) 1) "mystream"
2) 1) 1) "1001-0"
2) 1) "name"
2) "Tom"
3) "age"
4) "25"
127.0.0.1:6379> XGROUP DELCONSUMER mystream mygroup myconsumer
(integer) 1
127.0.0.1:6379> XREADGROUP GROUP mygroup consumer1 STREAMS mystream >
1) 1) "mystream"
2) 1) 1) "1000-0"
2) 1) "name"
2) "John"
3) "age"
4) "30"
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XGROUP CREATE mystream mygroup $
OK
127.0.0.1:6379> XREADGROUP GROUP mygroup myconsumer COUNT 1 STREAMS mystream >
1) 1) "mystream"
2) 1) 1) "1001-0"
2) 1) "name"
2) "Tom"
3) "age"
4) "25"
127.0.0.1:6379> XCLAIM mystream mygroup myconsumer 0 1001-0
1) 1) "mystream"
2) 1) 1) "1001-0"
2) 1) "name"
2) "Tom"
3) "age"
4) "25"
127.0.0.1:6379> XDEL mystream 1000-0
(integer) 1
127.0.0.1:6379> XADD mystream 1001 name Tom age 25
"1001-0"
127.0.0.1:6379> XADD mystream 1002 name Mary age 28
"1002-0"
127.0.0.1:6379> XADD mystream 1003 name Jack age 30
"1003-0"
127.0.0.1:6379> XADD mystream 1004 name Lucy age 27
"1004-0"
127.0.0.1:6379> XADD mystream 1005 name Bob age 32
"1005-0"
127.0.0.1:6379> XTRIM mystream MAXLEN 3
(integer) 2
我这边 redis 的版本是 Redis-x64-5.0.14.1,windows 上玩的,绿色版的,下载地址https://github.com/tporadowski/redis/releases
package com.pany.camp.redis;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.StreamConsumersInfo;
import redis.clients.jedis.StreamEntry;
import redis.clients.jedis.StreamEntryID;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.params.XReadGroupParams;
import redis.clients.jedis.params.XReadParams;
import java.util.*;
public class RedisStreamDemo {
private static final Logger logger = LoggerFactory.getLogger(RedisStreamDemo.class);
private static final int MESSAGE_READ_COUNT = 1;
private static final long MESSAGE_READ_TIMEOUT = 120000L;
public static void main(String[] args) {
// 创建 Jedis 实例
try (Jedis jedis = new Jedis("127.0.0.1", 6379)) {
// 定义 Stream 名称和消费者组名称
String streamName = "mystream";
String groupName = "mygroup5";
// 创建消费者组
try {
jedis.xgroupCreate(streamName, groupName, new StreamEntryID(), true);
} catch (JedisDataException e) {
// 如果 Stream 已经存在,则忽略异常
if (!e.getMessage().contains("BUSYGROUP")) {
throw e;
}
}
logger.info("消费者组已创建");
// 添加消息到 Stream 中
Map<String, String> fields = new HashMap<>();
fields.put("field1", "value1");
fields.put("field2", "value2");
StreamEntryID messageId = jedis.xadd(streamName, StreamEntryID.NEW_ENTRY, fields);
logger.info("消息已添加到 Stream 中,消息内容为:{}", JSONObject.toJSONString(fields));
// 读取消息
Map.Entry<String, StreamEntryID> streams = new AbstractMap.SimpleImmutableEntry<>(streamName,
new StreamEntryID().UNRECEIVED_ENTRY);
List<Map.Entry<String, List<StreamEntry>>> messages = jedis.xreadGroup(groupName, "c1", MESSAGE_READ_COUNT,
MESSAGE_READ_TIMEOUT, true, streams);
logger.info("从 Stream 中读取了 {} 条消息", messages.size());
for (Map.Entry<String, List<StreamEntry>> entry : messages) {
String sn = entry.getKey();
List<StreamEntry> streamMessages = entry.getValue();
for (StreamEntry message : streamMessages) {
logger.info("Stream 名称:{}", sn);
logger.info("Message ID:{}", message.getID());
logger.info("Message fields:{}", message.getFields());
}
}
// 确认消息已经被消费
jedis.xack(streamName, groupName, messageId);
logger.info("消息已确认消费");
// 删除消息
jedis.xdel(streamName, messageId);
logger.info("消息已删除");
} catch (Exception e) {
logger.error("执行 Redis 操作出错", e);
}
}
}
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>3.7.0version>
dependency>
Redis Stream 的常用的应用场景:
消息队列:Stream 可以作为一个高性能的消息队列使用,支持多个消费者对同一 Stream 进行消费,且支持消费者组的管理、消息确认和消息持久化等功能。
日志收集:Stream 可以作为一个分布式的日志收集系统使用,支持多个客户端将日志写入到同一 Stream 中,且支持按照时间戳和 ID 进行查询和过滤。
实时数据处理:Stream 可以作为一个实时数据处理系统使用,支持多个客户端将实时数据写入到同一 Stream 中,且支持按照时间戳和 ID 进行查询和过滤。
事件驱动架构:Stream 可以作为一个事件驱动架构的基础设施使用,支持多个事件源将事件写入到同一 Stream 中,且支持按照事件类型和时间戳进行查询和过滤。
本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
喜欢的话记得点赞收藏啊