XREAD

读取多个流中 ID 大于指定值的消息;使用 BLOCK 时可等待新消息。

语法

XREAD [COUNT count] [MAXCOUNT maxcount] [MAXSIZE maxsize] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]

引入版本:5.0.0

复杂度摘要:O(M)

[!NOTE] 此命令的行为在集群 Redis 环境中有所不同。请参阅 多键操作 页面了解更多信息。

从一个或多个流中读取数据,仅返回 ID 大于调用者报告的最后接收到的 ID 的条目。该命令有一个选项,可以在项目不可用时阻止,其方式与 BRPOP 或 BZPOPMIN 等类似。

如果您是流媒体新手,请参阅 Redis流简介。

必需参数

STREAMS key [key ...] id [id ...]

要读取的按键,后跟每个按键的 ID。对于每个流,返回 ID 大于给定 ID 的条目。使用 $ 仅读取调用后添加的条目。

可选参数

COUNT count

每个流返回的最大条目数。

MAXCOUNT maxcount

Redis 8.10 新增。命令中指定的所有流中返回的最大条目总数。与按每个流限制条目的 COUNT 不同,MAXCOUNT 对整个命令应用单个累积预算。它必须是一个正整数,并且当两者都给定时,它必须大于或等于COUNT。当省略 COUNT 时,仅 MAXCOUNT 限制总数。详细信息请参见 MAXCOUNT 和 MAXSIZE 选项。

MAXSIZE maxsize

Redis 8.10 新增。命令中指定的所有流的回复的最大大小(以字节为单位)。它必须是一个正整数。始终至少返回一个条目,因此仍返回大于 MAXSIZE 的单个条目,而不是产生空回复。详细信息请参见 MAXCOUNT 和 MAXSIZE 选项。

BLOCK milliseconds

如果没有可用条目,则最多阻塞这么多毫秒。 0 无限期阻塞。

详细说明

非阻塞使用

如果未使用 BLOCK 选项,则该命令是同步的,可以认为与 XRANGE 有点相关:它将返回流内的一系列项目,但是即使我们只考虑同步使用,它与 XRANGE 相比也有两个根本区别:

  • 如果我们想同时读取多个键,则可以使用多个流调用此命令。这是 XREAD 的一个关键功能,因为特别是在使用 BLOCK 进行阻止时,能够通过单个连接监听多个按键是一项至关重要的功能。
  • 虽然 XRANGE 返回一系列 ID 中的项目,但 XREAD 更适合从第一个条目开始使用流,该条目比我们迄今为止看到的任何其他条目都大。因此,对于每个流,我们传递给 XREAD 的是我们从该流接收到的最后一个元素的 ID。

例如,如果我有两个流 mystream 和 writers,并且我想从这两个流包含的第一个元素开始读取数据,我可以调用 XREAD,如下例所示。

注意:我们在示例中使用 COUNT 选项,以便对于每个流,调用将最多返回每个流两个元素。

> XREAD COUNT 2 STREAMS mystream writers 0-0 0-0
1) 1) "mystream"
   2) 1) 1) 1526984818136-0
         2) 1) "duration"
            2) "1532"
            3) "event-id"
            4) "5"
            5) "user-id"
            6) "7782813"
      2) 1) 1526999352406-0
         2) 1) "duration"
            2) "812"
            3) "event-id"
            4) "9"
            5) "user-id"
            6) "388234"
2) 1) "writers"
   2) 1) 1) 1526985676425-0
         2) 1) "name"
            2) "Virginia"
            3) "surname"
            4) "Woolf"
      2) 1) 1526985685298-0
         2) 1) "name"
            2) "Jane"
            3) "surname"
            4) "Austen"

STREAMS 选项是强制性的,并且必须是最终选项,因为此类选项获取以下格式的可变长度参数:

STREAMS key_1 key_2 key_3 ... key_N ID_1 ID_2 ID_3 ... ID_N

因此,我们从键列表开始,然后继续使用代表 我们收到的该流的最后一个 ID 的所有关联 ID,以便调用将只为我们提供来自同一流的更大 ID。

例如,在上面的示例中,我们收到的流 mystream 的最后一项的 ID 为 1526999352406-0,而流 writers 的最后一项的 ID 为 1526985685298-0。

要继续迭代这两个流,我将调用:

> XREAD COUNT 2 STREAMS mystream writers 1526999352406-0 1526985685298-0
1) 1) "mystream"
   2) 1) 1) 1526999626221-0
         2) 1) "duration"
            2) "911"
            3) "event-id"
            4) "7"
            5) "user-id"
            6) "9488232"
2) 1) "writers"
   2) 1) 1) 1526985691746-0
         2) 1) "name"
            2) "Toni"
            3) "surname"
            4) "Morrison"
      2) 1) 1526985712947-0
         2) 1) "name"
            2) "Agatha"
            3) "surname"
            4) "Christie"

等等。最终,该调用不会返回任何项目,而只是一个空数组,然后我们知道没有更多内容可以从流中获取(并且我们必须重试该操作,因此该命令也支持阻塞模式)。

身份证件不完整

使用不完整的 ID 是有效的,就像对 XRANGE 有效一样。然而,这里 ID 的序列部分(如果丢失)始终被解释为零,因此命令:

> XREAD COUNT 2 STREAMS mystream writers 0 0

完全等于

> XREAD COUNT 2 STREAMS mystream writers 0-0 0-0

数据阻塞

在同步形式下,只要有更多可用项目,该命令就可以获取新数据。然而,在某些时候,我们将不得不等待数据生产者使用 XADD 将新条目推送到我们正在使用的流中。为了避免以固定或自适应间隔进行轮询,如果命令无法返回任何数据,则能够根据指定的流和 ID 进行阻塞,并在请求的键之一接受数据后自动解除阻塞。

重要的是要理解,此命令 扇出 发送给所有正在等待相同范围 ID 的客户端,因此每个消费者都将获得数据的副本,这与使用阻止列表弹出操作时发生的情况不同。

为了阻止,使用 BLOCK 选项,以及我们想要在超时之前阻止的毫秒数。通常,Redis 阻塞命令会以秒为单位超时,但是此命令会超时,即使通常服务器的超时分辨率接近 0.1 秒。这次在某些用例中可能会阻塞更短的时间,并且如果服务器内部随着时间的推移而改进,则超时的解决方案可能会得到改善。

当 BLOCK 命令被传递,但至少在传递的其中一个流中有数据要返回时,该命令将同步执行 就像缺少 BLOCK 选项一样。

这是阻塞调用的示例,其中该命令稍后返回空回复,因为超时已过而没有新数据到达:

> XREAD BLOCK 1000 STREAMS mystream 1526999626221-0
(nil)

特殊的$ ID。

当阻塞时,有时我们希望只接收从阻塞那一刻起通过 XADD 添加到流中的条目。在这种情况下,我们对已添加条目的历史不感兴趣。对于此用例,我们必须检查流顶部元素 ID,并在 XREAD 命令行中使用此类 ID。这并不干净,需要调用其他命令,因此可以使用特殊的 $ ID 来向流发出信号,表明我们只需要新内容。

非常重要 理解为您应该仅在第一次调用 XREAD 时使用 $ ID。稍后,ID 应该是流中最后报告的项目之一,否则您可能会错过在其间添加的所有条目。

这是在消费者愿意只消费新条目的第一次迭代中典型的 XREAD 调用的样子:

> XREAD BLOCK 5000 COUNT 100 STREAMS mystream $

一旦我们得到一些答复,下一个电话将是这样的:

> XREAD BLOCK 5000 COUNT 100 STREAMS mystream 1526999644174-3

等等。

特殊的+ ID

您可以使用 XREVRANGE 命令轻松读取单个流中的最后一个条目,如下所示:

> XREVRANGE stream + - COUNT 1

但是,当您添加更多流时,这种方法会变得很慢,因为您必须为每个流发出单独的命令。相反,从 Redis 7.4 开始,您可以使用 + 标志作为特殊 ID。这请求流中的最后一个可用条目。例如:

> XREAD STREAMS streamA streamB streamC streamD + + + +

请注意,当对流使用此特殊 ID 时,COUNT 选项将被忽略(对于特定流),因为只能返回最后一个条目。

MAXCOUNT 和 MAXSIZE 选项

Redis 8.10 中添加了 MAXCOUNT 和 MAXSIZE 选项,可限制单个命令中指定的所有流中的 累计 回复。这与 COUNT 不同,后者限制在 每个流 基础上返回的条目数量。由于 XREAD 在一次调用中接受多个流,因此使用 COUNT C 读取 N 个流最多可以返回 N * C 条目,并且总回复大小不受限制。 MAXCOUNT 和 MAXSIZE 为客户提供了一种可靠的方式来限制单个多流读取的工作和内存。

  • MAXCOUNT 限制所有流返回的条目总数。它必须是正整数,并且当两者都给定时,它必须大于或等于 COUNT(因为它是每个流限制的累积上限)。当省略 COUNT 时,MAXCOUNT 单独限制总数,从第一个流开始填充。
  • MAXSIZE 限制总回复大​​小(以字节为单位)。它必须是一个正整数。
  • 始终至少返回一项。在整个回复中至少发出一个条目之前,不会强制执行字节预算,因此仍会返回大于 MAXSIZE 的单个条目,而不是产生空回复。
  • 当两个选项都给出时,以先达到的界限为准。

给定三个流,每个流有 100 个条目:

> XREAD COUNT 50 STREAMS s1 s2 s3 0 0 0
# returns 150 entries total (50 per stream)

> XREAD COUNT 50 MAXCOUNT 80 STREAMS s1 s2 s3 0 0 0
# returns 80 entries total — capped across all streams

> XREAD MAXCOUNT 7 STREAMS s1 s2 s3 0 0 0
# returns 7 entries total, all from s1

> XREAD MAXCOUNT 5 MAXSIZE 100000 STREAMS s1 s2 s3 0 0 0
# returns 5 entries (MAXCOUNT is the tighter bound)

始终返回单个超大条目,即使它超过 MAXSIZE:

> XADD bigstream 1-1 f <5000-byte value>
> XREAD MAXSIZE 50 STREAMS bigstream 0
1) 1) "bigstream"
   2) 1) 1) "1-1"
         2) 1) "f"
            2) "<5000-byte value>"
# the single entry exceeds MAXSIZE but is still returned

如何为单个流上阻塞的多个客户端提供服务

列表或有序集合上的阻止列表操作具有 流行音乐 行为。基本上,元素会从列表或有序集合中删除,以便返回给客户端。在这种情况下,您希望以公平的方式消耗项目,具体取决于在给定键上阻塞的客户端到达的时间。通常,Redis 在此用例中使用 FIFO 语义。

但请注意,对于流来说,这不是问题:当为客户端提供服务时,流条目不会从流中删除,因此一旦 XADD 命令向流提供数据,每个等待的客户端都会得到服务。

强烈建议阅读 Redis Streams介绍,以便更多地了解流的整体行为和语义。

Redis Software 与 Redis Cloud 兼容性

Redis
软件
Redis
Cloud
说明
✅ 标准
✅ 主动-主动
✅ 标准
✅ 主动-主动

返回值

RESP2

以下之一: * 数组回复:一个数组,其中每个元素都是由两个元素组成的数组,其中包含键名称和为该键报告的条目。报告的条目是完整的流条目,具有 ID 以及所有字段和值的列表。字段和值保证按照 XADD 添加的顺序进行报告。 * 无回复:如果给出了 BLOCK 选项并且发生超时,或者没有可以提供的流。

RESP3

以下之一: * 地图回复:键值元素的映射,其中每个元素由键名称和为该键报告的条目组成。报告的条目是完整的流条目,具有 ID 以及所有字段和值的列表。字段和值保证按照 XADD 添加的顺序进行报告。 * 空回复:如果给出了 BLOCK 选项并且发生超时,或者没有可以提供的流。

资料来源:Redis 官方 XREAD 文档;中文内容参考 Redis 文档许可。