dot 速度的未来即将来到您所在的城市。

加入我们在 Redis 发布会

Redis 队列

返回术语表

Redis 支持列表和集合数据结构,可以有效地用作消息队列。这意味着它可以处理排队等待处理的多个任务。任务可以立即处理,也可以在某个计划的时间处理。将 Redis 用作队列的能力为处理分布式作业和消息开辟了广泛的可能性,尤其是在需要高性能和可靠性的应用程序中。

深入了解 Redis 的高速消息传递世界:低延迟消息队列和代理软件

什么是队列?

在计算机科学中,队列是按顺序维护的实体集合,可以通过在序列的一端添加实体和从另一端删除实体来修改。这种特性称为 FIFO(先进先出),意味着第一个添加到队列的元素是第一个被删除的元素。

队列用于计算机编程,一个典型的队列例子是等待服务的人群。类似地,在编程中,任务可以在队列中排队以进行顺序处理。

Redis 队列基础

Redis 提供了一些命令,这些命令可以用来实现一个基本队列。为此使用的主要数据结构是 Redis 列表,它是由插入顺序排序的字符串列表。您可以将元素添加到 Redis 列表的头部(左侧)或尾部(右侧)。

在 Redis 中创建队列

要在 Redis 中创建队列,您可以使用 LPUSH 命令将元素添加到列表的头部,有效地将其推入队列。这是一个示例

LPUSH myqueue "Task1"

此命令创建一个名为“myqueue”的新列表,并将字符串“Task1”添加到其中。如果“myqueue”已经存在,则“Task1”将被添加到列表的头部。

基本队列操作

入队

入队是将元素添加到队列的过程。在 Redis 中,您可以使用 LPUSH 命令将元素入队

LPUSH myqueue "Task2"

现在,“myqueue”包含两个元素:“Task2”和“Task1”,按此顺序。

出队

出队是从队列中删除元素的过程。在队列中,第一个添加的元素是第一个被删除的元素(FIFO)。在 Redis 中,您可以使用 RPOP 命令将元素出队

RPOP myqueue

此命令将删除并返回列表尾部的元素,在本例中为“Task1”。

窥视

窥视是在不实际出队的情况下查看将要出队的元素的过程。在 Redis 中,您可以使用 LRANGE 命令来窥视队列

LRANGE myqueue -1 -1

此命令将返回列表尾部的元素,该元素是下一个要出队的元素。

高级 Redis 队列概念

虽然入队、出队和窥视的基本操作构成了 Redis 队列的基础,但有一些高级概念可以用来构建更复杂、更强大的排队系统。

可靠的队列

在基本队列中,如果消费者在出队任务后但在处理任务之前崩溃,则该任务将丢失。为了防止这种数据丢失,Redis 提供了一种可靠队列模式。在可靠队列中,任务不会在出队时立即从队列中删除。相反,它被移动到一个临时队列中,在该队列中它被存储,直到消费者确认任务已处理。

还值得注意的是,Redis 流 提供可靠的追加式日志数据结构,可以用作实现队列的更高级替代方案,并具有额外的功能。

以下是您在 Redis 中实现可靠队列的方法

  1. 使用 RPOPLPUSH 命令原子地从主队列中删除任务并将其添加到临时队列中
   RPOPLPUSH myqueue tempqueue
  1. 处理任务。
  2. 成功处理任务后,将其从临时队列中删除
   LREM tempqueue 1 "Task1"

如果消费者在处理任务之前崩溃,则该任务将保留在临时队列中,可以由另一个消费者重新处理。

阻塞队列

在基本队列中,如果消费者尝试在队列为空时出队任务,它会收到一个空响应,并且可能需要反复轮询队列。为了避免这种情况,Redis 提供了一种实现阻塞队列的方法。在阻塞队列中,如果消费者尝试在队列为空时出队任务,Redis 会将其挂起,直到有任务可用。

您可以使用 BRPOPBLPOP 命令从阻塞队列中出队任务

BRPOP myqueue 0

BRPOP 的第二个参数是以秒为单位的超时时间。如果队列为空,Redis 将阻塞客户端这个时间段,直到有任务可用。如果超时时间为 0,则 Redis 将无限期地阻塞客户端。

延迟任务

有时,您可能希望将任务添加到队列中,但延迟其执行,直到以后的时间。虽然 Redis 不直接支持延迟任务,但您可以使用排序集与常规队列相结合来实现它们。

以下是如何将任务安排在延迟后添加到队列中

  1. 将任务添加到排序集中,其分数表示任务应执行的时间
   ZADD delayedqueue 1633024800 "Task1"
  1. 有一个消费者定期检查排序集,并将到期的任务移到主队列中
   ZRANGEBYSCORE delayedqueue 0 <current_time>
   RPOPLPUSH tempqueue myqueue

优先级队列

在基本队列中,所有任务都具有相同的优先级。但是,在某些情况下,您可能希望某些任务在其他任务之前处理。Redis 可以使用列表或排序集来实现优先级队列。

对于列表,您可以使用不同的列表来表示不同的优先级级别,并让消费者在检查低优先级列表之前检查高优先级列表。对于排序集,您可以使用分数来表示任务的优先级。


Redis 和分布式系统

Redis 不仅是管理单个应用程序中数据的强大工具,在分布式系统中也表现出色。它的功能使其成为管理跨多个应用程序或服务的任务和消息的绝佳选择。

分布式系统中的消息传递和排队

在分布式系统中,不同的组件或服务通常需要相互通信以执行任务。这种通信可以通过消息传递来促进,其中表示任务的消息从一个服务发送到另一个服务。

队列是消息传递系统中常用的数据结构。它允许服务“入队”表示要执行的任务的消息。其他服务(称为消费者)“出队”这些消息并执行任务。

Redis 以其快速、内存中的数据结构支持而闻名,是分布式系统中实现队列的绝佳工具。它的功能,例如快速数据结构、低延迟和高吞吐量通信,在实时处理大量任务和消息时提供了显著的优势。

在分布式架构中使用 Redis 的优势

强调在分布式架构中使用 Redis 的优势对于理解为什么它在这些环境中很受欢迎至关重要

快速数据结构:Redis 以其闪电般的内存中数据结构而闻名。此功能使快速访问和操作数据成为可能,使其成为分布式系统中时间敏感的任务和消息传递的理想选择。

低延迟:由于其内存性质和优化的数据结构,Redis 在数据检索和存储操作中表现出低延迟。这种延迟降低确保了分布式组件之间的快速通信和响应能力,从而提高了整体系统性能。

高吞吐量通信:Redis 可以有效地处理大量消息和任务,使其适合需要高吞吐量通信的场景。无论是处理实时事件还是管理关键任务,Redis 都能满足分布式环境的需求。

Redis 中的发布/订阅模式

除了简单的队列之外,Redis 还支持发布/订阅 (pub/sub) 消息传递模式。在这种模式下,消息不是直接从生产者发送到消费者。相反,生产者将消息“发布”到“通道”,而消费者“订阅”通道以接收消息。

pub/sub 模式在需要将消息发送给多个消费者或消息的生产者和消费者彼此不了解的场景中很有用。

例如,假设我们有一个系统为多个用户生成实时通知。与其单独向每个用户发送通知,不如使用 pub/sub 模式将通知广播到代表通知类型的特定通道(例如,“new_message”、“friend_request”)。对特定类型通知感兴趣的订阅者可以订阅相应的通道,然后他们会自动收到发布到该通道的所有通知。

在 Redis 中设置 pub/sub 系统非常简单。生产者使用 PUBLISH 命令将消息发送到特定通道,而消费者使用 SUBSCRIBE 命令开始从一个或多个通道接收消息。

以下是如何在 Redis 中使用 pub/sub 命令的示例

  1. 消费者订阅一个通道
   SUBSCRIBE mychannel
  1. 生产者将消息发布到通道
   PUBLISH mychannel "Hello, world!"
  1. 消费者收到消息
   1) "message"
   2) "mychannel"
   3) "Hello, world!"

使用 Redis 队列与不同的编程语言

Redis 是一种通用的工具,可以与许多不同的编程语言一起使用。大多数流行语言都有可用的 Redis 客户端,其中许多客户端都支持 Redis 队列。在本节中,我们将看看如何使用 Python 和 Node.js 使用 Redis 队列。

Python 和 Redis 队列

Python 有多个用于处理 Redis 的库,但最流行的库之一是 RQ(Redis Queue)。RQ 是一个简单的 Python 库,用于将作业排队并在后台使用工作进程处理它们。它使用 Redis 作为作业的后台存储。

以下是如何使用 RQ 将作业排队的示例,请注意,更多示例可以在 github 上找到

from rq import Queue
from redis import Redis

# Establish a connection to Redis
redis_conn = Redis()

# Create a queue
q = Queue(connection=redis_conn)

# Enqueue a job
result = q.enqueue(count_words_at_url, 'http://nvie.com')

在这个例子中,count_words_at_url 是一个函数,它接收一个 URL,下载该 URL 页面上的内容,并计算字数。该函数被排队为一个作业,该作业将在后台由工作进程处理。需要注意的是,该函数是用户定义的函数,而不是 Python 内置函数。

Node.js 和 Redis 队列

在 Node.js 中,一个流行的用于处理 Redis 队列的库是 Bull。Bull 是一个 Node.js 包,它在 Redis 的支持下处理队列中的作业和消息。它旨在实现鲁棒性和原子性,并提供诸如基于优先级的作业处理、作业调度等功能。

以下是如何使用 Bull 将作业排队的示例

// Require the Bull library
const Queue = require('bull');

// Define Redis connection details
const redisConfig = {
  host: '127.0.0.1', // Redis server address
  port: 6379,        // Redis server port
  // You can add more Redis connection options here if needed
};

// Create a queue with the specified Redis connection
const myQueue = new Queue('myQueue', { redis: redisConfig });

// Enqueue a job
myQueue.add({ foo: 'bar' });

在这个例子中,对象 {foo: 'bar'} 被排队为一个作业。Bull 会将这个作业存储在 Redis 中,然后一个工作进程可以在后台处理它。


参考资料