redis stream机制

Redis Stream 是 Redis 5.0 引入的一种数据结构,旨在提供类似于消息队列的功能,但具备更强大的特性,如消费者组、持久化、消息确认和回溯读取等。Redis Stream 可以用于实现日志处理、消息队列、事件源等场景。下面是对 Redis Stream 机制的详细介绍。

1. 基本概念

a. Stream

Stream 是一种可变长的消息序列,每条消息由唯一的ID和一个键值对组成。Stream 是一个数据结构,它存储的不是单纯的字符串,而是一系列有序的、带有 ID 的键值对。

b. Entry

Stream 中的每条记录称为一个 Entry,它包含两个部分:

  • ID : 由 Redis 自动生成的唯一标识符,格式为 时间戳-序列号,如 1609459200000-0
  • 字段-值对: 一个或多个字段-值对,类似于 Redis 的哈希表。
c. Consumer

消费者是一个读取 Stream 中消息的客户端。消费者可以独立读取 Stream 中的消息。

d. Consumer Group

消费者组是 Redis Stream 中的一个重要特性,允许多个消费者协作消费同一个 Stream 中的消息。每个消费者组中的消息只会被一个消费者消费,消费者组有助于实现消息的负载均衡。

e. Pending Entries

消费者组中的挂起条目(Pending Entries)是指那些被某个消费者读取了但尚未确认的消息。

2. 基本操作

a. 添加消息

向 Stream 中添加消息,可以使用 XADD 命令。每条消息都由一个 ID 和多个字段值对组成。

bash 复制代码
XADD mystream * field1 value1 field2 value2
  • mystream 是 Stream 的名称。
  • * 表示让 Redis 自动生成 ID。
  • field1 value1 是消息体的字段和值。
b. 读取消息

使用 XRANGE 命令读取 Stream 中的消息,可以指定 ID 范围。

bash 复制代码
XRANGE mystream - +
  • -+ 分别表示从最早的消息到最新的消息。
c. 消费者组

消费者组允许多个消费者协作消费同一个 Stream。使用 XGROUP CREATE 命令创建一个消费者组:

bash 复制代码
XGROUP CREATE mystream mygroup $ MKSTREAM
  • mygroup 是消费者组的名称。
  • $ 表示从新消息开始消费。
d. 消费者读取消息

消费者从消费者组中读取消息时使用 XREADGROUP 命令:

bash 复制代码
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >
  • mygroup 是消费者组的名称。
  • consumer1 是消费者名称。
  • > 表示从未被其他消费者读取的消息开始读取。
e. 消息确认

消费者读取消息后,需要发送 XACK 命令确认已经处理完该消息:

bash 复制代码
XACK mystream mygroup 1609459200000-0
  • 1609459200000-0 是消息的 ID。

3. 高级特性

a. 持久化

Stream 中的消息是持久化的,Redis 会将它们存储在磁盘中,确保在服务器重启后仍然存在。

b. 自动修剪

Redis 提供 MAXLEN 参数,可以设置 Stream 的最大长度。当超过此长度时,旧消息会被自动删除。

bash 复制代码
XADD mystream MAXLEN 1000 * field1 value1
c. 消息回溯

消费者组中的消费者可以读取历史消息,即使这些消息已经被其他消费者消费。通过设置起始ID,消费者可以回溯到某个时刻重新读取消息。

4. 实现示例

a. 生产者示例

在 Java Spring Boot 中,可以使用 RedisTemplate 来向 Stream 中添加消息:

java 复制代码
@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void produceMessage(String streamKey, Map<String, String> message) {
    redisTemplate.opsForStream().add(StreamRecords.newRecord().in(streamKey).ofMap(message));
}
b. 消费者示例

通过 StreamMessageListenerContainer 实现消费者组中的消费者,消费消息并确认处理:

java 复制代码
@Autowired
private RedisTemplate<String, Object> redisTemplate;

@PostConstruct
public void startConsumer() {
    StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String, String, String>> options =
            StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder()
                    .pollTimeout(Duration.ofSeconds(1))
                    .build();

    StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer =
            StreamMessageListenerContainer.create(redisTemplate.getConnectionFactory(), options);

    listenerContainer.receive(Consumer.from("mygroup", "consumer1"),
            StreamOffset.create("mystream", ReadOffset.lastConsumed()),
            new StreamListener<String, MapRecord<String, String, String>>() {
                @Override
                public void onMessage(MapRecord<String, String, String> message) {
                    System.out.println("Received message: " + message.getValue().get("field1"));
                    // 消费后确认消息
                    redisTemplate.opsForStream().acknowledge("mygroup", message);
                }
            });

    listenerContainer.start();
}

总结

Redis Stream 提供了强大的消息队列功能,支持消费者组、消息持久化、消息确认与重试等特性,非常适合构建高吞吐量、高可靠性的分布式消息系统。通过对 Redis Stream 的理解和应用,可以解决许多实际的消息队列需求,尤其是在分布式环境中。

a. 可以进一步学习 Redis Stream 中的高级功能,例如 XCLAIM 命令用于处理消费者故障恢复的场景。
b. 可以尝试实现一个基于 Redis Stream 的分布式消息系统,并考虑使用 Redis Cluster 提升系统的可扩展性。

相关推荐
数据智能老司机16 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机16 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
松果猿17 小时前
空间数据库学习(二)—— PostgreSQL数据库的备份转储和导入恢复
数据库
Kagol17 小时前
macOS 和 Windows 操作系统下如何安装和启动 MySQL / Redis 数据库
redis·后端·mysql
无名之逆17 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
s91236010117 小时前
rust 同时处理多个异步任务
java·数据库·rust
数据智能老司机17 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
hzulwy17 小时前
Redis常用的数据结构及其使用场景
数据库·redis
程序猿熊跃晖17 小时前
解决 MyBatis-Plus 中 `update.setProcInsId(null)` 不生效的问题
数据库·tomcat·mybatis
ashane131419 小时前
Redis 哨兵集群(Sentinel)与 Cluster 集群对比
redis