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 提升系统的可扩展性。

相关推荐
.Shu.1 小时前
Mysql InnoDB 底层架构设计、功能、原理、源码系列合集【五、InnoDB 高阶机制与实战调优】
数据库·mysql
新法国菜3 小时前
MySql知识梳理之DDL语句
数据库·mysql
DarkAthena3 小时前
【GaussDB】全密态等值查询功能测试及全密态技术介绍
数据库·gaussdb
ShawnLeiLei4 小时前
2.3 Flink的核心概念解析
数据库·python·flink
小花鱼20254 小时前
redis在Spring中应用相关
redis·spring
郭京京4 小时前
redis基本操作
redis·go
似水流年流不尽思念4 小时前
Redis 分布式锁和 Zookeeper 进行比对的优缺点?
redis·后端
郭京京4 小时前
go操作redis
redis·后端·go
石皮幼鸟5 小时前
数据完整性在所有场景下都很重要吗?
数据库·后端
nightunderblackcat6 小时前
新手向:异步编程入门asyncio最佳实践
前端·数据库·python